diff --git a/.env.DApp b/.env.DApp new file mode 100644 index 000000000..444ef413b --- /dev/null +++ b/.env.DApp @@ -0,0 +1,4 @@ +SCHEME = "DApp" +APP_IDENTIFIER = "com.walletconnect.dapp" +MATCH_IDENTIFIERS = "com.walletconnect.dapp" +APPLE_ID = "1606875879" \ No newline at end of file diff --git a/.envrc b/.envrc new file mode 100644 index 000000000..a498dd64e --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +source .env diff --git a/.github/workflows/build_artifacts.yml b/.github/workflows/build_artifacts.yml index 94bff827b..8cfb69080 100644 --- a/.github/workflows/build_artifacts.yml +++ b/.github/workflows/build_artifacts.yml @@ -16,8 +16,7 @@ on: jobs: build: - runs-on: - group: apple-silicon + runs-on: macos-latest-xlarge timeout-minutes: 15 steps: diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 1f26d47f9..0dfbfbbef 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -13,8 +13,7 @@ env: PACKAGE_VERSION: ${{ github.event.pull_request.title }} jobs: set-user-agent: - runs-on: - group: apple-silicon + runs-on: macos-latest-xlarge steps: - uses: actions/checkout@v2 with: @@ -29,4 +28,4 @@ jobs: - name: Lint CocoaPods run: | - pod lib lint --verbose --no-clean --quick --allow-warnings --platforms=ios WalletConnectSwiftV2.podspec \ No newline at end of file + pod lib lint --verbose --no-clean --quick --allow-warnings --platforms=ios reown-swift.podspec diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d021cfad9..090b11b3d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,8 +22,7 @@ jobs: prepare: needs: authorize - runs-on: - group: apple-silicon + runs-on: macos-latest-xlarge steps: - uses: actions/checkout@v3 with: @@ -36,8 +35,7 @@ jobs: test: needs: prepare - runs-on: - group: apple-silicon + runs-on: macos-latest-xlarge timeout-minutes: 15 strategy: fail-fast: false diff --git a/.github/workflows/cocoapods.yml b/.github/workflows/cocoapods.yml index 0d533c0c9..3bf3e9a75 100644 --- a/.github/workflows/cocoapods.yml +++ b/.github/workflows/cocoapods.yml @@ -5,8 +5,7 @@ on: types: [ published ] jobs: set-user-agent: - runs-on: - group: apple-silicon + runs-on: macos-latest-xlarge steps: - uses: actions/checkout@v2 with: diff --git a/.github/workflows/deploy_pages.yml b/.github/workflows/deploy_pages.yml deleted file mode 100644 index 9901d0c0d..000000000 --- a/.github/workflows/deploy_pages.yml +++ /dev/null @@ -1,46 +0,0 @@ -# Simple workflow for deploying static content to GitHub Pages -name: Deploy static content to Pages - -on: - # Runs on pushes targeting the default branch - push: - branches: ["main"] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - # Single deploy job since we're just deploying - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: - group: apple-silicon - steps: - - name: Checkout - uses: actions/checkout@v3 - - name: Generate docs - shell: bash - run: | - ./generate_docs.sh - - name: Upload artifact - uses: actions/upload-pages-artifact@v1 - with: - # Upload just docs directory - path: 'docs' - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index df62cc8a9..85dce2767 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,16 +1,19 @@ name: release on: - schedule: - # Runs "Every Monday 10am CET" - - cron: '0 10 * * 1' - workflow_dispatch: + inputs: + app: + type: choice + description: Which sample app to release + options: + - DApp + - WalletApp + - Showcase jobs: build: - runs-on: - group: apple-silicon + runs-on: macos-latest-xlarge steps: - uses: actions/checkout@v3 @@ -35,5 +38,6 @@ jobs: APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }} APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }} WALLETAPP_SENTRY_DSN: ${{ secrets.WALLETAPP_SENTRY_DSN }} + MATCH_GIT_URL: ${{ secrets.MATCH_GIT_URL }} run: | - make release_wallet APPLE_ID=${{ secrets.APPLE_ID }} TOKEN=$(echo -n $GH_USER:$GH_TOKEN | base64) PROJECT_ID=${{ secrets.RELEASE_PROJECT_ID }} WALLETAPP_SENTRY_DSN=${{ secrets.WALLETAPP_SENTRY_DSN }} MIXPANEL_TOKEN=${{secrets.MIXPANEL_TOKEN}} + make release APPLE_ID=${{ secrets.APPLE_ID }} TOKEN=$(echo -n $GH_USER:$GH_TOKEN | base64) PROJECT_ID=${{ secrets.RELEASE_PROJECT_ID }} WALLETAPP_SENTRY_DSN=${{ secrets.WALLETAPP_SENTRY_DSN }} MIXPANEL_TOKEN=${{secrets.MIXPANEL_TOKEN}} APP=${{ github.event.inputs.app }} diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/CommonsTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/CommonsTests.xcscheme new file mode 100644 index 000000000..141246c9c --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/CommonsTests.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/EventsTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/EventsTests.xcscheme new file mode 100644 index 000000000..7f7753025 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/EventsTests.xcscheme @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/RelayerTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/RelayerTests.xcscheme new file mode 100644 index 000000000..f4fc9ed05 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/RelayerTests.xcscheme @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectHistory.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectHistory.xcscheme deleted file mode 100644 index 4311c49f7..000000000 --- a/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectHistory.xcscheme +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectKMSTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectKMSTests.xcscheme new file mode 100644 index 000000000..524c3cb72 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectKMSTests.xcscheme @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectSignTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectSignTests.xcscheme new file mode 100644 index 000000000..96b9d8baa --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectSignTests.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectUtilsTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectUtilsTests.xcscheme new file mode 100644 index 000000000..c78f495d4 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnectUtilsTests.xcscheme @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Web3Modal.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Web3Modal.xcscheme new file mode 100644 index 000000000..ab76cc547 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/Web3Modal.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/AppKitLab/AlertPresenter.swift b/Example/AppKitLab/AlertPresenter.swift new file mode 100644 index 000000000..5da5d4668 --- /dev/null +++ b/Example/AppKitLab/AlertPresenter.swift @@ -0,0 +1,35 @@ +import Foundation +import SwiftMessages +import UIKit + +struct AlertPresenter { + enum MessageType { + case warning + case error + case info + case success + } + + static func present(message: String, type: AlertPresenter.MessageType) { + DispatchQueue.main.async { + let view = MessageView.viewFromNib(layout: .cardView) + switch type { + case .warning: + view.configureTheme(.warning, iconStyle: .subtle) + case .error: + view.configureTheme(.error, iconStyle: .subtle) + case .info: + view.configureTheme(.info, iconStyle: .subtle) + case .success: + view.configureTheme(.success, iconStyle: .subtle) + } + view.button?.isHidden = true + view.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) + view.configureContent(title: "", body: message) + var config = SwiftMessages.Config() + config.presentationStyle = .top + config.duration = .seconds(seconds: 1.5) + SwiftMessages.show(config: config, view: view) + } + } +} diff --git a/Example/AppKitLab/AppKitLab.entitlements b/Example/AppKitLab/AppKitLab.entitlements new file mode 100644 index 000000000..928dcc298 --- /dev/null +++ b/Example/AppKitLab/AppKitLab.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.developer.associated-domains + + applinks:lab.web3modal.com + + com.apple.security.application-groups + + group.com.walletconnect.web3modal + + + diff --git a/Example/AppKitLab/AppKitLabApp.swift b/Example/AppKitLab/AppKitLabApp.swift new file mode 100644 index 000000000..8076f912c --- /dev/null +++ b/Example/AppKitLab/AppKitLabApp.swift @@ -0,0 +1,171 @@ +import Combine +//import Sentry +import SwiftUI +import UIKit +import WalletConnectSign +import ReownAppKit + +#if DEBUG +import Atlantis +#endif + + +class SocketConnectionManager: ObservableObject { + @Published var socketConnected: Bool = false +} + +@main +class AppKitLabApp: App { + private var disposeBag = Set() + private var socketConnectionManager = SocketConnectionManager() + + + @State var alertMessage: String = "" + + required init() { + #if DEBUG + Atlantis.start() + #endif + + let projectId = InputConfig.projectId + + // We're tracking Crash Reports / Issues from the Demo App to keep improving the SDK +// SentrySDK.start { options in +// options.dsn = "https://8b29c857724b94a32ac07ced45452702@o1095249.ingest.sentry.io/4506394479099904" +// options.debug = false +// options.enableTracing = true +// } +// +// SentrySDK.configureScope { scope in +// scope.setContext(value: ["projectId": projectId], key: "Project") +// } + + let metadata = AppMetadata( + name: "Web3Modal Swift Dapp", + description: "Web3Modal DApp sample", + url: "www.web3modal.com", + icons: ["https://avatars.githubusercontent.com/u/37784886"], + redirect: try! .init(native: "w3mdapp://", universal: "https://lab.web3modal.com/web3modal_example", linkMode: true) + ) + + Networking.configure( + groupIdentifier: "group.com.walletconnect.web3modal", + projectId: projectId, + socketFactory: DefaultSocketFactory() + ) + + AppKit.configure( + projectId: projectId, + metadata: metadata, + crypto: DefaultCryptoProvider(), + authRequestParams: nil, // use .stab() for testing SIWE + customWallets: [ + .init( + id: "swift-sample", + name: "Swift Sample Wallet", + homepage: "https://walletconnect.com/", + imageUrl: "https://avatars.githubusercontent.com/u/37784886?s=200&v=4", + order: 1, + mobileLink: "walletapp://", + linkMode: "https://lab.web3modal.com/wallet" + ) + ] + ) { error in +// SentrySDK.capture(error: error) + + print(error) + } + + setup() + + } + + func setup() { + AppKit.instance.socketConnectionStatusPublisher.receive(on: DispatchQueue.main).sink { [unowned self] status in + print("Socket connection status: \(status)") + self.socketConnectionManager.socketConnected = (status == .connected) + + }.store(in: &disposeBag) + AppKit.instance.logger.setLogging(level: .debug) + Sign.instance.setLogging(level: .debug) + Networking.instance.setLogging(level: .debug) + Relay.instance.setLogging(level: .debug) + + AppKit.instance.authResponsePublisher.sink { (id: RPCID, result: Result<(Session?, [Cacao]), AuthError>) in + switch result { + case .success((_, _)): + AlertPresenter.present(message: "User authenticated", type: .success) + case .failure(let error): + AlertPresenter.present(message: "User authentication error: \(error)", type: .error) + + } + }.store(in: &disposeBag) + + AppKit.instance.SIWEAuthenticationPublisher.sink { result in + switch result { + case .success((let message, let signature)): + AlertPresenter.present(message: "User authenticated", type: .success) + case .failure(let error): + AlertPresenter.present(message: "User authentication error: \(error)", type: .error) + } + }.store(in: &disposeBag) + } + + var body: some Scene { + WindowGroup { [unowned self] in + ContentView() + .environmentObject(socketConnectionManager) + .onOpenURL { url in + AppKit.instance.handleDeeplink(url) + } + .alert( + "Response", + isPresented: .init( + get: { !self.alertMessage.isEmpty }, + set: { _ in self.alertMessage = "" } + ) + ) { + Button("Dismiss", role: .cancel) {} + } message: { + Text(alertMessage) + } + .onReceive(AppKit.instance.sessionResponsePublisher, perform: { response in + switch response.result { + case let .response(value): + self.alertMessage = "Session response: \(value.stringRepresentation)" + case let .error(error): + self.alertMessage = "Session error: \(error)" + } + }) + } + } +} + +extension AuthRequestParams { + static func stub( + domain: String = "lab.web3modal.com", + chains: [String] = ["eip155:1", "eip155:137"], + nonce: String = "32891756", + uri: String = "https://lab.web3modal.com", + nbf: String? = nil, + exp: String? = nil, + statement: String? = "I accept the ServiceOrg Terms of Service: https://lab.web3modal.com", + requestId: String? = nil, + resources: [String]? = nil, + methods: [String]? = ["personal_sign", "eth_sendTransaction"] + ) -> AuthRequestParams { + return try! AuthRequestParams( + domain: domain, + chains: chains, + nonce: nonce, + uri: uri, + nbf: nbf, + exp: exp, + statement: statement, + requestId: requestId, + resources: resources, + methods: methods + ) + } +} + diff --git a/Example/AppKitLab/Assets.xcassets/AccentColor.colorset/Contents.json b/Example/AppKitLab/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 000000000..eb8789700 --- /dev/null +++ b/Example/AppKitLab/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Contents.json rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png b/Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png rename to Example/AppKitLab/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png diff --git a/Example/Showcase/Other/Assets.xcassets/Contents.json b/Example/AppKitLab/Assets.xcassets/Contents.json similarity index 100% rename from Example/Showcase/Other/Assets.xcassets/Contents.json rename to Example/AppKitLab/Assets.xcassets/Contents.json diff --git a/Example/AppKitLab/ComponentLibraryView.swift b/Example/AppKitLab/ComponentLibraryView.swift new file mode 100644 index 000000000..1a04ce8cd --- /dev/null +++ b/Example/AppKitLab/ComponentLibraryView.swift @@ -0,0 +1,53 @@ +import SwiftUI +import ReownAppKit + + +struct ComponentLibraryView: View { + var body: some View { + listView + .navigationTitle("Components") + } + + var listView: some View { + Group { +#if DEBUG + List { + NavigationLink(destination: AccountButtonPreviewView()) { + Text("AccountButton") + } + NavigationLink(destination: NetworkButtonPreviewView()) { + Text("NetworkButton") + } + NavigationLink(destination: W3MButtonStylePreviewView()) { + Text("W3MButton") + } + NavigationLink(destination: W3MCardSelectStylePreviewView()) { + Text("W3MCardSelect") + } + NavigationLink(destination: W3MTagPreviewView()) { + Text("W3MTag") + } + NavigationLink(destination: W3MListSelectStylePreviewView()) { + Text("W3MListSelect") + } + NavigationLink(destination: W3MActionEntryStylePreviewView()) { + Text("W3MActionEntry") + } + NavigationLink(destination: QRCodeViewPreviewView()) { + Text("QRCode") + } + NavigationLink(destination: W3MChipButtonStylePreviewView()) { + Text("W3MChipButtonStyle") + } + NavigationLink(destination: W3MListItemButtonStylePreviewView()) { + Text("W3MListItemButtonStyle") + } + NavigationLink(destination: ToastViewPreviewView()) { + Text("ToastView") + } + } + .listStyle(.plain) +#endif + } + } +} diff --git a/Example/AppKitLab/ContentView.swift b/Example/AppKitLab/ContentView.swift new file mode 100644 index 000000000..b6f44fd9c --- /dev/null +++ b/Example/AppKitLab/ContentView.swift @@ -0,0 +1,60 @@ +import SwiftUI +import ReownAppKit + +struct ContentView: View { + @State var showUIComponents: Bool = false + @EnvironmentObject var socketConnectionManager: SocketConnectionManager + + + var body: some View { + NavigationView { + VStack { + Spacer() + + AppKitButton() + + Web3ModalNetworkButton() + + Spacer() + + Button("Personal sign") { + Task { + do { + try await requestPersonalSign() + AppKit.instance.launchCurrentWallet() + } catch { + print("Error occurred: \(error)") + } + } + } + .buttonStyle(W3MButtonStyle()) + + NavigationLink(destination: ComponentLibraryView(), isActive: $showUIComponents) { + Button("UI components") { + showUIComponents = true + } + .buttonStyle(W3MButtonStyle()) + } + } + .overlay( + HStack { + Circle() + .fill(socketConnectionManager.socketConnected ? Color.Success100 : Color.Error100) + .frame(width: 10, height: 10) + + Text("Socket \(socketConnectionManager.socketConnected ? "Connected" : "Disconnected")") + .font(.system(size: 12, weight: .semibold)) + .foregroundColor(socketConnectionManager.socketConnected ? Color.Success100 : Color.Error100) + }, + alignment: .top + ) + } + } + + func requestPersonalSign() async throws { + + guard let address = AppKit.instance.getAddress() else { return } + try await AppKit.instance.request(.personal_sign(address: address, message: "Hello there!")) + + } +} diff --git a/Example/AppKitLab/DefaultCryptoProvider.swift b/Example/AppKitLab/DefaultCryptoProvider.swift new file mode 100644 index 000000000..b333f40b3 --- /dev/null +++ b/Example/AppKitLab/DefaultCryptoProvider.swift @@ -0,0 +1,24 @@ +import Foundation +import Web3 +import CryptoSwift +import WalletConnectSigner + +struct DefaultCryptoProvider: CryptoProvider { + + public func recoverPubKey(signature: EthereumSignature, message: Data) throws -> Data { + let publicKey = try EthereumPublicKey( + message: message.bytes, + v: EthereumQuantity(quantity: BigUInt(signature.v)), + r: EthereumQuantity(signature.r), + s: EthereumQuantity(signature.s) + ) + return Data(publicKey.rawPublicKey) + } + + public func keccak256(_ data: Data) -> Data { + let digest = SHA3(variant: .keccak256) + let hash = digest.calculate(for: [UInt8](data)) + return Data(hash) + } + +} diff --git a/Example/AppKitLab/Example.entitlements b/Example/AppKitLab/Example.entitlements new file mode 100644 index 000000000..7aa6c890b --- /dev/null +++ b/Example/AppKitLab/Example.entitlements @@ -0,0 +1,18 @@ + + + + + com.apple.developer.associated-domains + + applinks:lab.web3modal.com + + com.apple.security.app-sandbox + + com.apple.security.application-groups + + group.com.walletconnect.web3modal + + com.apple.security.files.user-selected.read-only + + + diff --git a/Example/AppKitLab/Info.plist b/Example/AppKitLab/Info.plist new file mode 100644 index 000000000..029d17566 --- /dev/null +++ b/Example/AppKitLab/Info.plist @@ -0,0 +1,8 @@ + + + + + PROJECT_ID + $(PROJECT_ID) + + diff --git a/Example/DApp/Common/InputConfig.swift b/Example/AppKitLab/InputConfig.swift similarity index 100% rename from Example/DApp/Common/InputConfig.swift rename to Example/AppKitLab/InputConfig.swift diff --git a/Sources/WalletConnectModal/Resources/Assets.xcassets/Contents.json b/Example/AppKitLab/Preview Content/Preview Assets.xcassets/Contents.json similarity index 100% rename from Sources/WalletConnectModal/Resources/Assets.xcassets/Contents.json rename to Example/AppKitLab/Preview Content/Preview Assets.xcassets/Contents.json diff --git a/Example/AppKitLab/WCSocketFactory.swift b/Example/AppKitLab/WCSocketFactory.swift new file mode 100644 index 000000000..fc929b24e --- /dev/null +++ b/Example/AppKitLab/WCSocketFactory.swift @@ -0,0 +1,14 @@ +import Foundation +import WalletConnectRelay +import Starscream + +extension WebSocket: WebSocketConnecting { } + +struct DefaultSocketFactory: WebSocketFactory { + func create(with url: URL) -> WebSocketConnecting { + let socket = WebSocket(url: url) + let queue = DispatchQueue(label: "com.walletconnect.sdk.sockets", attributes: .concurrent) + socket.callbackQueue = queue + return socket + } +} diff --git a/Example/DApp/AppDelegate.swift b/Example/DApp/AppDelegate.swift index 1bccf58bf..acc22e14a 100644 --- a/Example/DApp/AppDelegate.swift +++ b/Example/DApp/AppDelegate.swift @@ -1,4 +1,5 @@ import UIKit +import WalletConnectSign @main class AppDelegate: UIResponder, UIApplicationDelegate { @@ -7,6 +8,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return true } + func applicationWillEnterForeground(_ application: UIApplication) { + ProfilingService.instance.send(logMessage: .init(message: "AppDelegate: application will enter foreground")) + // Additional code to handle entering the foreground + } + + func applicationDidBecomeActive(_ application: UIApplication) { + ProfilingService.instance.send(logMessage: .init(message: "AppDelegate: application did become active")) + // Additional code to handle becoming active + } + // MARK: UISceneSession Lifecycle func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { @@ -15,10 +26,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } + func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) async -> Bool { + ProfilingService.instance.send(logMessage: .init(message: "AppDelegate: will try to dispatch envelope: \(String(describing: userActivity.webpageURL))")) + guard let url = userActivity.webpageURL, + let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else { + return true + } + try! Sign.instance.dispatchEnvelope(url.absoluteString) + + return true + } + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } + func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { + // Log the event of opening the app via URL + ProfilingService.instance.send(logMessage: .init(message: "AppDelegate: app opened by URL: \(url.absoluteString)")) + + // Handle the URL appropriately + try! Sign.instance.dispatchEnvelope(url.absoluteString) + + return true + } } diff --git a/Example/DApp/ApplicationLayer/Application.swift b/Example/DApp/ApplicationLayer/Application.swift index feba5e373..e4c9d7c63 100644 --- a/Example/DApp/ApplicationLayer/Application.swift +++ b/Example/DApp/ApplicationLayer/Application.swift @@ -4,5 +4,4 @@ import WalletConnectUtils final class Application { var uri: WalletConnectURI? - var requestSent = false } diff --git a/Example/DApp/Assets.xcassets/solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ.imageset/Contents.json b/Example/DApp/Assets.xcassets/solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp.imageset/Contents.json similarity index 100% rename from Example/DApp/Assets.xcassets/solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ.imageset/Contents.json rename to Example/DApp/Assets.xcassets/solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp.imageset/Contents.json diff --git a/Example/DApp/Assets.xcassets/solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ.imageset/solana (1).png b/Example/DApp/Assets.xcassets/solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp.imageset/solana (1).png similarity index 100% rename from Example/DApp/Assets.xcassets/solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ.imageset/solana (1).png rename to Example/DApp/Assets.xcassets/solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp.imageset/solana (1).png diff --git a/Example/DApp/Common/ActivityIndicatorManager.swift b/Example/DApp/Common/ActivityIndicatorManager.swift new file mode 100644 index 000000000..2405ea052 --- /dev/null +++ b/Example/DApp/Common/ActivityIndicatorManager.swift @@ -0,0 +1,42 @@ +import UIKit + +class ActivityIndicatorManager { + static let shared = ActivityIndicatorManager() + private var activityIndicator: UIActivityIndicatorView? + private let serialQueue = DispatchQueue(label: "com.yourapp.activityIndicatorManager") + + private init() {} + + func start() { + serialQueue.async { + self.stopInternal() + + DispatchQueue.main.async { + guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let window = windowScene.windows.first(where: { $0.isKeyWindow }) else { return } + + let activityIndicator = UIActivityIndicatorView(style: .large) + activityIndicator.center = window.center + activityIndicator.color = .white + activityIndicator.startAnimating() + window.addSubview(activityIndicator) + + self.activityIndicator = activityIndicator + } + } + } + + func stop() { + serialQueue.async { + self.stopInternal() + } + } + + private func stopInternal() { + DispatchQueue.main.sync { + self.activityIndicator?.stopAnimating() + self.activityIndicator?.removeFromSuperview() + self.activityIndicator = nil + } + } +} diff --git a/Example/DApp/Constants.swift b/Example/DApp/Constants.swift new file mode 100644 index 000000000..36eb6a4d3 --- /dev/null +++ b/Example/DApp/Constants.swift @@ -0,0 +1,6 @@ + +import Foundation + +enum Constants { + static let groupIdentifier = "group.com.walletconnect.dapp" +} diff --git a/Example/DApp/DApp.entitlements b/Example/DApp/DApp.entitlements new file mode 100644 index 000000000..787b67d9b --- /dev/null +++ b/Example/DApp/DApp.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.developer.associated-domains + + applinks:lab.web3modal.com + + com.apple.security.application-groups + + group.com.walletconnect.dapp + + + diff --git a/Example/DApp/DAppRelease.entitlements b/Example/DApp/DAppRelease.entitlements new file mode 100644 index 000000000..787b67d9b --- /dev/null +++ b/Example/DApp/DAppRelease.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.developer.associated-domains + + applinks:lab.web3modal.com + + com.apple.security.application-groups + + group.com.walletconnect.dapp + + + diff --git a/Example/DApp/Info.plist b/Example/DApp/Info.plist index 20e5043da..1f05fe57e 100644 --- a/Example/DApp/Info.plist +++ b/Example/DApp/Info.plist @@ -2,6 +2,8 @@ + MIXPANEL_TOKEN + $(MIXPANEL_TOKEN) CFBundleURLTypes diff --git a/Example/DApp/Modules/Auth/AuthInteractor.swift b/Example/DApp/Modules/Auth/AuthInteractor.swift deleted file mode 100644 index ffddc61dd..000000000 --- a/Example/DApp/Modules/Auth/AuthInteractor.swift +++ /dev/null @@ -1,3 +0,0 @@ -import Foundation - -final class AuthInteractor {} diff --git a/Example/DApp/Modules/Auth/AuthModule.swift b/Example/DApp/Modules/Auth/AuthModule.swift deleted file mode 100644 index 9252f89e3..000000000 --- a/Example/DApp/Modules/Auth/AuthModule.swift +++ /dev/null @@ -1,16 +0,0 @@ -import SwiftUI - -final class AuthModule { - @discardableResult - static func create(app: Application) -> UIViewController { - let router = AuthRouter(app: app) - let interactor = AuthInteractor() - let presenter = AuthPresenter(interactor: interactor, router: router) - let view = AuthView().environmentObject(presenter) - let viewController = SceneViewController(viewModel: presenter, content: view) - - router.viewController = viewController - - return viewController - } -} diff --git a/Example/DApp/Modules/Auth/AuthPresenter.swift b/Example/DApp/Modules/Auth/AuthPresenter.swift deleted file mode 100644 index 8e01e32e6..000000000 --- a/Example/DApp/Modules/Auth/AuthPresenter.swift +++ /dev/null @@ -1,116 +0,0 @@ -import UIKit -import Combine - -import Auth - -final class AuthPresenter: ObservableObject { - enum SigningState { - case none - case signed(Cacao) - case error(Error) - } - - private let interactor: AuthInteractor - private let router: AuthRouter - - @Published var qrCodeImageData: Data? - @Published var signingState = SigningState.none - @Published var showSigningState = false - - private var walletConnectUri: WalletConnectURI? - - private var subscriptions = Set() - - init( - interactor: AuthInteractor, - router: AuthRouter - ) { - defer { - Task { - await setupInitialState() - } - } - self.interactor = interactor - self.router = router - } - - func onAppear() { - generateQR() - } - - func copyUri() { - UIPasteboard.general.string = walletConnectUri?.absoluteString - } - - func connectWallet() { - if let walletConnectUri { - let walletUri = URL(string: "walletapp://wc?uri=\(walletConnectUri.deeplinkUri.removingPercentEncoding!)")! - DispatchQueue.main.async { - UIApplication.shared.open(walletUri) - } - } - } -} - -// MARK: - Private functions -extension AuthPresenter { - @MainActor - private func setupInitialState() { - Auth.instance.authResponsePublisher.sink { [weak self] (_, result) in - switch result { - case .success(let cacao): - self?.signingState = .signed(cacao) - self?.generateQR() - self?.showSigningState.toggle() - - case .failure(let error): - self?.signingState = .error(error) - self?.showSigningState.toggle() - } - } - .store(in: &subscriptions) - } - - private func generateQR() { - Task { @MainActor in - let uri = try! await Pair.instance.create() - walletConnectUri = uri - try await Auth.instance.request(.stub(), topic: uri.topic) - let qrCodeImage = QRCodeGenerator.generateQRCode(from: uri.absoluteString) - DispatchQueue.main.async { - self.qrCodeImageData = qrCodeImage.pngData() - } - } - } -} - -// MARK: - SceneViewModel -extension AuthPresenter: SceneViewModel {} - -// MARK: - Auth request stub -private extension RequestParams { - static func stub( - domain: String = "service.invalid", - chainId: String = "eip155:1", - nonce: String = "32891756", - aud: String = "https://service.invalid/login", - nbf: String? = nil, - exp: String? = nil, - statement: String? = "I accept the ServiceOrg Terms of Service: https://service.invalid/tos", - requestId: String? = nil, - resources: [String]? = ["ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/", "https://example.com/my-web2-claim.json"] - ) -> RequestParams { - return RequestParams( - domain: domain, - chainId: chainId, - nonce: nonce, - aud: aud, - nbf: nbf, - exp: exp, - statement: statement, - requestId: requestId, - resources: resources - ) - } -} - diff --git a/Example/DApp/Modules/Auth/AuthRouter.swift b/Example/DApp/Modules/Auth/AuthRouter.swift deleted file mode 100644 index 3caacfd38..000000000 --- a/Example/DApp/Modules/Auth/AuthRouter.swift +++ /dev/null @@ -1,16 +0,0 @@ -import UIKit - -final class AuthRouter { - weak var viewController: UIViewController! - - private let app: Application - - init(app: Application) { - self.app = app - } - - func dismiss() { - viewController.dismiss(animated: true) - UIApplication.shared.open(URL(string: "showcase://")!) - } -} diff --git a/Example/DApp/Modules/Auth/AuthView.swift b/Example/DApp/Modules/Auth/AuthView.swift deleted file mode 100644 index 8e15bacc0..000000000 --- a/Example/DApp/Modules/Auth/AuthView.swift +++ /dev/null @@ -1,140 +0,0 @@ -import SwiftUI - -struct AuthView: View { - @EnvironmentObject var presenter: AuthPresenter - - var body: some View { - NavigationStack { - ZStack { - Color(red: 25/255, green: 26/255, blue: 26/255) - .ignoresSafeArea() - - VStack { - ZStack { - RoundedRectangle(cornerRadius: 25) - .fill(.white) - .aspectRatio(1, contentMode: .fit) - .padding(20) - - if let data = presenter.qrCodeImageData { - let qrCodeImage = UIImage(data: data) ?? UIImage() - Image(uiImage: qrCodeImage) - .resizable() - .aspectRatio(1, contentMode: .fit) - .padding(40) - } - } - - Button { - presenter.connectWallet() - } label: { - Text("Connect Sample Wallet") - .font(.system(size: 16, weight: .semibold)) - .foregroundColor(.white) - .padding(.horizontal, 16) - .padding(.vertical, 10) - .background(Color(red: 95/255, green: 159/255, blue: 248/255)) - .cornerRadius(16) - } - - Button { - presenter.copyUri() - } label: { - HStack { - Image("copy") - Text("Copy link") - .font(.system(size: 14, weight: .semibold)) - .foregroundColor(Color(red: 0.58, green: 0.62, blue: 0.62)) - } - } - .padding(.top, 16) - - Spacer() - } - } - .navigationTitle("Auth") - .navigationBarTitleDisplayMode(.inline) - .toolbarColorScheme(.dark, for: .navigationBar) - .toolbarBackground(.visible, for: .navigationBar) - .toolbarBackground( - Color(red: 25/255, green: 26/255, blue: 26/255), - for: .navigationBar - ) - .onAppear { - presenter.onAppear() - } - .sheet(isPresented: $presenter.showSigningState) { - ZStack { - Color(red: 25/255, green: 26/255, blue: 26/255) - .ignoresSafeArea() - - VStack { - HStack { - RoundedRectangle(cornerRadius: 2) - .fill(.gray.opacity(0.5)) - .frame(width: 30, height: 4) - - } - .padding(20) - - Image("profile") - .resizable() - .frame(width: 64, height: 64) - - switch presenter.signingState { - case .error(let error): - Text(error.localizedDescription) - .font(.system(size: 16, weight: .semibold)) - .foregroundColor(.white) - .padding(.horizontal, 16) - .padding(.vertical, 10) - .background(.green) - .cornerRadius(16) - .padding(.top, 16) - - case .signed(let cacao): - HStack { - Text(cacao.p.iss.split(separator: ":").last ?? "") - .lineLimit(1) - .truncationMode(.middle) - .frame(width: 135) - .font(.system(size: 24, weight: .semibold)) - .foregroundColor(Color(red: 0.89, green: 0.91, blue: 0.91)) - - Button { - UIPasteboard.general.string = String(cacao.p.iss.split(separator: ":").last ?? "") - } label: { - Image("copy") - .resizable() - .frame(width: 14, height: 14) - } - } - - Text("Authenticated") - .font(.system(size: 16, weight: .semibold)) - .foregroundColor(.white) - .padding(.horizontal, 16) - .padding(.vertical, 10) - .background(.green) - .cornerRadius(16) - .padding(.top, 16) - - case .none: - EmptyView() - } - - Spacer() - } - } - .presentationDetents([.medium]) - } - } - } -} - -struct AuthView_Previews: PreviewProvider { - static var previews: some View { - AuthView() - } -} - diff --git a/Example/DApp/Modules/Configuration/ConfigModule.swift b/Example/DApp/Modules/Configuration/ConfigModule.swift new file mode 100644 index 000000000..df4037810 --- /dev/null +++ b/Example/DApp/Modules/Configuration/ConfigModule.swift @@ -0,0 +1,15 @@ +import SwiftUI + +final class ConfigModule { + @discardableResult + static func create(app: Application) -> UIViewController { + let router = ConfigRouter(app: app) + let presenter = ConfigPresenter(router: router) + let view = ConfigView().environmentObject(presenter) + + let viewController = SceneViewController(viewModel: presenter, content: view) + router.viewController = viewController + + return viewController + } +} diff --git a/Example/DApp/Modules/Configuration/ConfigPresenter.swift b/Example/DApp/Modules/Configuration/ConfigPresenter.swift new file mode 100644 index 000000000..0872c7c25 --- /dev/null +++ b/Example/DApp/Modules/Configuration/ConfigPresenter.swift @@ -0,0 +1,41 @@ +import UIKit +import Combine + +import WalletConnectSign + +final class ConfigPresenter: ObservableObject, SceneViewModel { + + + private let router: ConfigRouter + + var clientId: String { + guard let clientId = try? Networking.interactor.getClientId() else { return .empty } + return clientId + } + + init( + router: ConfigRouter + ) { + defer { setupInitialState() } + self.router = router + } + + func onAppear() { + + } + + private func setupInitialState() { + + } + + func cleanLinkModeSupportedWalletsCache() { + let userDefaults = UserDefaults(suiteName: Constants.groupIdentifier)! + let prefix = "com.walletconnect.sdk.linkModeLinks" + let keys = userDefaults.dictionaryRepresentation().keys + + for key in keys where key.hasPrefix(prefix) { + userDefaults.removeObject(forKey: key) + } + } + +} diff --git a/Example/DApp/Modules/Configuration/ConfigRouter.swift b/Example/DApp/Modules/Configuration/ConfigRouter.swift new file mode 100644 index 000000000..c3e5283f1 --- /dev/null +++ b/Example/DApp/Modules/Configuration/ConfigRouter.swift @@ -0,0 +1,14 @@ + +import Foundation +import UIKit +import WalletConnectSign + +final class ConfigRouter { + weak var viewController: UIViewController! + + private let app: Application + + init(app: Application) { + self.app = app + } +} diff --git a/Example/DApp/Modules/Configuration/ConfigView.swift b/Example/DApp/Modules/Configuration/ConfigView.swift new file mode 100644 index 000000000..35d061ddf --- /dev/null +++ b/Example/DApp/Modules/Configuration/ConfigView.swift @@ -0,0 +1,110 @@ +import SwiftUI + +struct ConfigView: View { + @EnvironmentObject var presenter: ConfigPresenter + @State private var copyAlert: Bool = false + @State private var cacheCleanAlert: Bool = false + + var body: some View { + NavigationStack { + ZStack { + Color(red: 25/255, green: 26/255, blue: 26/255) + .ignoresSafeArea() + + ScrollView { + VStack(spacing: 12) { + // Clean Cache Button + Button(action: { + presenter.cleanLinkModeSupportedWalletsCache() + cacheCleanAlert = true + }) { + VStack(alignment: .leading, spacing: 4) { + HStack(spacing: 6) { + Text("Clean Cache") + .multilineTextAlignment(.leading) + .foregroundColor(.white) + .font(.system(size: 16, weight: .semibold)) + + Image(systemName: "trash") + .foregroundColor(.white) + + Spacer() + } + .padding(.horizontal, 12) + .padding(.top, 16) + + Text("Clean link mode supported wallets cache") + .multilineTextAlignment(.leading) + .foregroundColor(.white.opacity(0.7)) + .font(.system(size: 14)) + .padding(.horizontal, 12) + .padding(.bottom, 16) + } + .background(Color(red: 95/255, green: 159/255, blue: 248/255).opacity(0.2).cornerRadius(12)) + } + .frame(maxWidth: .infinity) + .padding(.horizontal, 12) + .padding(.top, 10) + + // Client ID Row + Button(action: { + UIPasteboard.general.string = presenter.clientId + copyAlert = true + }) { + VStack(alignment: .leading, spacing: 4) { + HStack(spacing: 6) { + Text("Client ID") + .multilineTextAlignment(.leading) + .foregroundColor(.white) + .font(.system(size: 16, weight: .semibold)) + + Image(systemName: "doc.on.doc") + .foregroundColor(.white) + + Spacer() + } + .padding(.horizontal, 12) + .padding(.top, 16) + + Text(presenter.clientId) + .multilineTextAlignment(.leading) + .foregroundColor(.white.opacity(0.7)) + .font(.system(size: 14)) + .padding(.horizontal, 12) + .padding(.bottom, 16) + } + .background(Color(red: 95/255, green: 159/255, blue: 248/255).opacity(0.2).cornerRadius(12)) + } + .frame(maxWidth: .infinity) + .padding(.horizontal, 12) + } + .padding(12) + } + .padding(.bottom, 76) + .onAppear { + presenter.onAppear() + } + } + .navigationTitle("Configuration") + .navigationBarTitleDisplayMode(.inline) + .toolbarColorScheme(.dark, for: .navigationBar) + .toolbarBackground(.visible, for: .navigationBar) + .toolbarBackground( + Color(red: 25/255, green: 26/255, blue: 26/255), + for: .navigationBar + ) + } + .alert("Cache cleaned successfully", isPresented: $cacheCleanAlert) { + Button("OK", role: .cancel) { } + } + .alert("Client ID copied to clipboard", isPresented: $copyAlert) { + Button("OK", role: .cancel) { } + } + } +} + +struct ConfigView_Previews: PreviewProvider { + static var previews: some View { + ConfigView() + } +} diff --git a/Example/DApp/Modules/Main/MainInteractor.swift b/Example/DApp/Modules/Main/MainInteractor.swift deleted file mode 100644 index a3954796d..000000000 --- a/Example/DApp/Modules/Main/MainInteractor.swift +++ /dev/null @@ -1,3 +0,0 @@ -import Foundation - -final class MainInteractor {} diff --git a/Example/DApp/Modules/Main/MainModule.swift b/Example/DApp/Modules/Main/MainModule.swift deleted file mode 100644 index 67a9d6060..000000000 --- a/Example/DApp/Modules/Main/MainModule.swift +++ /dev/null @@ -1,15 +0,0 @@ -import SwiftUI - -final class MainModule { - @discardableResult - static func create(app: Application) -> UIViewController { - let router = MainRouter(app: app) - let interactor = MainInteractor() - let presenter = MainPresenter(router: router, interactor: interactor) - let viewController = MainViewController(presenter: presenter) - - router.viewController = viewController - - return viewController - } -} diff --git a/Example/DApp/Modules/Main/MainPresenter.swift b/Example/DApp/Modules/Main/MainPresenter.swift deleted file mode 100644 index c3c7d47ee..000000000 --- a/Example/DApp/Modules/Main/MainPresenter.swift +++ /dev/null @@ -1,32 +0,0 @@ -import UIKit -import Combine - -final class MainPresenter { - private let interactor: MainInteractor - private let router: MainRouter - private var disposeBag = Set() - - var tabs: [TabPage] { - return TabPage.allCases - } - - var viewControllers: [UIViewController] { - return [ - router.signViewController(), - router.authViewController() - ] - } - - init(router: MainRouter, interactor: MainInteractor) { - defer { - setupInitialState() - } - self.router = router - self.interactor = interactor - } -} - -// MARK: - Private functions -extension MainPresenter { - private func setupInitialState() {} -} diff --git a/Example/DApp/Modules/Main/MainRouter.swift b/Example/DApp/Modules/Main/MainRouter.swift deleted file mode 100644 index 4b3fef3de..000000000 --- a/Example/DApp/Modules/Main/MainRouter.swift +++ /dev/null @@ -1,19 +0,0 @@ -import UIKit - -final class MainRouter { - weak var viewController: UIViewController! - - private let app: Application - - init(app: Application) { - self.app = app - } - - func signViewController() -> UIViewController { - return SignModule.create(app: app) - } - - func authViewController() -> UIViewController { - return AuthModule.create(app: app) - } -} diff --git a/Example/DApp/Modules/Main/MainViewController.swift b/Example/DApp/Modules/Main/MainViewController.swift deleted file mode 100644 index 539b2a789..000000000 --- a/Example/DApp/Modules/Main/MainViewController.swift +++ /dev/null @@ -1,43 +0,0 @@ -import UIKit -import Sentry - -enum LoginError: Error { - case wrongUser(id: String) - case wrongPassword -} - -final class MainViewController: UITabBarController { - - private let presenter: MainPresenter - - init(presenter: MainPresenter) { - self.presenter = presenter - super.init(nibName: nil, bundle: nil) - } - - override func viewDidLoad() { - super.viewDidLoad() - setupTabs() - } - - private func setupTabs() { - let viewControllers = presenter.viewControllers - - for (index, viewController) in viewControllers.enumerated() { - let model = presenter.tabs[index] - let item = UITabBarItem() - item.title = model.title - item.image = model.icon - item.isEnabled = TabPage.enabledTabs.contains(model) - viewController.tabBarItem = item - viewController.view.backgroundColor = .w_background - } - - self.viewControllers = viewControllers - self.selectedIndex = TabPage.selectedIndex - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} diff --git a/Example/DApp/Modules/Main/Model/TabPage.swift b/Example/DApp/Modules/Main/Model/TabPage.swift deleted file mode 100644 index faec2ba34..000000000 --- a/Example/DApp/Modules/Main/Model/TabPage.swift +++ /dev/null @@ -1,32 +0,0 @@ -import UIKit - -enum TabPage: CaseIterable { - case sign - case auth - - var title: String { - switch self { - case .sign: - return "Sign" - case .auth: - return "Auth" - } - } - - var icon: UIImage { - switch self { - case .sign: - return UIImage(named: "pen")! - case .auth: - return UIImage(named: "auth")! - } - } - - static var selectedIndex: Int { - return 0 - } - - static var enabledTabs: [TabPage] { - return [.sign, .auth] - } -} diff --git a/Example/DApp/Modules/Sign/NewPairing/NewPairingRouter.swift b/Example/DApp/Modules/Sign/NewPairing/NewPairingRouter.swift index 51fc5b2f2..89c0ea8a7 100644 --- a/Example/DApp/Modules/Sign/NewPairing/NewPairingRouter.swift +++ b/Example/DApp/Modules/Sign/NewPairing/NewPairingRouter.swift @@ -11,6 +11,5 @@ final class NewPairingRouter { func dismiss() { viewController.dismiss(animated: true) - UIApplication.shared.open(URL(string: "showcase://")!) } } diff --git a/Example/DApp/Modules/Sign/SessionAccount/SessionAccountPresenter.swift b/Example/DApp/Modules/Sign/SessionAccount/SessionAccountPresenter.swift index 15b0b7e74..e89ea8a8e 100644 --- a/Example/DApp/Modules/Sign/SessionAccount/SessionAccountPresenter.swift +++ b/Example/DApp/Modules/Sign/SessionAccount/SessionAccountPresenter.swift @@ -12,7 +12,10 @@ final class SessionAccountPresenter: ObservableObject { @Published var showError = false @Published var errorMessage = String.empty @Published var showRequestSent = false - + @Published var requesting = false + var lastRequest: Request? + + private let interactor: SessionAccountInteractor private let router: SessionAccountRouter private let session: Session @@ -41,14 +44,21 @@ final class SessionAccountPresenter: ObservableObject { do { let requestParams = try getRequest(for: method) - let request = Request(topic: session.topic, method: method, params: requestParams, chainId: Blockchain(sessionAccount.chain)!) + let ttl: TimeInterval = 300 + let request = try Request(topic: session.topic, method: method, params: requestParams, chainId: Blockchain(sessionAccount.chain)!, ttl: ttl) Task { do { + ActivityIndicatorManager.shared.start() try await Sign.instance.request(params: request) + lastRequest = request + ActivityIndicatorManager.shared.stop() + requesting = true DispatchQueue.main.async { [weak self] in self?.openWallet() } } catch { + ActivityIndicatorManager.shared.stop() + requesting = false showError.toggle() errorMessage = error.localizedDescription } @@ -70,13 +80,14 @@ extension SessionAccountPresenter { Sign.instance.sessionResponsePublisher .receive(on: DispatchQueue.main) .sink { [unowned self] response in + requesting = false presentResponse(response: response) } .store(in: &subscriptions) } private func getRequest(for method: String) throws -> AnyCodable { - let account = session.namespaces.first!.value.accounts.first!.absoluteString + let account = session.namespaces.first!.value.accounts.first!.address if method == "eth_sendTransaction" { let tx = Stub.tx return AnyCodable(tx) diff --git a/Example/DApp/Modules/Sign/SessionAccount/SessionAccountView.swift b/Example/DApp/Modules/Sign/SessionAccount/SessionAccountView.swift index 1b8a3ebb8..939a9edb6 100644 --- a/Example/DApp/Modules/Sign/SessionAccount/SessionAccountView.swift +++ b/Example/DApp/Modules/Sign/SessionAccount/SessionAccountView.swift @@ -8,9 +8,11 @@ struct SessionAccountView: View { var body: some View { NavigationStack { ZStack { + Color(red: 25/255, green: 26/255, blue: 26/255) .ignoresSafeArea() - + + ScrollView { VStack(spacing: 12) { networkView(title: String(presenter.sessionAccount.chain.split(separator: ":").first ?? "")) @@ -21,6 +23,14 @@ struct SessionAccountView: View { } .padding(12) } + + if presenter.requesting { + loadingView + .frame(width: 200, height: 200) + .background(Color.gray.opacity(0.95)) + .cornerRadius(20) + .shadow(radius: 10) + } } .navigationTitle(presenter.sessionAccount.chain) .navigationBarTitleDisplayMode(.inline) @@ -179,7 +189,18 @@ struct SessionAccountView: View { } } } - + + private var loadingView: some View { + VStack { + ProgressView() + .progressViewStyle(CircularProgressViewStyle(tint: .black)) + .scaleEffect(1.5) + Text("Request sent, waiting for response") + .foregroundColor(.white) + .padding(.top, 20) + } + } + private func responseView(response: Response) -> some View { ZStack { RoundedRectangle(cornerRadius: 16) @@ -209,14 +230,14 @@ struct SessionAccountView: View { .padding(12) Spacer() - - let record = Sign.instance.getSessionRequestRecord(id: response.id)! - Text(record.request.method) - .font( - Font.system(size: 14, weight: .medium) - ) - .foregroundColor(Color(red: 0.58, green: 0.62, blue: 0.62)) - .padding(12) + if let lastRequest = presenter.lastRequest { + Text(lastRequest.method) + .font( + Font.system(size: 14, weight: .medium) + ) + .foregroundColor(Color(red: 0.58, green: 0.62, blue: 0.62)) + .padding(12) + } } ZStack { diff --git a/Example/DApp/Modules/Sign/SignInteractor.swift b/Example/DApp/Modules/Sign/SignInteractor.swift index 8fa7d0e2b..8c35d79c1 100644 --- a/Example/DApp/Modules/Sign/SignInteractor.swift +++ b/Example/DApp/Modules/Sign/SignInteractor.swift @@ -6,8 +6,7 @@ enum Proposal { static let requiredNamespaces: [String: ProposalNamespace] = [ "eip155": ProposalNamespace( chains: [ - Blockchain("eip155:1")!, - Blockchain("eip155:137")! + Blockchain("eip155:1")! ], methods: [ "eth_sendTransaction", @@ -20,12 +19,22 @@ enum Proposal { static let optionalNamespaces: [String: ProposalNamespace] = [ "solana": ProposalNamespace( chains: [ - Blockchain("solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ")! + Blockchain("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp")! ], methods: [ "solana_signMessage", "solana_signTransaction" ], events: [] + ), + "eip155": ProposalNamespace( + chains: [ + Blockchain("eip155:137")! + ], + methods: [ + "eth_sendTransaction", + "personal_sign", + "eth_signTypedData" + ], events: [] ) ] } diff --git a/Example/DApp/Modules/Sign/SignPresenter.swift b/Example/DApp/Modules/Sign/SignPresenter.swift index b42d2663c..c16bbe68c 100644 --- a/Example/DApp/Modules/Sign/SignPresenter.swift +++ b/Example/DApp/Modules/Sign/SignPresenter.swift @@ -1,7 +1,7 @@ import UIKit import Combine -import Web3Modal +import ReownAppKit import WalletConnectSign final class SignPresenter: ObservableObject { @@ -15,7 +15,7 @@ final class SignPresenter: ObservableObject { let chains = [ Chain(name: "Ethereum", id: "eip155:1"), Chain(name: "Polygon", id: "eip155:137"), - Chain(name: "Solana", id: "solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ") + Chain(name: "Solana", id: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp") ] private let interactor: SignInteractor @@ -44,35 +44,94 @@ final class SignPresenter: ObservableObject { func connectWalletWithW3M() { Task { - Web3Modal.set(sessionParams: .init( + AppKit.set(sessionParams: .init( requiredNamespaces: Proposal.requiredNamespaces, optionalNamespaces: Proposal.optionalNamespaces )) } - Web3Modal.present(from: nil) + AppKit.present(from: nil) } - + @MainActor - func connectWalletWithSign() { + func connectWalletWithSessionPropose() { Task { - let uri = try await Pair.instance.create() - walletConnectUri = uri - try await Sign.instance.connect( - requiredNamespaces: Proposal.requiredNamespaces, - optionalNamespaces: Proposal.optionalNamespaces, - topic: uri.topic - ) - router.presentNewPairing(walletConnectUri: uri) + do { + ActivityIndicatorManager.shared.start() + walletConnectUri = try await Sign.instance.connect( + requiredNamespaces: Proposal.requiredNamespaces, + optionalNamespaces: Proposal.optionalNamespaces + ) + ActivityIndicatorManager.shared.stop() + router.presentNewPairing(walletConnectUri: walletConnectUri!) + } catch { + ActivityIndicatorManager.shared.stop() + } } } - + + @MainActor + func connectWalletWithSessionAuthenticate() { + Task { + do { + ActivityIndicatorManager.shared.start() + let uri = try await Sign.instance.authenticate(.stub()) + walletConnectUri = uri + ActivityIndicatorManager.shared.stop() + router.presentNewPairing(walletConnectUri: walletConnectUri!) + } catch { + ActivityIndicatorManager.shared.stop() + } + } + } + + @MainActor + func connectWalletWithSessionAuthenticateSIWEOnly() { + Task { + do { + ActivityIndicatorManager.shared.start() + let uri = try await Sign.instance.authenticate(.stub(methods: ["personal_sign"])) + walletConnectUri = uri + ActivityIndicatorManager.shared.stop() + router.presentNewPairing(walletConnectUri: walletConnectUri!) + } catch { + ActivityIndicatorManager.shared.stop() + } + } + } + + @MainActor + func connectWalletWithSessionAuthenticateLinkMode() { + Task { + do { + ActivityIndicatorManager.shared.start() + if let pairingUri = try await Sign.instance.authenticate(.stub(methods: ["personal_sign"]), walletUniversalLink: "https://lab.web3modal.com/wallet") { + walletConnectUri = pairingUri + ActivityIndicatorManager.shared.stop() + router.presentNewPairing(walletConnectUri: walletConnectUri!) + } + } catch { + AlertPresenter.present(message: error.localizedDescription, type: .error) + ActivityIndicatorManager.shared.stop() + } + } + } + + @MainActor + func openConfiguration() { + router.openConfig() + } + + @MainActor func disconnect() { if let session { Task { @MainActor in do { + ActivityIndicatorManager.shared.start() try await Sign.instance.disconnect(topic: session.topic) + ActivityIndicatorManager.shared.stop() accountsDetails.removeAll() } catch { + ActivityIndicatorManager.shared.stop() showError.toggle() errorMessage = error.localizedDescription } @@ -90,20 +149,62 @@ final class SignPresenter: ObservableObject { // MARK: - Private functions extension SignPresenter { private func setupInitialState() { - Sign.instance.sessionSettlePublisher - .receive(on: DispatchQueue.main) - .sink { [unowned self] _ in - self.router.dismiss() - self.getSession() - } - .store(in: &subscriptions) - getSession() Sign.instance.sessionDeletePublisher .receive(on: DispatchQueue.main) .sink { [unowned self] _ in self.accountsDetails.removeAll() + router.popToRoot() + Task(priority: .high) { ActivityIndicatorManager.shared.stop() } + } + .store(in: &subscriptions) + + Sign.instance.authResponsePublisher + .receive(on: DispatchQueue.main) + .sink { [unowned self] response in + switch response.result { + case .success(let (session, _)): + if session == nil { + AlertPresenter.present(message: "Wallet Succesfully Authenticated", type: .success) + } else { + self.router.dismiss() + self.getSession() + } + break + case .failure(let error): + AlertPresenter.present(message: error.localizedDescription, type: .error) + } + Task(priority: .high) { ActivityIndicatorManager.shared.stop() } + } + .store(in: &subscriptions) + + Sign.instance.sessionResponsePublisher + .receive(on: DispatchQueue.main) + .sink { response in + Task(priority: .high) { ActivityIndicatorManager.shared.stop() } + } + .store(in: &subscriptions) + + Sign.instance.requestExpirationPublisher + .receive(on: DispatchQueue.main) + .sink { _ in + Task(priority: .high) { ActivityIndicatorManager.shared.stop() } + AlertPresenter.present(message: "Session Request has expired", type: .warning) + } + .store(in: &subscriptions) + + AppKit.instance.SIWEAuthenticationPublisher + .receive(on: DispatchQueue.main) + .sink { [unowned self] result in + switch result { + case .success((let message, let signature)): + AlertPresenter.present(message: "Authenticated with SIWE", type: .success) + self.router.dismiss() + self.getSession() + case .failure(let error): + AlertPresenter.present(message: "\(error)", type: .warning) + } } .store(in: &subscriptions) } @@ -128,3 +229,34 @@ extension SignPresenter { // MARK: - SceneViewModel extension SignPresenter: SceneViewModel {} + + +// MARK: - Authenticate request stub +extension AuthRequestParams { + static func stub( + domain: String = "lab.web3modal.com", + chains: [String] = ["eip155:1", "eip155:137"], + nonce: String = "32891756", + uri: String = "https://lab.web3modal.com", + nbf: String? = nil, + exp: String? = nil, + statement: String? = "I accept the ServiceOrg Terms of Service: https://app.web3inbox.com/tos", + requestId: String? = nil, + resources: [String]? = nil, + methods: [String]? = ["personal_sign", "eth_sendTransaction"] + ) -> AuthRequestParams { + return try! AuthRequestParams( + domain: domain, + chains: chains, + nonce: nonce, + uri: uri, + nbf: nbf, + exp: exp, + statement: statement, + requestId: requestId, + resources: resources, + methods: methods + ) + } +} + diff --git a/Example/DApp/Modules/Sign/SignRouter.swift b/Example/DApp/Modules/Sign/SignRouter.swift index 60da1928c..6dea21cc2 100644 --- a/Example/DApp/Modules/Sign/SignRouter.swift +++ b/Example/DApp/Modules/Sign/SignRouter.swift @@ -20,14 +20,22 @@ final class SignRouter { func presentSessionAccount(sessionAccount: AccountDetails, session: Session) { SessionAccountModule.create(app: app, sessionAccount: sessionAccount, session: session) - .present(from: viewController) + .push(from: viewController) } - + func dismissNewPairing() { newPairingViewController?.dismiss() } - + func dismiss() { viewController.dismiss(animated: true) } + + func popToRoot() { + viewController.popToRoot() + } + + func openConfig() { + ConfigModule.create(app: app).push(from: viewController) + } } diff --git a/Example/DApp/Modules/Sign/SignView.swift b/Example/DApp/Modules/Sign/SignView.swift index fc60a1754..e59774df0 100644 --- a/Example/DApp/Modules/Sign/SignView.swift +++ b/Example/DApp/Modules/Sign/SignView.swift @@ -2,45 +2,82 @@ import SwiftUI struct SignView: View { @EnvironmentObject var presenter: SignPresenter - + var body: some View { NavigationStack { ZStack { Color(red: 25/255, green: 26/255, blue: 26/255) .ignoresSafeArea() - + ScrollView { if presenter.accountsDetails.isEmpty { VStack { ForEach(presenter.chains, id: \.name) { chain in networkItem(title: chain.name, icon: chain.name.lowercased(), id: chain.id) } - + Spacer() - - Button { - presenter.connectWalletWithW3M() - } label: { - Text("Connect with Web3Modal") - .font(.system(size: 16, weight: .semibold)) - .foregroundColor(.white) - .padding(.horizontal, 16) - .padding(.vertical, 10) - .background(Color(red: 95/255, green: 159/255, blue: 248/255)) - .cornerRadius(16) - } - .padding(.top, 20) - - Button { - presenter.connectWalletWithSign() - } label: { - Text("Connect with Sign API") - .font(.system(size: 16, weight: .semibold)) - .foregroundColor(.white) - .padding(.horizontal, 16) - .padding(.vertical, 10) - .background(Color(red: 95/255, green: 159/255, blue: 248/255)) - .cornerRadius(16) + + VStack(spacing: 10) { + Button { + presenter.connectWalletWithSessionAuthenticateLinkMode() + } label: { + Text("1-Click Auth with Link Mode") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(.white) + .padding(.horizontal, 16) + .padding(.vertical, 10) + .background(Color(red: 95/255, green: 159/255, blue: 248/255)) + .cornerRadius(16) + } + + Button { + presenter.connectWalletWithW3M() + } label: { + Text("Connect with Web3Modal") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(.white) + .padding(.horizontal, 16) + .padding(.vertical, 10) + .background(Color(red: 95/255, green: 159/255, blue: 248/255)) + .cornerRadius(16) + } + + Button { + presenter.connectWalletWithSessionPropose() + } label: { + Text("Connect Session Propose") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(.white) + .padding(.horizontal, 16) + .padding(.vertical, 10) + .background(Color(red: 95/255, green: 159/255, blue: 248/255)) + .cornerRadius(16) + } + + Button { + presenter.connectWalletWithSessionAuthenticate() + } label: { + Text("Connect Session Authenticate") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(.white) + .padding(.horizontal, 16) + .padding(.vertical, 10) + .background(Color(red: 95/255, green: 159/255, blue: 248/255)) + .cornerRadius(16) + } + + Button { + presenter.connectWalletWithSessionAuthenticateSIWEOnly() + } label: { + Text("Connect Session Authenticate - SIWE only") + .font(.system(size: 16, weight: .semibold)) + .foregroundColor(.white) + .padding(.horizontal, 16) + .padding(.vertical, 10) + .background(Color(red: 95/255, green: 159/255, blue: 248/255)) + .cornerRadius(16) + } } .padding(.top, 10) } @@ -59,46 +96,47 @@ struct SignView: View { .padding(12) } } + .padding(.bottom, presenter.accountsDetails.isEmpty ? 0 : 76) .onAppear { presenter.onAppear() } - + if !presenter.accountsDetails.isEmpty { VStack { Spacer() - + Button { presenter.disconnect() } label: { ZStack { RoundedRectangle(cornerRadius: 16) .fill(.white.opacity(0.02)) - + HStack { ZStack { Circle() .fill(.white.opacity(0.05)) .frame(width: 32, height: 32) - + Circle() .fill(.white.opacity(0.1)) .frame(width: 30, height: 30) - + Image("exit") .resizable() .frame(width: 14, height: 14) } - + Text("Disconnect") .font(.system(size: 16, weight: .medium)) .foregroundColor(Color(red: 0.58, green: 0.62, blue: 0.62)) - + Spacer() } .padding(.horizontal, 12) } .frame(height: 56) - + } .padding(20) } @@ -112,22 +150,32 @@ struct SignView: View { Color(red: 25/255, green: 26/255, blue: 26/255), for: .navigationBar ) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button(action: { + presenter.openConfiguration() + }) { + Image(systemName: "gearshape") + .foregroundColor(.white) + } + } + } .alert(presenter.errorMessage, isPresented: $presenter.showError) { Button("OK", role: .cancel) {} } } } - + private func networkItem(title: String, icon: String, id: String) -> some View { ZStack { RoundedRectangle(cornerRadius: 16) .fill(Color(red: 30/255, green: 31/255, blue: 31/255)) - + HStack(spacing: 10) { Image(icon == "eip155" ? "ethereum" : icon) .resizable() .frame(width: 40, height: 40) - + VStack(alignment: .leading, spacing: 5) { HStack { Text(title) @@ -135,23 +183,23 @@ struct SignView: View { .truncationMode(.middle) .font(.system(size: 16, weight: .medium)) .foregroundColor(Color(red: 228/255, green: 231/255, blue: 231/255)) - + Spacer() } - + HStack { Text(id) .lineLimit(1) .truncationMode(.middle) .font(.system(size: 13, weight: .regular)) .foregroundColor(Color(red: 0.58, green: 0.62, blue: 0.62)) - + Spacer() } } - + Spacer() - + if !presenter.accountsDetails.isEmpty { Image(systemName: "chevron.right") .foregroundColor(Color(red: 0.58, green: 0.62, blue: 0.62)) diff --git a/Example/DApp/SceneDelegate.swift b/Example/DApp/SceneDelegate.swift index 2586a7fd9..fd5b21c81 100644 --- a/Example/DApp/SceneDelegate.swift +++ b/Example/DApp/SceneDelegate.swift @@ -1,32 +1,36 @@ import UIKit -import Web3Modal -import Auth +import ReownAppKit import WalletConnectRelay import WalletConnectNetworking +import Combine + class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? + private var publishers = Set() private let app = Application() + + func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { + ProfilingService.instance.send(logMessage: .init(message: "SceneDelegate: will try to dispatch envelope - userActivity: \(String(describing: userActivity.webpageURL))")) + guard let url = userActivity.webpageURL, + let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else { + return + } + AppKit.instance.handleDeeplink(url) + } + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - Networking.configure(projectId: InputConfig.projectId, socketFactory: DefaultSocketFactory()) - Auth.configure(crypto: DefaultCryptoProvider()) - - let metadata = AppMetadata( - name: "Swift Dapp", - description: "WalletConnect DApp sample", - url: "wallet.connect", - icons: ["https://avatars.githubusercontent.com/u/37784886"], - redirect: AppMetadata.Redirect(native: "wcdapp://", universal: nil) - ) - - Web3Modal.configure( - projectId: InputConfig.projectId, - metadata: metadata - ) - + configureClientsIfNeeded() + setUpProfilingIfNeeded() + ProfilingService.instance.send(logMessage: .init(message: "SceneDelegate: willConnectTo : \(String(describing: connectionOptions.userActivities.first?.webpageURL?.absoluteString))")) + + configureClientsIfNeeded() + setUpProfilingIfNeeded() + + setupWindow(scene: scene) } @@ -34,9 +38,132 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { guard let windowScene = (scene as? UIWindowScene) else { return } window = UIWindow(windowScene: windowScene) - let viewController = MainModule.create(app: app) + let viewController = SignModule.create(app: app) + .wrapToNavigationController() window?.rootViewController = viewController window?.makeKeyAndVisible() } + + func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { + ProfilingService.instance.send(logMessage: .init(message: "SceneDelegate: - openURLContexts : \(String(describing: URLContexts.first?.url))")) + + guard let context = URLContexts.first else { return } + + let url = context.url + + guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false), + let queryItems = components.queryItems, + queryItems.contains(where: { $0.name == "wc_ev" }) else { + return + } + + do { + try Sign.instance.dispatchEnvelope(url.absoluteString) + } catch { + AlertPresenter.present(message: error.localizedDescription, type: .error) + } + } + + func sceneWillEnterForeground(_ scene: UIScene) { + ProfilingService.instance.send(logMessage: .init(message: "SceneDelegate: scene will enter foreground")) + // Additional code to handle entering the foreground + } + + func sceneDidBecomeActive(_ scene: UIScene) { + ProfilingService.instance.send(logMessage: .init(message: "SceneDelegate: scene did become active")) + // Additional code to handle becoming active + } + + private func setUpProfilingIfNeeded() { + if let clientId = try? Networking.interactor.getClientId() { + ProfilingService.instance.setUpProfiling(account: "swift_dapp_\(clientId)", clientId: clientId) + } + } + + var clientsConfigured = false + private func configureClientsIfNeeded() { + if clientsConfigured {return} + else {clientsConfigured = true} + Networking.configure( + groupIdentifier: Constants.groupIdentifier, + projectId: InputConfig.projectId, + socketFactory: DefaultSocketFactory() + ) + + let metadata = AppMetadata( + name: "Swift Dapp", + description: "WalletConnect DApp sample", + url: "https://lab.web3modal.com/dapp", + icons: ["https://avatars.githubusercontent.com/u/37784886"], + redirect: try! AppMetadata.Redirect(native: "wcdapp://", universal: "https://lab.web3modal.com/dapp", linkMode: true) + ) + + AppKit.configure( + projectId: InputConfig.projectId, + metadata: metadata, + crypto: DefaultCryptoProvider(), + authRequestParams: .stub(), // set to nil for non SIWE + customWallets: [ + .init( + id: "swift-sample", + name: "Swift Sample Wallet", + homepage: "https://walletconnect.com/", + imageUrl: "https://avatars.githubusercontent.com/u/37784886?s=200&v=4", + order: 1, + mobileLink: "walletapp://", + linkMode: "https://lab.web3modal.com/wallet" + ), + .init( + id: "rn-sample", + name: "RN Sample Wallet", + homepage: "https://walletconnect.com/", + imageUrl: "https://avatars.githubusercontent.com/u/37784886?s=200&v=4", + order: 1, + mobileLink: "rn-web3wallet://", + linkMode: "https://lab.web3modal.com/rn_walletkit" + ), + .init( + id: "flutter-sample-internal", + name: "FL Sample Wallet (internal)", + homepage: "https://walletconnect.com/", + imageUrl: "https://avatars.githubusercontent.com/u/37784886?s=200&v=4", + order: 1, + mobileLink: "wcflutterwallet-internal://", + linkMode: "https://dev.lab.web3modal.com/flutter_walletkit_internal" + ), + ] + ) + + AppKit.instance.authResponsePublisher.sink { (id, result) in + switch result { + case .success((_, _)): + AlertPresenter.present(message: "User Authenticted with SIWE", type: .success) + case .failure(_): + break + } + }.store(in: &publishers) + + Sign.instance.logger.setLogging(level: .debug) + Networking.instance.setLogging(level: .debug) + + Sign.instance.logsPublisher.sink { log in + switch log { + case .error(let logMessage): + AlertPresenter.present(message: logMessage.message, type: .error) + default: return + } + }.store(in: &publishers) + + Sign.instance.socketConnectionStatusPublisher.sink { status in + switch status { + case .connected: + AlertPresenter.present(message: "Your web socket has connected", type: .success) + case .disconnected: + AlertPresenter.present(message: "Your web socket is disconnected", type: .warning) + } + }.store(in: &publishers) + + AppKit.instance.disableAnalytics() + } } diff --git a/Example/ExampleApp.xcodeproj/IntegrationTests.xctestplan b/Example/ExampleApp.xcodeproj/IntegrationTests.xctestplan index 40b79df1d..a7e0d1b30 100644 --- a/Example/ExampleApp.xcodeproj/IntegrationTests.xctestplan +++ b/Example/ExampleApp.xcodeproj/IntegrationTests.xctestplan @@ -10,6 +10,11 @@ ], "defaultOptions" : { "codeCoverage" : false, + "commandLineArgumentEntries" : [ + { + "argument" : "isTesting" + } + ], "environmentVariableEntries" : [ { "key" : "RELAY_HOST", @@ -54,10 +59,12 @@ { "parallelizable" : true, "skippedTests" : [ + "AuthTests", "AuthTests\/testEIP1271RespondSuccess()", "ChatTests", "ENSResolverTests", "HistoryTests", + "NotifyTests", "SyncDerivationServiceTests", "SyncTests" ], diff --git a/Example/ExampleApp.xcodeproj/project.pbxproj b/Example/ExampleApp.xcodeproj/project.pbxproj index 4f5a2101c..988d32e57 100644 --- a/Example/ExampleApp.xcodeproj/project.pbxproj +++ b/Example/ExampleApp.xcodeproj/project.pbxproj @@ -8,9 +8,29 @@ /* Begin PBXBuildFile section */ 767DC83528997F8E00080FA9 /* EthSendTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 767DC83428997F8E00080FA9 /* EthSendTransaction.swift */; }; - 7694A5262874296A0001257E /* RegistryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7694A5252874296A0001257E /* RegistryTests.swift */; }; + 840507E32C8BAC7C00148A9B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 840507E22C8BAC7C00148A9B /* Preview Assets.xcassets */; }; + 8421447B2C80A2B8004FF494 /* ReownAppKit in Frameworks */ = {isa = PBXBuildFile; productRef = 8421447A2C80A2B8004FF494 /* ReownAppKit */; }; + 8421447D2C80A544004FF494 /* ReownAppKitUI in Frameworks */ = {isa = PBXBuildFile; productRef = 8421447C2C80A544004FF494 /* ReownAppKitUI */; }; + 8421447F2C81863A004FF494 /* ReownWalletKit in Frameworks */ = {isa = PBXBuildFile; productRef = 8421447E2C81863A004FF494 /* ReownWalletKit */; }; + 842144812C818684004FF494 /* ReownWalletKit in Frameworks */ = {isa = PBXBuildFile; productRef = 842144802C818684004FF494 /* ReownWalletKit */; }; + 842144832C818928004FF494 /* ReownWalletKit in Frameworks */ = {isa = PBXBuildFile; productRef = 842144822C818928004FF494 /* ReownWalletKit */; }; 84310D05298BC980000C15B6 /* MainInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84310D04298BC980000C15B6 /* MainInteractor.swift */; }; 8439CB89293F658E00F2F2E2 /* PushMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8439CB88293F658E00F2F2E2 /* PushMessage.swift */; }; + 844511922C8B689D00A6A86C /* AppKitLabApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844511912C8B689D00A6A86C /* AppKitLabApp.swift */; }; + 844511AC2C8B695500A6A86C /* InputConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844511A02C8B695300A6A86C /* InputConfig.swift */; }; + 844511AD2C8B695500A6A86C /* ComponentLibraryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844511A12C8B695400A6A86C /* ComponentLibraryView.swift */; }; + 844511AF2C8B695500A6A86C /* WCSocketFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844511A42C8B695400A6A86C /* WCSocketFactory.swift */; }; + 844511B02C8B695500A6A86C /* DefaultCryptoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844511A52C8B695400A6A86C /* DefaultCryptoProvider.swift */; }; + 844511B12C8B695500A6A86C /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844511A62C8B695500A6A86C /* ContentView.swift */; }; + 844511B32C8B695500A6A86C /* AlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844511A82C8B695500A6A86C /* AlertPresenter.swift */; }; + 844511B42C8B695500A6A86C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 844511A92C8B695500A6A86C /* Assets.xcassets */; }; + 844511B62C8B69F200A6A86C /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = 844511B52C8B69F200A6A86C /* Starscream */; }; + 844511BA2C8B6BC800A6A86C /* Atlantis in Frameworks */ = {isa = PBXBuildFile; productRef = 844511B92C8B6BC800A6A86C /* Atlantis */; }; + 844511BC2C8B6BE600A6A86C /* Web3ContractABI in Frameworks */ = {isa = PBXBuildFile; productRef = 844511BB2C8B6BE600A6A86C /* Web3ContractABI */; }; + 844511BE2C8B6BF000A6A86C /* ReownAppKitUI in Frameworks */ = {isa = PBXBuildFile; productRef = 844511BD2C8B6BF000A6A86C /* ReownAppKitUI */; }; + 844511C02C8B6BF800A6A86C /* Web3 in Frameworks */ = {isa = PBXBuildFile; productRef = 844511BF2C8B6BF800A6A86C /* Web3 */; }; + 844511C22C8B6C0600A6A86C /* SwiftMessages in Frameworks */ = {isa = PBXBuildFile; productRef = 844511C12C8B6C0600A6A86C /* SwiftMessages */; }; + 844511C42C8B6C0D00A6A86C /* ReownAppKit in Frameworks */ = {isa = PBXBuildFile; productRef = 844511C32C8B6C0D00A6A86C /* ReownAppKit */; }; 844749F629B9E5B9005F520B /* RelayClientEndToEndTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844749F529B9E5B9005F520B /* RelayClientEndToEndTests.swift */; }; 844749FD29B9E6B2005F520B /* WalletConnectNetworking in Frameworks */ = {isa = PBXBuildFile; productRef = 844749FC29B9E6B2005F520B /* WalletConnectNetworking */; }; 844749FE29B9EB1B005F520B /* InputConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A518B31328E33A6500A2CE93 /* InputConfig.swift */; }; @@ -19,6 +39,14 @@ 84474A0229B9ECA2005F520B /* DefaultSocketFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AEF2877F73000094373 /* DefaultSocketFactory.swift */; }; 8448F1D427E4726F0000B866 /* WalletConnect in Frameworks */ = {isa = PBXBuildFile; productRef = 8448F1D327E4726F0000B866 /* WalletConnect */; }; 845B8D8C2934B36C0084A966 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B8D8B2934B36C0084A966 /* Account.swift */; }; + 846E359F2C00654F00E63DF4 /* ConfigModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846E359E2C00654F00E63DF4 /* ConfigModule.swift */; }; + 846E35A22C0065AD00E63DF4 /* ConfigRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846E35A12C0065AD00E63DF4 /* ConfigRouter.swift */; }; + 846E35A42C0065B600E63DF4 /* ConfigPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846E35A32C0065B600E63DF4 /* ConfigPresenter.swift */; }; + 846E35A62C0065C100E63DF4 /* ConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846E35A52C0065C100E63DF4 /* ConfigView.swift */; }; + 846E35A82C006C5600E63DF4 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846E35A72C006C5600E63DF4 /* Constants.swift */; }; + 84733CD32C1C2A4B001B2850 /* AlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AEC2502B4D42C100E27A5B /* AlertPresenter.swift */; }; + 84733CD42C1C2C24001B2850 /* ProfilingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50B6A372B06697B00162B01 /* ProfilingService.swift */; }; + 84733CD52C1C2CEB001B2850 /* InputConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE25D293F56D6004840D1 /* InputConfig.swift */; }; 847BD1D62989492500076C90 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847BD1D12989492500076C90 /* MainViewController.swift */; }; 847BD1D82989492500076C90 /* MainModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847BD1D32989492500076C90 /* MainModule.swift */; }; 847BD1D92989492500076C90 /* MainPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847BD1D42989492500076C90 /* MainPresenter.swift */; }; @@ -31,24 +59,25 @@ 847BD1E8298A806800076C90 /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847BD1E3298A806800076C90 /* NotificationsView.swift */; }; 847BD1EB298A87AB00076C90 /* SubscriptionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847BD1EA298A87AB00076C90 /* SubscriptionsViewModel.swift */; }; 847F08012A25DBFF00B2A5A4 /* XPlatformW3WTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847F08002A25DBFF00B2A5A4 /* XPlatformW3WTests.swift */; }; - 8487A9442A836C2A0003D5AF /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 8487A9432A836C2A0003D5AF /* Sentry */; }; - 8487A9462A836C3F0003D5AF /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 8487A9452A836C3F0003D5AF /* Sentry */; }; + 8486EDD32B4F2EA6008E53C3 /* SwiftMessages in Frameworks */ = {isa = PBXBuildFile; productRef = 8486EDD22B4F2EA6008E53C3 /* SwiftMessages */; }; 8487A9482A83AD680003D5AF /* LoggingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8487A9472A83AD680003D5AF /* LoggingService.swift */; }; 84943C7B2A9BA206007EBAC2 /* Mixpanel in Frameworks */ = {isa = PBXBuildFile; productRef = 84943C7A2A9BA206007EBAC2 /* Mixpanel */; }; 84943C7D2A9BA328007EBAC2 /* Mixpanel in Frameworks */ = {isa = PBXBuildFile; productRef = 84943C7C2A9BA328007EBAC2 /* Mixpanel */; }; 849D7A93292E2169006A2BD4 /* NotifyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849D7A92292E2169006A2BD4 /* NotifyTests.swift */; }; 84A6E3C32A386BBC008A0571 /* Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A6E3C22A386BBC008A0571 /* Publisher.swift */; }; 84AA01DB28CF0CD7005D48D8 /* XCTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AA01DA28CF0CD7005D48D8 /* XCTest.swift */; }; + 84AEC24F2B4D1EE400E27A5B /* ActivityIndicatorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AEC24E2B4D1EE400E27A5B /* ActivityIndicatorManager.swift */; }; + 84AEC2512B4D42C100E27A5B /* AlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84AEC2502B4D42C100E27A5B /* AlertPresenter.swift */; }; + 84AEC2542B4D43CD00E27A5B /* SwiftMessages in Frameworks */ = {isa = PBXBuildFile; productRef = 84AEC2532B4D43CD00E27A5B /* SwiftMessages */; }; 84B8154E2991099000FAD54E /* BuildConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B8154D2991099000FAD54E /* BuildConfiguration.swift */; }; 84B8155B2992A18D00FAD54E /* NotifyMessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B8155A2992A18D00FAD54E /* NotifyMessageViewModel.swift */; }; + 84CA52172C88965C0069BB33 /* ReownRouter in Frameworks */ = {isa = PBXBuildFile; productRef = 84CA52162C88965C0069BB33 /* ReownRouter */; }; 84CE641F27981DED00142511 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CE641E27981DED00142511 /* AppDelegate.swift */; }; 84CE642127981DED00142511 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CE642027981DED00142511 /* SceneDelegate.swift */; }; 84CE642827981DF000142511 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 84CE642727981DF000142511 /* Assets.xcassets */; }; 84CE642B27981DF000142511 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 84CE642927981DF000142511 /* LaunchScreen.storyboard */; }; - 84CEC64628D89D6B00D081A8 /* PairingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CEC64528D89D6B00D081A8 /* PairingTests.swift */; }; - 84D2A66628A4F51E0088AE09 /* AuthTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D2A66528A4F51E0088AE09 /* AuthTests.swift */; }; + 84D093EB2B4EA6CB005B1925 /* ActivityIndicatorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D093EA2B4EA6CB005B1925 /* ActivityIndicatorManager.swift */; }; 84DB38F32983CDAE00BFEE37 /* PushRegisterer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84DB38F22983CDAE00BFEE37 /* PushRegisterer.swift */; }; - 84DDB4ED28ABB663003D66ED /* WalletConnectAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 84DDB4EC28ABB663003D66ED /* WalletConnectAuth */; }; 84E6B84A29787A8000428BAF /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E6B84929787A8000428BAF /* NotificationService.swift */; }; 84E6B84E29787A8000428BAF /* PNDecryptionService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 84E6B84729787A8000428BAF /* PNDecryptionService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 84FE684628ACDB4700C893FF /* RequestParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84FE684528ACDB4700C893FF /* RequestParams.swift */; }; @@ -60,11 +89,8 @@ A50D53C32ABA055700A4FD8B /* NotifyPreferencesRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50D53BE2ABA055700A4FD8B /* NotifyPreferencesRouter.swift */; }; A50D53C42ABA055700A4FD8B /* NotifyPreferencesInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50D53BF2ABA055700A4FD8B /* NotifyPreferencesInteractor.swift */; }; A50D53C52ABA055700A4FD8B /* NotifyPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50D53C02ABA055700A4FD8B /* NotifyPreferencesView.swift */; }; - A50DF19D2A25084A0036EA6C /* WalletConnectHistory in Frameworks */ = {isa = PBXBuildFile; productRef = A50DF19C2A25084A0036EA6C /* WalletConnectHistory */; }; - A50F3946288005B200064555 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50F3945288005B200064555 /* Types.swift */; }; A51606F82A2F47BD00CACB92 /* DefaultBIP44Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51606F72A2F47BD00CACB92 /* DefaultBIP44Provider.swift */; }; A51606F92A2F47BD00CACB92 /* DefaultBIP44Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51606F72A2F47BD00CACB92 /* DefaultBIP44Provider.swift */; }; - A51606FA2A2F47BD00CACB92 /* DefaultBIP44Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51606F72A2F47BD00CACB92 /* DefaultBIP44Provider.swift */; }; A51606FB2A2F47BD00CACB92 /* DefaultBIP44Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51606F72A2F47BD00CACB92 /* DefaultBIP44Provider.swift */; }; A51811982A52E21A00A52B15 /* ConfigurationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51811972A52E21A00A52B15 /* ConfigurationService.swift */; }; A518119F2A52E83100A52B15 /* SettingsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A518119A2A52E83100A52B15 /* SettingsModule.swift */; }; @@ -72,100 +98,30 @@ A51811A12A52E83100A52B15 /* SettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A518119C2A52E83100A52B15 /* SettingsRouter.swift */; }; A51811A22A52E83100A52B15 /* SettingsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A518119D2A52E83100A52B15 /* SettingsInteractor.swift */; }; A51811A32A52E83100A52B15 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A518119E2A52E83100A52B15 /* SettingsView.swift */; }; - A518A98729683FB60035247E /* Web3InboxViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A518A98429683FB60035247E /* Web3InboxViewController.swift */; }; - A518A98829683FB60035247E /* Web3InboxModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A518A98529683FB60035247E /* Web3InboxModule.swift */; }; - A518A98929683FB60035247E /* Web3InboxRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A518A98629683FB60035247E /* Web3InboxRouter.swift */; }; A518B31428E33A6500A2CE93 /* InputConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A518B31328E33A6500A2CE93 /* InputConfig.swift */; }; - A51AC0D928E436A3001BACF9 /* InputConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51AC0D828E436A3001BACF9 /* InputConfig.swift */; }; - A51AC0DF28E4379F001BACF9 /* InputConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51AC0DE28E4379F001BACF9 /* InputConfig.swift */; }; - A5321C2B2A250367006CADC3 /* HistoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5321C2A2A250367006CADC3 /* HistoryTests.swift */; }; - A5417BBE299BFC3E00B469F3 /* ImportAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5417BBD299BFC3E00B469F3 /* ImportAccount.swift */; }; A541959E2934BFEF0035AD19 /* CacaoSignerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A541959A2934BFEF0035AD19 /* CacaoSignerTests.swift */; }; A541959F2934BFEF0035AD19 /* SignerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A541959B2934BFEF0035AD19 /* SignerTests.swift */; }; A54195A02934BFEF0035AD19 /* EIP1271VerifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A541959C2934BFEF0035AD19 /* EIP1271VerifierTests.swift */; }; A54195A12934BFEF0035AD19 /* EIP191VerifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A541959D2934BFEF0035AD19 /* EIP191VerifierTests.swift */; }; A54195A52934E83F0035AD19 /* Web3 in Frameworks */ = {isa = PBXBuildFile; productRef = A54195A42934E83F0035AD19 /* Web3 */; }; - A561C80029DF32CE00DF540D /* HDWalletKit in Frameworks */ = {isa = PBXBuildFile; productRef = A561C7FF29DF32CE00DF540D /* HDWalletKit */; }; - A561C80329DFCCDC00DF540D /* SyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A561C80229DFCCDC00DF540D /* SyncTests.swift */; }; - A561C80529DFCD4500DF540D /* WalletConnectSync in Frameworks */ = {isa = PBXBuildFile; productRef = A561C80429DFCD4500DF540D /* WalletConnectSync */; }; - A5629AA92876A23100094373 /* ChatService.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AA82876A23100094373 /* ChatService.swift */; }; - A5629ABD2876CBC000094373 /* ChatListModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AB82876CBC000094373 /* ChatListModule.swift */; }; - A5629ABE2876CBC000094373 /* ChatListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AB92876CBC000094373 /* ChatListPresenter.swift */; }; - A5629ABF2876CBC000094373 /* ChatListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629ABA2876CBC000094373 /* ChatListRouter.swift */; }; - A5629AC02876CBC000094373 /* ChatListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629ABB2876CBC000094373 /* ChatListInteractor.swift */; }; - A5629AC12876CBC000094373 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629ABC2876CBC000094373 /* ChatListView.swift */; }; - A5629AD32876CC5700094373 /* InviteModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629ACE2876CC5700094373 /* InviteModule.swift */; }; - A5629AD42876CC5700094373 /* InvitePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629ACF2876CC5700094373 /* InvitePresenter.swift */; }; - A5629AD52876CC5700094373 /* InviteRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AD02876CC5700094373 /* InviteRouter.swift */; }; - A5629AD62876CC5700094373 /* InviteInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AD12876CC5700094373 /* InviteInteractor.swift */; }; - A5629AD72876CC5700094373 /* InviteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AD22876CC5700094373 /* InviteView.swift */; }; - A5629ADE2876CC6E00094373 /* InviteListModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AD92876CC6E00094373 /* InviteListModule.swift */; }; - A5629ADF2876CC6E00094373 /* InviteListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629ADA2876CC6E00094373 /* InviteListPresenter.swift */; }; - A5629AE02876CC6E00094373 /* InviteListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629ADB2876CC6E00094373 /* InviteListRouter.swift */; }; - A5629AE12876CC6E00094373 /* InviteListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629ADC2876CC6E00094373 /* InviteListInteractor.swift */; }; - A5629AE22876CC6E00094373 /* InviteListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629ADD2876CC6E00094373 /* InviteListView.swift */; }; - A5629AE42876E6D200094373 /* ThreadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AE32876E6D200094373 /* ThreadViewModel.swift */; }; - A5629AE828772A0100094373 /* InviteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AE728772A0100094373 /* InviteViewModel.swift */; }; - A5629AEA2877F2D600094373 /* WalletConnectChat in Frameworks */ = {isa = PBXBuildFile; productRef = A5629AE92877F2D600094373 /* WalletConnectChat */; }; - A5629AF22877F75100094373 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = A5629AF12877F75100094373 /* Starscream */; }; A56AC8F22AD88A5A001C8FAA /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = A56AC8F12AD88A5A001C8FAA /* Sequence.swift */; }; - A573C53729EC34A600E3CBFD /* SyncDerivationServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A573C53629EC34A600E3CBFD /* SyncDerivationServiceTests.swift */; }; A573C53929EC365000E3CBFD /* HDWalletKit in Frameworks */ = {isa = PBXBuildFile; productRef = A573C53829EC365000E3CBFD /* HDWalletKit */; }; A573C53B29EC365800E3CBFD /* HDWalletKit in Frameworks */ = {isa = PBXBuildFile; productRef = A573C53A29EC365800E3CBFD /* HDWalletKit */; }; A573C53D29EC366500E3CBFD /* HDWalletKit in Frameworks */ = {isa = PBXBuildFile; productRef = A573C53C29EC366500E3CBFD /* HDWalletKit */; }; A57879712A4EDC8100F8D10B /* TextFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57879702A4EDC8100F8D10B /* TextFieldView.swift */; }; A57879722A4F225E00F8D10B /* ImportAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5417BBD299BFC3E00B469F3 /* ImportAccount.swift */; }; A57879732A4F248200F8D10B /* AccountStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C20228287EB34C007E3188 /* AccountStorage.swift */; }; - A578FA322873036400AA7720 /* InputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A578FA312873036400AA7720 /* InputView.swift */; }; - A578FA35287304A300AA7720 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = A578FA34287304A300AA7720 /* Color.swift */; }; - A578FA372873D8EE00AA7720 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A578FA362873D8EE00AA7720 /* UIColor.swift */; }; - A578FA392873FCE000AA7720 /* ChatScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A578FA382873FCE000AA7720 /* ChatScrollView.swift */; }; - A578FA3D2874002400AA7720 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = A578FA3C2874002400AA7720 /* View.swift */; }; A58A1ECC29BF458600A82A20 /* ENSResolverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58A1ECB29BF458600A82A20 /* ENSResolverTests.swift */; }; - A58E7CEB28729F550082D443 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7CEA28729F550082D443 /* AppDelegate.swift */; }; - A58E7CED28729F550082D443 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7CEC28729F550082D443 /* SceneDelegate.swift */; }; - A58E7CF428729F550082D443 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A58E7CF328729F550082D443 /* Assets.xcassets */; }; - A58E7CF728729F550082D443 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A58E7CF528729F550082D443 /* LaunchScreen.storyboard */; }; - A58E7D002872A1050082D443 /* SceneViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7CFF2872A1050082D443 /* SceneViewController.swift */; }; - A58E7D032872A1630082D443 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D022872A1630082D443 /* String.swift */; }; - A58E7D0C2872A45B0082D443 /* MainModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D072872A45B0082D443 /* MainModule.swift */; }; - A58E7D0D2872A45B0082D443 /* MainPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D082872A45B0082D443 /* MainPresenter.swift */; }; - A58E7D0E2872A45B0082D443 /* MainRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D092872A45B0082D443 /* MainRouter.swift */; }; - A58E7D132872A4A80082D443 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D122872A4A80082D443 /* Application.swift */; }; - A58E7D152872A5410082D443 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D142872A5410082D443 /* UIViewController.swift */; }; - A58E7D1D2872A57B0082D443 /* Configurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D172872A57B0082D443 /* Configurator.swift */; }; - A58E7D1E2872A57B0082D443 /* ThirdPartyConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D182872A57B0082D443 /* ThirdPartyConfigurator.swift */; }; - A58E7D1F2872A57B0082D443 /* ApplicationConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D192872A57B0082D443 /* ApplicationConfigurator.swift */; }; - A58E7D212872A57B0082D443 /* MigrationConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D1B2872A57B0082D443 /* MigrationConfigurator.swift */; }; - A58E7D222872A57B0082D443 /* AppearanceConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D1C2872A57B0082D443 /* AppearanceConfigurator.swift */; }; - A58E7D242872AB130082D443 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D232872AB130082D443 /* MainViewController.swift */; }; - A58E7D392872D55F0082D443 /* ChatModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D342872D55F0082D443 /* ChatModule.swift */; }; - A58E7D3A2872D55F0082D443 /* ChatRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D352872D55F0082D443 /* ChatRouter.swift */; }; - A58E7D3B2872D55F0082D443 /* ChatInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D362872D55F0082D443 /* ChatInteractor.swift */; }; - A58E7D3C2872D55F0082D443 /* ChatPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D372872D55F0082D443 /* ChatPresenter.swift */; }; - A58E7D3D2872D55F0082D443 /* ChatView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D382872D55F0082D443 /* ChatView.swift */; }; - A58E7D3F2872E99A0082D443 /* TabPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D3E2872E99A0082D443 /* TabPage.swift */; }; - A58E7D432872EE320082D443 /* MessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D422872EE320082D443 /* MessageView.swift */; }; - A58E7D452872EE570082D443 /* ContentMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D442872EE570082D443 /* ContentMessageView.swift */; }; - A58E7D482872EF610082D443 /* MessageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E7D472872EF610082D443 /* MessageViewModel.swift */; }; - A58EC611299D57B800F3452A /* AsyncButton in Frameworks */ = {isa = PBXBuildFile; productRef = A58EC610299D57B800F3452A /* AsyncButton */; }; - A58EC616299D5C6400F3452A /* PlainButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58EC615299D5C6400F3452A /* PlainButton.swift */; }; - A58EC618299D665A00F3452A /* Web3Inbox in Frameworks */ = {isa = PBXBuildFile; productRef = A58EC617299D665A00F3452A /* Web3Inbox */; }; A59CF4F6292F83D50031A42F /* DefaultSignerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59CF4F5292F83D50031A42F /* DefaultSignerFactory.swift */; }; A59D25EE2AB3672700D7EA3A /* AsyncButton in Frameworks */ = {isa = PBXBuildFile; productRef = A59D25ED2AB3672700D7EA3A /* AsyncButton */; }; - A59F877628B5462900A9CD80 /* WalletConnectAuth in Frameworks */ = {isa = PBXBuildFile; productRef = A59F877528B5462900A9CD80 /* WalletConnectAuth */; }; - A59FAEC928B7B93A002BB66F /* Web3 in Frameworks */ = {isa = PBXBuildFile; productRef = A59FAEC828B7B93A002BB66F /* Web3 */; }; A5A0843D29D2F624000B9B17 /* DefaultCryptoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A0843B29D2F60A000B9B17 /* DefaultCryptoProvider.swift */; }; A5A0843E29D2F624000B9B17 /* DefaultCryptoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A0843B29D2F60A000B9B17 /* DefaultCryptoProvider.swift */; }; - A5A0843F29D2F625000B9B17 /* DefaultCryptoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A0843B29D2F60A000B9B17 /* DefaultCryptoProvider.swift */; }; A5A0844029D2F626000B9B17 /* DefaultCryptoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A0843B29D2F60A000B9B17 /* DefaultCryptoProvider.swift */; }; A5A4FC772840C12C00BBEC1E /* RegressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A4FC762840C12C00BBEC1E /* RegressionTests.swift */; }; A5A650CA2B062A1400F9AD4B /* Mixpanel in Frameworks */ = {isa = PBXBuildFile; productRef = A5A650C92B062A1400F9AD4B /* Mixpanel */; }; A5A8E47A293A1C9B00FEB97D /* DefaultSocketFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AEF2877F73000094373 /* DefaultSocketFactory.swift */; }; A5A8E47D293A1CFE00FEB97D /* DefaultSocketFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AEF2877F73000094373 /* DefaultSocketFactory.swift */; }; A5A8E47E293A1CFE00FEB97D /* DefaultSignerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59CF4F5292F83D50031A42F /* DefaultSignerFactory.swift */; }; - A5A8E47F293A1D0000FEB97D /* DefaultSocketFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AEF2877F73000094373 /* DefaultSocketFactory.swift */; }; - A5A8E480293A1D0000FEB97D /* DefaultSignerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59CF4F5292F83D50031A42F /* DefaultSignerFactory.swift */; }; A5B4F7C22ABB20AE0099AF7C /* SubscriptionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5B4F7BD2ABB20AE0099AF7C /* SubscriptionPresenter.swift */; }; A5B4F7C32ABB20AE0099AF7C /* SubscriptionInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5B4F7BE2ABB20AE0099AF7C /* SubscriptionInteractor.swift */; }; A5B4F7C42ABB20AE0099AF7C /* SubscriptionModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5B4F7BF2ABB20AE0099AF7C /* SubscriptionModule.swift */; }; @@ -176,22 +132,7 @@ A5B6C0F32A6EAB1700927332 /* WalletConnectNotify in Frameworks */ = {isa = PBXBuildFile; productRef = A5B6C0F22A6EAB1700927332 /* WalletConnectNotify */; }; A5B6C0F52A6EAB2800927332 /* WalletConnectNotify in Frameworks */ = {isa = PBXBuildFile; productRef = A5B6C0F42A6EAB2800927332 /* WalletConnectNotify */; }; A5B6C0F72A6EAB3200927332 /* WalletConnectNotify in Frameworks */ = {isa = PBXBuildFile; productRef = A5B6C0F62A6EAB3200927332 /* WalletConnectNotify */; }; - A5BB7FA328B6A50400707FC6 /* WalletConnectAuth in Frameworks */ = {isa = PBXBuildFile; productRef = A5BB7FA228B6A50400707FC6 /* WalletConnectAuth */; }; A5BB7FAD28B6AA7D00707FC6 /* QRCodeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5BB7FAC28B6AA7D00707FC6 /* QRCodeGenerator.swift */; }; - A5C2020B287D9DEE007E3188 /* WelcomeModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C20206287D9DEE007E3188 /* WelcomeModule.swift */; }; - A5C2020C287D9DEE007E3188 /* WelcomePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C20207287D9DEE007E3188 /* WelcomePresenter.swift */; }; - A5C2020D287D9DEE007E3188 /* WelcomeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C20208287D9DEE007E3188 /* WelcomeRouter.swift */; }; - A5C2020F287D9DEE007E3188 /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C2020A287D9DEE007E3188 /* WelcomeView.swift */; }; - A5C20219287E1FD8007E3188 /* ImportModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C20214287E1FD8007E3188 /* ImportModule.swift */; }; - A5C2021A287E1FD8007E3188 /* ImportPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C20215287E1FD8007E3188 /* ImportPresenter.swift */; }; - A5C2021B287E1FD8007E3188 /* ImportRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C20216287E1FD8007E3188 /* ImportRouter.swift */; }; - A5C2021C287E1FD8007E3188 /* ImportInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C20217287E1FD8007E3188 /* ImportInteractor.swift */; }; - A5C2021D287E1FD8007E3188 /* ImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C20218287E1FD8007E3188 /* ImportView.swift */; }; - A5C20221287EA5B8007E3188 /* TextFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C20220287EA5B8007E3188 /* TextFieldView.swift */; }; - A5C20223287EA7E2007E3188 /* BrandButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C20222287EA7E2007E3188 /* BrandButton.swift */; }; - A5C20229287EB34C007E3188 /* AccountStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C20228287EB34C007E3188 /* AccountStorage.swift */; }; - A5C2022B287EB89A007E3188 /* WelcomeInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C2022A287EB89A007E3188 /* WelcomeInteractor.swift */; }; - A5C5153329BB7A6A004210BA /* InviteType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C5153229BB7A6A004210BA /* InviteType.swift */; }; A5C8BE85292FE20B006CC85C /* Web3 in Frameworks */ = {isa = PBXBuildFile; productRef = A5C8BE84292FE20B006CC85C /* Web3 */; }; A5D610C82AB31EE800C20083 /* SegmentedPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D610C72AB31EE800C20083 /* SegmentedPicker.swift */; }; A5D610CA2AB3249100C20083 /* ListingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D610C92AB3249100C20083 /* ListingViewModel.swift */; }; @@ -204,8 +145,6 @@ A5E03DFA286465C700888481 /* SignClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E03DF9286465C700888481 /* SignClientTests.swift */; }; A5E03DFD286465D100888481 /* Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E03DFC286465D100888481 /* Stubs.swift */; }; A5E03DFF2864662500888481 /* WalletConnect in Frameworks */ = {isa = PBXBuildFile; productRef = A5E03DFE2864662500888481 /* WalletConnect */; }; - A5E03E01286466EA00888481 /* WalletConnectChat in Frameworks */ = {isa = PBXBuildFile; productRef = A5E03E00286466EA00888481 /* WalletConnectChat */; }; - A5E03E03286466F400888481 /* ChatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E03E02286466F400888481 /* ChatTests.swift */; }; A5E03E1128646F8000888481 /* KeychainStorageMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E03E1028646F8000888481 /* KeychainStorageMock.swift */; }; A5E22D1A2840C62A00E36487 /* Engine.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E22D192840C62A00E36487 /* Engine.swift */; }; A5E22D1C2840C85D00E36487 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E22D1B2840C85D00E36487 /* App.swift */; }; @@ -214,16 +153,12 @@ A5E22D222840C8D300E36487 /* WalletEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E22D212840C8D300E36487 /* WalletEngine.swift */; }; A5E22D242840C8DB00E36487 /* SafariEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E22D232840C8DB00E36487 /* SafariEngine.swift */; }; A5E22D2C2840EAC300E36487 /* XCUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E22D2B2840EAC300E36487 /* XCUIElement.swift */; }; - A5E776BA29F4362D00172091 /* AlertError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E776B929F4362D00172091 /* AlertError.swift */; }; - A5F1526F2ACDC46B00D745A6 /* Web3ModalUI in Frameworks */ = {isa = PBXBuildFile; productRef = A5F1526E2ACDC46B00D745A6 /* Web3ModalUI */; }; A74D32BA2A1E25AD00CB8536 /* QueryParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = A74D32B92A1E25AD00CB8536 /* QueryParameters.swift */; }; C5133A78294125CC00A8314C /* Web3 in Frameworks */ = {isa = PBXBuildFile; productRef = C5133A77294125CC00A8314C /* Web3 */; }; C53AA4362941251C008EA57C /* DefaultSignerFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59CF4F5292F83D50031A42F /* DefaultSignerFactory.swift */; }; - C54C24902AEB1B5600DA4BF6 /* WalletConnectRouter in Frameworks */ = {isa = PBXBuildFile; productRef = C54C248F2AEB1B5600DA4BF6 /* WalletConnectRouter */; }; C55D347F295DD7140004314A /* AuthRequestModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D347A295DD7140004314A /* AuthRequestModule.swift */; }; C55D3480295DD7140004314A /* AuthRequestPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D347B295DD7140004314A /* AuthRequestPresenter.swift */; }; C55D3481295DD7140004314A /* AuthRequestRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D347C295DD7140004314A /* AuthRequestRouter.swift */; }; - C55D3482295DD7140004314A /* AuthRequestInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D347D295DD7140004314A /* AuthRequestInteractor.swift */; }; C55D3483295DD7140004314A /* AuthRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D347E295DD7140004314A /* AuthRequestView.swift */; }; C55D3489295DD8CA0004314A /* PasteUriModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3484295DD8CA0004314A /* PasteUriModule.swift */; }; C55D348A295DD8CA0004314A /* PasteUriPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3485295DD8CA0004314A /* PasteUriPresenter.swift */; }; @@ -235,7 +170,6 @@ C55D3495295DFA750004314A /* WelcomeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3490295DFA750004314A /* WelcomeRouter.swift */; }; C55D3496295DFA750004314A /* WelcomeInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3491295DFA750004314A /* WelcomeInteractor.swift */; }; C55D3497295DFA750004314A /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D3492295DFA750004314A /* WelcomeView.swift */; }; - C55D349929630D440004314A /* Web3Wallet in Frameworks */ = {isa = PBXBuildFile; productRef = C55D349829630D440004314A /* Web3Wallet */; }; C55D349B2965BC2F0004314A /* TagsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D349A2965BC2F0004314A /* TagsView.swift */; }; C55D34AE2965FB750004314A /* SessionProposalModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D34A92965FB750004314A /* SessionProposalModule.swift */; }; C55D34AF2965FB750004314A /* SessionProposalPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55D34AA2965FB750004314A /* SessionProposalPresenter.swift */; }; @@ -264,8 +198,6 @@ C56EE275293F56D7004840D1 /* InputConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE25D293F56D6004840D1 /* InputConfig.swift */; }; C56EE276293F56D7004840D1 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE26C293F56D6004840D1 /* UIViewController.swift */; }; C56EE279293F56D7004840D1 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE268293F56D6004840D1 /* Color.swift */; }; - C56EE27B293F56F8004840D1 /* WalletConnectAuth in Frameworks */ = {isa = PBXBuildFile; productRef = C56EE27A293F56F8004840D1 /* WalletConnectAuth */; }; - C56EE27D293F56F8004840D1 /* WalletConnectChat in Frameworks */ = {isa = PBXBuildFile; productRef = C56EE27C293F56F8004840D1 /* WalletConnectChat */; }; C56EE288293F5757004840D1 /* ThirdPartyConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE286293F5757004840D1 /* ThirdPartyConfigurator.swift */; }; C56EE289293F5757004840D1 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE280293F5757004840D1 /* Application.swift */; }; C56EE28A293F5757004840D1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE27F293F5757004840D1 /* AppDelegate.swift */; }; @@ -275,7 +207,6 @@ C56EE28E293F5757004840D1 /* ApplicationConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE284293F5757004840D1 /* ApplicationConfigurator.swift */; }; C56EE28F293F5757004840D1 /* MigrationConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE283293F5757004840D1 /* MigrationConfigurator.swift */; }; C56EE2A3293F6BAF004840D1 /* UIPasteboardWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE2A2293F6BAF004840D1 /* UIPasteboardWrapper.swift */; }; - C579FEB62AFA86CD008855EB /* Web3Modal in Frameworks */ = {isa = PBXBuildFile; productRef = C579FEB52AFA86CD008855EB /* Web3Modal */; }; C579FEBA2AFCDFA6008855EB /* ConnectedSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C579FEB92AFCDFA6008855EB /* ConnectedSheetView.swift */; }; C58099352A543CD000AB58F5 /* BlinkAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C58099342A543CD000AB58F5 /* BlinkAnimation.swift */; }; C5B2F6F629705293000DBA0E /* SessionRequestModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5B2F6F12970511B000DBA0E /* SessionRequestModule.swift */; }; @@ -289,13 +220,7 @@ C5B2F7052970573D000DBA0E /* SolanaSwift in Frameworks */ = {isa = PBXBuildFile; productRef = C5B2F7042970573D000DBA0E /* SolanaSwift */; }; C5B2F71029705827000DBA0E /* EthereumTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F568C32795832A00D0A289 /* EthereumTransaction.swift */; }; C5B4C4C42AF11C8B00B4274A /* SignView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5B4C4C32AF11C8B00B4274A /* SignView.swift */; }; - C5B4C4CF2AF12F1600B4274A /* AuthView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5B4C4CE2AF12F1600B4274A /* AuthView.swift */; }; C5BE01D12AF661D70064FC88 /* NewPairingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE01D02AF661D70064FC88 /* NewPairingView.swift */; }; - C5BE01D72AF691CD0064FC88 /* AuthModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE01D62AF691CD0064FC88 /* AuthModule.swift */; }; - C5BE01D92AF691FE0064FC88 /* AuthPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE01D82AF691FE0064FC88 /* AuthPresenter.swift */; }; - C5BE01DB2AF692060064FC88 /* AuthRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE01DA2AF692060064FC88 /* AuthRouter.swift */; }; - C5BE01DD2AF692100064FC88 /* AuthInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE01DC2AF692100064FC88 /* AuthInteractor.swift */; }; - C5BE01DF2AF692D80064FC88 /* WalletConnectRouter in Frameworks */ = {isa = PBXBuildFile; productRef = C5BE01DE2AF692D80064FC88 /* WalletConnectRouter */; }; C5BE01E22AF693080064FC88 /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE01E12AF693080064FC88 /* Application.swift */; }; C5BE01E32AF696540064FC88 /* SceneViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE264293F56D6004840D1 /* SceneViewController.swift */; }; C5BE01E42AF697100064FC88 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE26B293F56D6004840D1 /* UIColor.swift */; }; @@ -310,12 +235,6 @@ C5BE02022AF774CB0064FC88 /* NewPairingInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE01F62AF6CA2B0064FC88 /* NewPairingInteractor.swift */; }; C5BE02032AF774CB0064FC88 /* NewPairingPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE01F42AF6CA2B0064FC88 /* NewPairingPresenter.swift */; }; C5BE02042AF7764F0064FC88 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C56EE26C293F56D6004840D1 /* UIViewController.swift */; }; - C5BE020E2AF777AD0064FC88 /* MainRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE02082AF777AD0064FC88 /* MainRouter.swift */; }; - C5BE020F2AF777AD0064FC88 /* TabPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE020D2AF777AD0064FC88 /* TabPage.swift */; }; - C5BE02102AF777AD0064FC88 /* MainModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE02072AF777AD0064FC88 /* MainModule.swift */; }; - C5BE02112AF777AD0064FC88 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE020A2AF777AD0064FC88 /* MainViewController.swift */; }; - C5BE02122AF777AD0064FC88 /* MainPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE020B2AF777AD0064FC88 /* MainPresenter.swift */; }; - C5BE02132AF777AD0064FC88 /* MainInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE02092AF777AD0064FC88 /* MainInteractor.swift */; }; C5BE02142AF77A940064FC88 /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C5F32A352954FE3C00A6476E /* Colors.xcassets */; }; C5BE021B2AF79B9A0064FC88 /* SessionAccountPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE02172AF79B950064FC88 /* SessionAccountPresenter.swift */; }; C5BE021C2AF79B9A0064FC88 /* SessionAccountRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE02162AF79B950064FC88 /* SessionAccountRouter.swift */; }; @@ -323,10 +242,8 @@ C5BE021E2AF79B9A0064FC88 /* SessionAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE02192AF79B950064FC88 /* SessionAccountView.swift */; }; C5BE021F2AF79B9A0064FC88 /* SessionAccountModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5BE021A2AF79B960064FC88 /* SessionAccountModule.swift */; }; C5D4603A29687A5700302C7E /* DefaultSocketFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AEF2877F73000094373 /* DefaultSocketFactory.swift */; }; - C5DD5BE1294E09E3008FD3A4 /* Web3Wallet in Frameworks */ = {isa = PBXBuildFile; productRef = C5DD5BE0294E09E3008FD3A4 /* Web3Wallet */; }; C5F32A2C2954814200A6476E /* ConnectionDetailsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A2B2954814200A6476E /* ConnectionDetailsModule.swift */; }; C5F32A2E2954814A00A6476E /* ConnectionDetailsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A2D2954814A00A6476E /* ConnectionDetailsRouter.swift */; }; - C5F32A302954816100A6476E /* ConnectionDetailsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C5F32A2F2954816100A6476E /* ConnectionDetailsInteractor.swift */; }; 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 */; }; @@ -344,7 +261,6 @@ CF1A594B29E5876600AAC16B /* DAppEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF1A594229E5876600AAC16B /* DAppEngine.swift */; }; CF1A594C29E5876600AAC16B /* RoutingEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF1A594329E5876600AAC16B /* RoutingEngine.swift */; }; CF1A594D29E5876600AAC16B /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF1A594429E5876600AAC16B /* App.swift */; }; - CF25F2892A432476009C7E49 /* WalletConnectModal in Frameworks */ = {isa = PBXBuildFile; productRef = CF25F2882A432476009C7E49 /* WalletConnectModal */; }; CF6704DF29E59DDC003326A4 /* XCUIElementQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF6704DE29E59DDC003326A4 /* XCUIElementQuery.swift */; }; CF6704E129E5A014003326A4 /* XCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF6704E029E5A014003326A4 /* XCTestCase.swift */; }; /* End PBXBuildFile section */ @@ -406,14 +322,31 @@ 764E1D5526F8DADE00A1FB15 /* WalletConnectSwiftV2 */ = {isa = PBXFileReference; lastKnownFileType = folder; name = WalletConnectSwiftV2; path = ..; sourceTree = ""; }; 764E1D5626F8DB6000A1FB15 /* WalletConnectSwiftV2 */ = {isa = PBXFileReference; lastKnownFileType = folder; name = WalletConnectSwiftV2; path = ..; sourceTree = ""; }; 767DC83428997F8E00080FA9 /* EthSendTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthSendTransaction.swift; sourceTree = ""; }; - 7694A5252874296A0001257E /* RegistryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistryTests.swift; sourceTree = ""; }; + 840507E22C8BAC7C00148A9B /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 84310D04298BC980000C15B6 /* MainInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainInteractor.swift; sourceTree = ""; }; 8439CB88293F658E00F2F2E2 /* PushMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushMessage.swift; sourceTree = ""; }; + 8445118F2C8B689D00A6A86C /* AppKitLab.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AppKitLab.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 844511912C8B689D00A6A86C /* AppKitLabApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppKitLabApp.swift; sourceTree = ""; }; + 844511A02C8B695300A6A86C /* InputConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputConfig.swift; sourceTree = ""; }; + 844511A12C8B695400A6A86C /* ComponentLibraryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComponentLibraryView.swift; sourceTree = ""; }; + 844511A22C8B695400A6A86C /* Example.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Example.entitlements; sourceTree = ""; }; + 844511A42C8B695400A6A86C /* WCSocketFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WCSocketFactory.swift; sourceTree = ""; }; + 844511A52C8B695400A6A86C /* DefaultCryptoProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultCryptoProvider.swift; sourceTree = ""; }; + 844511A62C8B695500A6A86C /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 844511A82C8B695500A6A86C /* AlertPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertPresenter.swift; sourceTree = ""; }; + 844511A92C8B695500A6A86C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 844511C82C8BA12200A6A86C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 844511C92C8BA69D00A6A86C /* AppKitLab.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = AppKitLab.entitlements; sourceTree = ""; }; 844749F329B9E5B9005F520B /* RelayIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RelayIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 844749F529B9E5B9005F520B /* RelayClientEndToEndTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayClientEndToEndTests.swift; sourceTree = ""; }; 845AA7D929BA1EBA00F33739 /* IntegrationTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = IntegrationTests.xctestplan; path = ExampleApp.xcodeproj/IntegrationTests.xctestplan; sourceTree = ""; }; 845AA7DC29BB424800F33739 /* SmokeTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = SmokeTests.xctestplan; sourceTree = ""; }; 845B8D8B2934B36C0084A966 /* Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = ""; }; + 846E359E2C00654F00E63DF4 /* ConfigModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigModule.swift; sourceTree = ""; }; + 846E35A12C0065AD00E63DF4 /* ConfigRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigRouter.swift; sourceTree = ""; }; + 846E35A32C0065B600E63DF4 /* ConfigPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigPresenter.swift; sourceTree = ""; }; + 846E35A52C0065C100E63DF4 /* ConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigView.swift; sourceTree = ""; }; + 846E35A72C006C5600E63DF4 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 847BD1D12989492500076C90 /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; 847BD1D32989492500076C90 /* MainModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainModule.swift; sourceTree = ""; }; 847BD1D42989492500076C90 /* MainPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainPresenter.swift; sourceTree = ""; }; @@ -433,6 +366,8 @@ 849D7A92292E2169006A2BD4 /* NotifyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotifyTests.swift; sourceTree = ""; }; 84A6E3C22A386BBC008A0571 /* Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Publisher.swift; sourceTree = ""; }; 84AA01DA28CF0CD7005D48D8 /* XCTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTest.swift; sourceTree = ""; }; + 84AEC24E2B4D1EE400E27A5B /* ActivityIndicatorManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityIndicatorManager.swift; sourceTree = ""; }; + 84AEC2502B4D42C100E27A5B /* AlertPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertPresenter.swift; sourceTree = ""; }; 84B8154D2991099000FAD54E /* BuildConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildConfiguration.swift; sourceTree = ""; }; 84B8155A2992A18D00FAD54E /* NotifyMessageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotifyMessageViewModel.swift; sourceTree = ""; }; 84CE641C27981DED00142511 /* DApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -442,14 +377,15 @@ 84CE642A27981DF000142511 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 84CE642C27981DF000142511 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 84CE6453279FFE1100142511 /* Wallet.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Wallet.entitlements; sourceTree = ""; }; - 84CEC64528D89D6B00D081A8 /* PairingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PairingTests.swift; sourceTree = ""; }; - 84D2A66528A4F51E0088AE09 /* AuthTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthTests.swift; sourceTree = ""; }; + 84D093EA2B4EA6CB005B1925 /* ActivityIndicatorManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityIndicatorManager.swift; sourceTree = ""; }; + 84D72FC62B4692770057EAF3 /* DApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DApp.entitlements; sourceTree = ""; }; 84DB38F029828A7C00BFEE37 /* WalletApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WalletApp.entitlements; sourceTree = ""; }; 84DB38F129828A7F00BFEE37 /* PNDecryptionService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = PNDecryptionService.entitlements; sourceTree = ""; }; 84DB38F22983CDAE00BFEE37 /* PushRegisterer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushRegisterer.swift; sourceTree = ""; }; 84E6B84729787A8000428BAF /* PNDecryptionService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = PNDecryptionService.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 84E6B84929787A8000428BAF /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; 84E6B84B29787A8000428BAF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 84F1CD392BBD414000D2A6E2 /* DAppRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DAppRelease.entitlements; sourceTree = ""; }; 84F568C1279582D200D0A289 /* Signer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Signer.swift; sourceTree = ""; }; 84F568C32795832A00D0A289 /* EthereumTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthereumTransaction.swift; sourceTree = ""; }; 84FE684528ACDB4700C893FF /* RequestParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestParams.swift; sourceTree = ""; }; @@ -460,7 +396,6 @@ A50D53BE2ABA055700A4FD8B /* NotifyPreferencesRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotifyPreferencesRouter.swift; sourceTree = ""; }; A50D53BF2ABA055700A4FD8B /* NotifyPreferencesInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotifyPreferencesInteractor.swift; sourceTree = ""; }; A50D53C02ABA055700A4FD8B /* NotifyPreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotifyPreferencesView.swift; sourceTree = ""; }; - A50F3945288005B200064555 /* Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Types.swift; sourceTree = ""; }; A51606F72A2F47BD00CACB92 /* DefaultBIP44Provider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultBIP44Provider.swift; sourceTree = ""; }; A51811972A52E21A00A52B15 /* ConfigurationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationService.swift; sourceTree = ""; }; A518119A2A52E83100A52B15 /* SettingsModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModule.swift; sourceTree = ""; }; @@ -468,78 +403,18 @@ A518119C2A52E83100A52B15 /* SettingsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRouter.swift; sourceTree = ""; }; A518119D2A52E83100A52B15 /* SettingsInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsInteractor.swift; sourceTree = ""; }; A518119E2A52E83100A52B15 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; - A518A98429683FB60035247E /* Web3InboxViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Web3InboxViewController.swift; sourceTree = ""; }; - A518A98529683FB60035247E /* Web3InboxModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Web3InboxModule.swift; sourceTree = ""; }; - A518A98629683FB60035247E /* Web3InboxRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Web3InboxRouter.swift; sourceTree = ""; }; A518B31328E33A6500A2CE93 /* InputConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputConfig.swift; sourceTree = ""; }; - A51AC0D828E436A3001BACF9 /* InputConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputConfig.swift; sourceTree = ""; }; - A51AC0DE28E4379F001BACF9 /* InputConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputConfig.swift; sourceTree = ""; }; - A5321C2A2A250367006CADC3 /* HistoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryTests.swift; sourceTree = ""; }; A5417BBD299BFC3E00B469F3 /* ImportAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportAccount.swift; sourceTree = ""; }; A541959A2934BFEF0035AD19 /* CacaoSignerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CacaoSignerTests.swift; sourceTree = ""; }; A541959B2934BFEF0035AD19 /* SignerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignerTests.swift; sourceTree = ""; }; A541959C2934BFEF0035AD19 /* EIP1271VerifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EIP1271VerifierTests.swift; sourceTree = ""; }; A541959D2934BFEF0035AD19 /* EIP191VerifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EIP191VerifierTests.swift; sourceTree = ""; }; - A561C80229DFCCDC00DF540D /* SyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncTests.swift; sourceTree = ""; }; - A5629AA82876A23100094373 /* ChatService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatService.swift; sourceTree = ""; }; - A5629AB82876CBC000094373 /* ChatListModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListModule.swift; sourceTree = ""; }; - A5629AB92876CBC000094373 /* ChatListPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListPresenter.swift; sourceTree = ""; }; - A5629ABA2876CBC000094373 /* ChatListRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListRouter.swift; sourceTree = ""; }; - A5629ABB2876CBC000094373 /* ChatListInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListInteractor.swift; sourceTree = ""; }; - A5629ABC2876CBC000094373 /* ChatListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListView.swift; sourceTree = ""; }; - A5629ACE2876CC5700094373 /* InviteModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteModule.swift; sourceTree = ""; }; - A5629ACF2876CC5700094373 /* InvitePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitePresenter.swift; sourceTree = ""; }; - A5629AD02876CC5700094373 /* InviteRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteRouter.swift; sourceTree = ""; }; - A5629AD12876CC5700094373 /* InviteInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteInteractor.swift; sourceTree = ""; }; - A5629AD22876CC5700094373 /* InviteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteView.swift; sourceTree = ""; }; - A5629AD92876CC6E00094373 /* InviteListModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteListModule.swift; sourceTree = ""; }; - A5629ADA2876CC6E00094373 /* InviteListPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteListPresenter.swift; sourceTree = ""; }; - A5629ADB2876CC6E00094373 /* InviteListRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteListRouter.swift; sourceTree = ""; }; - A5629ADC2876CC6E00094373 /* InviteListInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteListInteractor.swift; sourceTree = ""; }; - A5629ADD2876CC6E00094373 /* InviteListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteListView.swift; sourceTree = ""; }; - A5629AE32876E6D200094373 /* ThreadViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadViewModel.swift; sourceTree = ""; }; - A5629AE728772A0100094373 /* InviteViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteViewModel.swift; sourceTree = ""; }; A5629AEF2877F73000094373 /* DefaultSocketFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultSocketFactory.swift; sourceTree = ""; }; A56AC8F12AD88A5A001C8FAA /* Sequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sequence.swift; sourceTree = ""; }; - A573C53629EC34A600E3CBFD /* SyncDerivationServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncDerivationServiceTests.swift; sourceTree = ""; }; A57879702A4EDC8100F8D10B /* TextFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldView.swift; sourceTree = ""; }; - A578FA312873036400AA7720 /* InputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputView.swift; sourceTree = ""; }; - A578FA34287304A300AA7720 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; - A578FA362873D8EE00AA7720 /* UIColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = ""; }; - A578FA382873FCE000AA7720 /* ChatScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatScrollView.swift; sourceTree = ""; }; - A578FA3C2874002400AA7720 /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; A57E71A5291CF76400325797 /* ETHSigner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ETHSigner.swift; sourceTree = ""; }; A57E71A7291CF8A500325797 /* SOLSigner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SOLSigner.swift; sourceTree = ""; }; A58A1ECB29BF458600A82A20 /* ENSResolverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ENSResolverTests.swift; sourceTree = ""; }; - A58E7CE828729F550082D443 /* Showcase.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Showcase.app; sourceTree = BUILT_PRODUCTS_DIR; }; - A58E7CEA28729F550082D443 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - A58E7CEC28729F550082D443 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - A58E7CF328729F550082D443 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - A58E7CF628729F550082D443 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - A58E7CF828729F550082D443 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - A58E7CFF2872A1050082D443 /* SceneViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneViewController.swift; sourceTree = ""; }; - A58E7D022872A1630082D443 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; - A58E7D072872A45B0082D443 /* MainModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainModule.swift; sourceTree = ""; }; - A58E7D082872A45B0082D443 /* MainPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainPresenter.swift; sourceTree = ""; }; - A58E7D092872A45B0082D443 /* MainRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainRouter.swift; sourceTree = ""; }; - A58E7D122872A4A80082D443 /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; }; - A58E7D142872A5410082D443 /* UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = ""; }; - A58E7D172872A57B0082D443 /* Configurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Configurator.swift; sourceTree = ""; }; - A58E7D182872A57B0082D443 /* ThirdPartyConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThirdPartyConfigurator.swift; sourceTree = ""; }; - A58E7D192872A57B0082D443 /* ApplicationConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationConfigurator.swift; sourceTree = ""; }; - A58E7D1B2872A57B0082D443 /* MigrationConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationConfigurator.swift; sourceTree = ""; }; - A58E7D1C2872A57B0082D443 /* AppearanceConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppearanceConfigurator.swift; sourceTree = ""; }; - A58E7D232872AB130082D443 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; - A58E7D342872D55F0082D443 /* ChatModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatModule.swift; sourceTree = ""; }; - A58E7D352872D55F0082D443 /* ChatRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatRouter.swift; sourceTree = ""; }; - A58E7D362872D55F0082D443 /* ChatInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatInteractor.swift; sourceTree = ""; }; - A58E7D372872D55F0082D443 /* ChatPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatPresenter.swift; sourceTree = ""; }; - A58E7D382872D55F0082D443 /* ChatView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatView.swift; sourceTree = ""; }; - A58E7D3E2872E99A0082D443 /* TabPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabPage.swift; sourceTree = ""; }; - A58E7D422872EE320082D443 /* MessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageView.swift; sourceTree = ""; }; - A58E7D442872EE570082D443 /* ContentMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentMessageView.swift; sourceTree = ""; }; - A58E7D472872EF610082D443 /* MessageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageViewModel.swift; sourceTree = ""; }; - A58EC615299D5C6400F3452A /* PlainButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlainButton.swift; sourceTree = ""; }; A59CF4F5292F83D50031A42F /* DefaultSignerFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultSignerFactory.swift; sourceTree = ""; }; A5A0843B29D2F60A000B9B17 /* DefaultCryptoProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultCryptoProvider.swift; sourceTree = ""; }; A5A4FC722840C12C00BBEC1E /* UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -551,20 +426,7 @@ A5B4F7C12ABB20AE0099AF7C /* SubscriptionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubscriptionView.swift; sourceTree = ""; }; A5B4F7C72ABB21190099AF7C /* CacheAsyncImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CacheAsyncImage.swift; sourceTree = ""; }; A5BB7FAC28B6AA7D00707FC6 /* QRCodeGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeGenerator.swift; sourceTree = ""; }; - A5C20206287D9DEE007E3188 /* WelcomeModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeModule.swift; sourceTree = ""; }; - A5C20207287D9DEE007E3188 /* WelcomePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomePresenter.swift; sourceTree = ""; }; - A5C20208287D9DEE007E3188 /* WelcomeRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeRouter.swift; sourceTree = ""; }; - A5C2020A287D9DEE007E3188 /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = ""; }; - A5C20214287E1FD8007E3188 /* ImportModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportModule.swift; sourceTree = ""; }; - A5C20215287E1FD8007E3188 /* ImportPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportPresenter.swift; sourceTree = ""; }; - A5C20216287E1FD8007E3188 /* ImportRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportRouter.swift; sourceTree = ""; }; - A5C20217287E1FD8007E3188 /* ImportInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportInteractor.swift; sourceTree = ""; }; - A5C20218287E1FD8007E3188 /* ImportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportView.swift; sourceTree = ""; }; - A5C20220287EA5B8007E3188 /* TextFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldView.swift; sourceTree = ""; }; - A5C20222287EA7E2007E3188 /* BrandButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrandButton.swift; sourceTree = ""; }; A5C20228287EB34C007E3188 /* AccountStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountStorage.swift; sourceTree = ""; }; - A5C2022A287EB89A007E3188 /* WelcomeInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeInteractor.swift; sourceTree = ""; }; - A5C5153229BB7A6A004210BA /* InviteType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteType.swift; sourceTree = ""; }; A5D610C72AB31EE800C20083 /* SegmentedPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentedPicker.swift; sourceTree = ""; }; A5D610C92AB3249100C20083 /* ListingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListingViewModel.swift; sourceTree = ""; }; A5D610CD2AB3594100C20083 /* ListingsAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListingsAPI.swift; sourceTree = ""; }; @@ -574,7 +436,6 @@ A5E03DED286464DB00888481 /* IntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; A5E03DF9286465C700888481 /* SignClientTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignClientTests.swift; sourceTree = ""; }; A5E03DFC286465D100888481 /* Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stubs.swift; sourceTree = ""; }; - A5E03E02286466F400888481 /* ChatTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatTests.swift; sourceTree = ""; }; A5E03E1028646F8000888481 /* KeychainStorageMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainStorageMock.swift; sourceTree = ""; }; A5E22D192840C62A00E36487 /* Engine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Engine.swift; sourceTree = ""; }; A5E22D1B2840C85D00E36487 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; @@ -583,13 +444,11 @@ A5E22D212840C8D300E36487 /* WalletEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletEngine.swift; sourceTree = ""; }; A5E22D232840C8DB00E36487 /* SafariEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariEngine.swift; sourceTree = ""; }; A5E22D2B2840EAC300E36487 /* XCUIElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCUIElement.swift; sourceTree = ""; }; - A5E776B929F4362D00172091 /* AlertError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertError.swift; sourceTree = ""; }; A5F48A0528E43D3F0034CBFB /* Configuration.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Configuration.xcconfig; path = ../Configuration.xcconfig; sourceTree = ""; }; A74D32B92A1E25AD00CB8536 /* QueryParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryParameters.swift; sourceTree = ""; }; C55D347A295DD7140004314A /* AuthRequestModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestModule.swift; sourceTree = ""; }; C55D347B295DD7140004314A /* AuthRequestPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestPresenter.swift; sourceTree = ""; }; C55D347C295DD7140004314A /* AuthRequestRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestRouter.swift; sourceTree = ""; }; - C55D347D295DD7140004314A /* AuthRequestInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestInteractor.swift; sourceTree = ""; }; C55D347E295DD7140004314A /* AuthRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequestView.swift; sourceTree = ""; }; C55D3484295DD8CA0004314A /* PasteUriModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteUriModule.swift; sourceTree = ""; }; C55D3485295DD8CA0004314A /* PasteUriPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasteUriPresenter.swift; sourceTree = ""; }; @@ -647,12 +506,7 @@ C5B2F6F42970511B000DBA0E /* SessionRequestInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRequestInteractor.swift; sourceTree = ""; }; C5B2F6F52970511B000DBA0E /* SessionRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRequestView.swift; sourceTree = ""; }; C5B4C4C32AF11C8B00B4274A /* SignView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignView.swift; sourceTree = ""; }; - C5B4C4CE2AF12F1600B4274A /* AuthView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthView.swift; sourceTree = ""; }; C5BE01D02AF661D70064FC88 /* NewPairingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPairingView.swift; sourceTree = ""; }; - C5BE01D62AF691CD0064FC88 /* AuthModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthModule.swift; sourceTree = ""; }; - C5BE01D82AF691FE0064FC88 /* AuthPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthPresenter.swift; sourceTree = ""; }; - C5BE01DA2AF692060064FC88 /* AuthRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRouter.swift; sourceTree = ""; }; - C5BE01DC2AF692100064FC88 /* AuthInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthInteractor.swift; sourceTree = ""; }; C5BE01E12AF693080064FC88 /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = ""; }; C5BE01ED2AF6C9DF0064FC88 /* SignPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignPresenter.swift; sourceTree = ""; }; C5BE01EE2AF6C9DF0064FC88 /* SignModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignModule.swift; sourceTree = ""; }; @@ -662,12 +516,6 @@ C5BE01F42AF6CA2B0064FC88 /* NewPairingPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPairingPresenter.swift; sourceTree = ""; }; C5BE01F52AF6CA2B0064FC88 /* NewPairingModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPairingModule.swift; sourceTree = ""; }; C5BE01F62AF6CA2B0064FC88 /* NewPairingInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewPairingInteractor.swift; sourceTree = ""; }; - C5BE02072AF777AD0064FC88 /* MainModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainModule.swift; sourceTree = ""; }; - C5BE02082AF777AD0064FC88 /* MainRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainRouter.swift; sourceTree = ""; }; - C5BE02092AF777AD0064FC88 /* MainInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainInteractor.swift; sourceTree = ""; }; - C5BE020A2AF777AD0064FC88 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; - C5BE020B2AF777AD0064FC88 /* MainPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainPresenter.swift; sourceTree = ""; }; - C5BE020D2AF777AD0064FC88 /* TabPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabPage.swift; sourceTree = ""; }; C5BE02162AF79B950064FC88 /* SessionAccountRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionAccountRouter.swift; sourceTree = ""; }; C5BE02172AF79B950064FC88 /* SessionAccountPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionAccountPresenter.swift; sourceTree = ""; }; C5BE02182AF79B950064FC88 /* SessionAccountInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionAccountInteractor.swift; sourceTree = ""; }; @@ -675,7 +523,6 @@ C5BE021A2AF79B960064FC88 /* SessionAccountModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionAccountModule.swift; sourceTree = ""; }; C5F32A2B2954814200A6476E /* ConnectionDetailsModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDetailsModule.swift; sourceTree = ""; }; C5F32A2D2954814A00A6476E /* ConnectionDetailsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDetailsRouter.swift; sourceTree = ""; }; - C5F32A2F2954816100A6476E /* ConnectionDetailsInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionDetailsInteractor.swift; sourceTree = ""; }; 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 = ""; }; @@ -701,6 +548,20 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 8445118C2C8B689D00A6A86C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 844511BC2C8B6BE600A6A86C /* Web3ContractABI in Frameworks */, + 844511C42C8B6C0D00A6A86C /* ReownAppKit in Frameworks */, + 844511BA2C8B6BC800A6A86C /* Atlantis in Frameworks */, + 844511B62C8B69F200A6A86C /* Starscream in Frameworks */, + 844511BE2C8B6BF000A6A86C /* ReownAppKitUI in Frameworks */, + 844511C22C8B6C0600A6A86C /* SwiftMessages in Frameworks */, + 844511C02C8B6BF800A6A86C /* Web3 in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 844749F029B9E5B9005F520B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -715,15 +576,13 @@ buildActionMask = 2147483647; files = ( 8448F1D427E4726F0000B866 /* WalletConnect in Frameworks */, - C579FEB62AFA86CD008855EB /* Web3Modal in Frameworks */, - C5BE01DF2AF692D80064FC88 /* WalletConnectRouter in Frameworks */, + 8421447B2C80A2B8004FF494 /* ReownAppKit in Frameworks */, A5B6C0F12A6EAB0800927332 /* WalletConnectNotify in Frameworks */, A54195A52934E83F0035AD19 /* Web3 in Frameworks */, - 8487A9442A836C2A0003D5AF /* Sentry in Frameworks */, A5D85228286333E300DAF5C3 /* Starscream in Frameworks */, + 8486EDD32B4F2EA6008E53C3 /* SwiftMessages in Frameworks */, 84943C7B2A9BA206007EBAC2 /* Mixpanel in Frameworks */, A573C53929EC365000E3CBFD /* HDWalletKit in Frameworks */, - A5BB7FA328B6A50400707FC6 /* WalletConnectAuth in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -732,25 +591,11 @@ buildActionMask = 2147483647; files = ( A5A650CA2B062A1400F9AD4B /* Mixpanel in Frameworks */, + 842144812C818684004FF494 /* ReownWalletKit in Frameworks */, A5B6C0F72A6EAB3200927332 /* WalletConnectNotify in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - A58E7CE528729F550082D443 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - A58EC618299D665A00F3452A /* Web3Inbox in Frameworks */, - A5629AEA2877F2D600094373 /* WalletConnectChat in Frameworks */, - CF25F2892A432476009C7E49 /* WalletConnectModal in Frameworks */, - A561C80029DF32CE00DF540D /* HDWalletKit in Frameworks */, - A59FAEC928B7B93A002BB66F /* Web3 in Frameworks */, - A5629AF22877F75100094373 /* Starscream in Frameworks */, - A59F877628B5462900A9CD80 /* WalletConnectAuth in Frameworks */, - A58EC611299D57B800F3452A /* AsyncButton in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; A5A4FC6F2840C12C00BBEC1E /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -763,15 +608,11 @@ buildActionMask = 2147483647; files = ( A5E03DFF2864662500888481 /* WalletConnect in Frameworks */, - A561C80529DFCD4500DF540D /* WalletConnectSync in Frameworks */, A5E03DF52864651200888481 /* Starscream in Frameworks */, - A50DF19D2A25084A0036EA6C /* WalletConnectHistory in Frameworks */, A5C8BE85292FE20B006CC85C /* Web3 in Frameworks */, - 84DDB4ED28ABB663003D66ED /* WalletConnectAuth in Frameworks */, - C5DD5BE1294E09E3008FD3A4 /* Web3Wallet in Frameworks */, A5B6C0F32A6EAB1700927332 /* WalletConnectNotify in Frameworks */, + 842144832C818928004FF494 /* ReownWalletKit in Frameworks */, A573C53B29EC365800E3CBFD /* HDWalletKit in Frameworks */, - A5E03E01286466EA00888481 /* WalletConnectChat in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -781,17 +622,15 @@ files = ( A573C53D29EC366500E3CBFD /* HDWalletKit in Frameworks */, A59D25EE2AB3672700D7EA3A /* AsyncButton in Frameworks */, - C56EE27D293F56F8004840D1 /* WalletConnectChat in Frameworks */, C5133A78294125CC00A8314C /* Web3 in Frameworks */, C5B2F7052970573D000DBA0E /* SolanaSwift in Frameworks */, - 8487A9462A836C3F0003D5AF /* Sentry in Frameworks */, - C55D349929630D440004314A /* Web3Wallet in Frameworks */, - A5F1526F2ACDC46B00D745A6 /* Web3ModalUI in Frameworks */, C56EE255293F569A004840D1 /* Starscream in Frameworks */, + 84AEC2542B4D43CD00E27A5B /* SwiftMessages in Frameworks */, A5B6C0F52A6EAB2800927332 /* WalletConnectNotify in Frameworks */, - C56EE27B293F56F8004840D1 /* WalletConnectAuth in Frameworks */, - C54C24902AEB1B5600DA4BF6 /* WalletConnectRouter in Frameworks */, 84943C7D2A9BA328007EBAC2 /* Mixpanel in Frameworks */, + 8421447F2C81863A004FF494 /* ReownWalletKit in Frameworks */, + 8421447D2C80A544004FF494 /* ReownAppKitUI in Frameworks */, + 84CA52172C88965C0069BB33 /* ReownRouter in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -819,11 +658,11 @@ 84CE641D27981DED00142511 /* DApp */, A5A4FC732840C12C00BBEC1E /* UITests */, A5E03DEE286464DB00888481 /* IntegrationTests */, - A58E7CE928729F550082D443 /* Showcase */, C56EE21C293F55ED004840D1 /* WalletApp */, 84E6B84829787A8000428BAF /* PNDecryptionService */, 844749F429B9E5B9005F520B /* RelayIntegrationTests */, CF1A593129E5873D00AAC16B /* EchoUITests */, + 844511902C8B689D00A6A86C /* AppKitLab */, 764E1D3D26F8D3FC00A1FB15 /* Products */, 764E1D5326F8DAC800A1FB15 /* Frameworks */, 764E1D5626F8DB6000A1FB15 /* WalletConnectSwiftV2 */, @@ -836,11 +675,11 @@ 84CE641C27981DED00142511 /* DApp.app */, A5A4FC722840C12C00BBEC1E /* UITests.xctest */, A5E03DED286464DB00888481 /* IntegrationTests.xctest */, - A58E7CE828729F550082D443 /* Showcase.app */, C56EE21B293F55ED004840D1 /* WalletApp.app */, 84E6B84729787A8000428BAF /* PNDecryptionService.appex */, 844749F329B9E5B9005F520B /* RelayIntegrationTests.xctest */, CF1A593029E5873D00AAC16B /* EchoUITests.xctest */, + 8445118F2C8B689D00A6A86C /* AppKitLab.app */, ); name = Products; sourceTree = ""; @@ -863,6 +702,33 @@ path = Helpers; sourceTree = ""; }; + 840507E12C8BAC4100148A9B /* Preview Content */ = { + isa = PBXGroup; + children = ( + 840507E22C8BAC7C00148A9B /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + 844511902C8B689D00A6A86C /* AppKitLab */ = { + isa = PBXGroup; + children = ( + 844511C92C8BA69D00A6A86C /* AppKitLab.entitlements */, + 844511C82C8BA12200A6A86C /* Info.plist */, + 844511A82C8B695500A6A86C /* AlertPresenter.swift */, + 844511A92C8B695500A6A86C /* Assets.xcassets */, + 844511A12C8B695400A6A86C /* ComponentLibraryView.swift */, + 840507E12C8BAC4100148A9B /* Preview Content */, + 844511A62C8B695500A6A86C /* ContentView.swift */, + 844511A52C8B695400A6A86C /* DefaultCryptoProvider.swift */, + 844511A22C8B695400A6A86C /* Example.entitlements */, + 844511A02C8B695300A6A86C /* InputConfig.swift */, + 844511A42C8B695400A6A86C /* WCSocketFactory.swift */, + 844511912C8B689D00A6A86C /* AppKitLabApp.swift */, + ); + path = AppKitLab; + sourceTree = ""; + }; 844749F429B9E5B9005F520B /* RelayIntegrationTests */ = { isa = PBXGroup; children = ( @@ -871,6 +737,17 @@ path = RelayIntegrationTests; sourceTree = ""; }; + 846E35A02C00655500E63DF4 /* Configuration */ = { + isa = PBXGroup; + children = ( + 846E359E2C00654F00E63DF4 /* ConfigModule.swift */, + 846E35A52C0065C100E63DF4 /* ConfigView.swift */, + 846E35A32C0065B600E63DF4 /* ConfigPresenter.swift */, + 846E35A12C0065AD00E63DF4 /* ConfigRouter.swift */, + ); + path = Configuration; + sourceTree = ""; + }; 847BD1DB2989493F00076C90 /* Main */ = { isa = PBXGroup; children = ( @@ -972,11 +849,14 @@ 84CE641D27981DED00142511 /* DApp */ = { isa = PBXGroup; children = ( + 84F1CD392BBD414000D2A6E2 /* DAppRelease.entitlements */, + 84D72FC62B4692770057EAF3 /* DApp.entitlements */, C5BE01E02AF692F80064FC88 /* ApplicationLayer */, C5BE02202AF7DDE70064FC88 /* Modules */, A5BB7FAB28B6AA7100707FC6 /* Common */, 84CE641E27981DED00142511 /* AppDelegate.swift */, 84CE642027981DED00142511 /* SceneDelegate.swift */, + 846E35A72C006C5600E63DF4 /* Constants.swift */, 84CE642727981DF000142511 /* Assets.xcassets */, 84CE642927981DF000142511 /* LaunchScreen.storyboard */, 84CE642C27981DF000142511 /* Info.plist */, @@ -984,20 +864,11 @@ path = DApp; sourceTree = ""; }; - 84CEC64728D8A98900D081A8 /* Pairing */ = { - isa = PBXGroup; - children = ( - 84CEC64528D89D6B00D081A8 /* PairingTests.swift */, - ); - path = Pairing; - sourceTree = ""; - }; 84D2A66728A4F5260088AE09 /* Auth */ = { isa = PBXGroup; children = ( A58A1ECA29BF457800A82A20 /* ENS */, A54195992934BFDD0035AD19 /* Signer */, - 84D2A66528A4F51E0088AE09 /* AuthTests.swift */, ); path = Auth; sourceTree = ""; @@ -1025,14 +896,6 @@ path = NotifySettings; sourceTree = ""; }; - A50F3944288005A700064555 /* Types */ = { - isa = PBXGroup; - children = ( - A50F3945288005B200064555 /* Types.swift */, - ); - path = Types; - sourceTree = ""; - }; A51811992A52E82100A52B15 /* Settings */ = { isa = PBXGroup; children = ( @@ -1045,14 +908,6 @@ path = Settings; sourceTree = ""; }; - A5321C292A25035A006CADC3 /* History */ = { - isa = PBXGroup; - children = ( - A5321C2A2A250367006CADC3 /* HistoryTests.swift */, - ); - path = History; - sourceTree = ""; - }; A54195992934BFDD0035AD19 /* Signer */ = { isa = PBXGroup; children = ( @@ -1065,87 +920,6 @@ path = Signer; sourceTree = ""; }; - A561C80129DFCCD300DF540D /* Sync */ = { - isa = PBXGroup; - children = ( - A561C80229DFCCDC00DF540D /* SyncTests.swift */, - A573C53629EC34A600E3CBFD /* SyncDerivationServiceTests.swift */, - ); - path = Sync; - sourceTree = ""; - }; - A5629AA42876A19D00094373 /* DomainLayer */ = { - isa = PBXGroup; - children = ( - A5629AEB2877F69C00094373 /* Chat */, - ); - path = DomainLayer; - sourceTree = ""; - }; - A5629AB72876CBA700094373 /* ChatList */ = { - isa = PBXGroup; - children = ( - A5629AE5287729EF00094373 /* Models */, - A5629AB82876CBC000094373 /* ChatListModule.swift */, - A5629AB92876CBC000094373 /* ChatListPresenter.swift */, - A5629ABA2876CBC000094373 /* ChatListRouter.swift */, - A5629ABB2876CBC000094373 /* ChatListInteractor.swift */, - A5629ABC2876CBC000094373 /* ChatListView.swift */, - ); - path = ChatList; - sourceTree = ""; - }; - A5629ACD2876CC4A00094373 /* Invite */ = { - isa = PBXGroup; - children = ( - A5629ACE2876CC5700094373 /* InviteModule.swift */, - A5629ACF2876CC5700094373 /* InvitePresenter.swift */, - A5629AD02876CC5700094373 /* InviteRouter.swift */, - A5629AD12876CC5700094373 /* InviteInteractor.swift */, - A5629AD22876CC5700094373 /* InviteView.swift */, - ); - path = Invite; - sourceTree = ""; - }; - A5629AD82876CC5B00094373 /* InviteList */ = { - isa = PBXGroup; - children = ( - A5629AE6287729F800094373 /* Models */, - A5629AD92876CC6E00094373 /* InviteListModule.swift */, - A5629ADA2876CC6E00094373 /* InviteListPresenter.swift */, - A5629ADB2876CC6E00094373 /* InviteListRouter.swift */, - A5629ADC2876CC6E00094373 /* InviteListInteractor.swift */, - A5629ADD2876CC6E00094373 /* InviteListView.swift */, - ); - path = InviteList; - sourceTree = ""; - }; - A5629AE5287729EF00094373 /* Models */ = { - isa = PBXGroup; - children = ( - A5629AE32876E6D200094373 /* ThreadViewModel.swift */, - A5E776B929F4362D00172091 /* AlertError.swift */, - ); - path = Models; - sourceTree = ""; - }; - A5629AE6287729F800094373 /* Models */ = { - isa = PBXGroup; - children = ( - A5629AE728772A0100094373 /* InviteViewModel.swift */, - A5C5153229BB7A6A004210BA /* InviteType.swift */, - ); - path = Models; - sourceTree = ""; - }; - A5629AEB2877F69C00094373 /* Chat */ = { - isa = PBXGroup; - children = ( - A5629AA82876A23100094373 /* ChatService.swift */, - ); - path = Chat; - sourceTree = ""; - }; A56AC8F02AD88A4B001C8FAA /* Foundation */ = { isa = PBXGroup; children = ( @@ -1154,16 +928,6 @@ path = Foundation; sourceTree = ""; }; - A574B3592964570000C2BB91 /* Web3Inbox */ = { - isa = PBXGroup; - children = ( - A518A98529683FB60035247E /* Web3InboxModule.swift */, - A518A98629683FB60035247E /* Web3InboxRouter.swift */, - A518A98429683FB60035247E /* Web3InboxViewController.swift */, - ); - path = Web3Inbox; - sourceTree = ""; - }; A578796F2A4EDC6B00F8D10B /* Views */ = { isa = PBXGroup; children = ( @@ -1172,32 +936,6 @@ path = Views; sourceTree = ""; }; - A578FA332873049400AA7720 /* Style */ = { - isa = PBXGroup; - children = ( - A578FA34287304A300AA7720 /* Color.swift */, - ); - path = Style; - sourceTree = ""; - }; - A578FA3A2874001100AA7720 /* UIKit */ = { - isa = PBXGroup; - children = ( - A58E7D142872A5410082D443 /* UIViewController.swift */, - A58E7D022872A1630082D443 /* String.swift */, - A578FA362873D8EE00AA7720 /* UIColor.swift */, - ); - path = UIKit; - sourceTree = ""; - }; - A578FA3B2874001900AA7720 /* SwiftUI */ = { - isa = PBXGroup; - children = ( - A578FA3C2874002400AA7720 /* View.swift */, - ); - path = SwiftUI; - sourceTree = ""; - }; A57E71A4291CF73300325797 /* Signer */ = { isa = PBXGroup; children = ( @@ -1216,164 +954,6 @@ path = ENS; sourceTree = ""; }; - A58E7CE928729F550082D443 /* Showcase */ = { - isa = PBXGroup; - children = ( - A58E7D052872A4330082D443 /* Classes */, - A58E7CFD2872A0F80082D443 /* Common */, - A58E7CFC28729F9E0082D443 /* Other */, - ); - path = Showcase; - sourceTree = ""; - }; - A58E7CFC28729F9E0082D443 /* Other */ = { - isa = PBXGroup; - children = ( - A58E7CF328729F550082D443 /* Assets.xcassets */, - A58E7CF528729F550082D443 /* LaunchScreen.storyboard */, - A58E7CF828729F550082D443 /* Info.plist */, - ); - path = Other; - sourceTree = ""; - }; - A58E7CFD2872A0F80082D443 /* Common */ = { - isa = PBXGroup; - children = ( - A51AC0DE28E4379F001BACF9 /* InputConfig.swift */, - A50F3944288005A700064555 /* Types */, - A5C2021F287EA5AF007E3188 /* Components */, - A578FA332873049400AA7720 /* Style */, - A58E7D012872A1430082D443 /* Extensions */, - A58E7CFE2872A1050082D443 /* VIPER */, - ); - path = Common; - sourceTree = ""; - }; - A58E7CFE2872A1050082D443 /* VIPER */ = { - isa = PBXGroup; - children = ( - A58E7CFF2872A1050082D443 /* SceneViewController.swift */, - ); - path = VIPER; - sourceTree = ""; - }; - A58E7D012872A1430082D443 /* Extensions */ = { - isa = PBXGroup; - children = ( - A578FA3B2874001900AA7720 /* SwiftUI */, - A578FA3A2874001100AA7720 /* UIKit */, - ); - path = Extensions; - sourceTree = ""; - }; - A58E7D052872A4330082D443 /* Classes */ = { - isa = PBXGroup; - children = ( - A5629AA42876A19D00094373 /* DomainLayer */, - A58E7D112872A49E0082D443 /* ApplicationLayer */, - A58E7D062872A4390082D443 /* PresentationLayer */, - ); - path = Classes; - sourceTree = ""; - }; - A58E7D062872A4390082D443 /* PresentationLayer */ = { - isa = PBXGroup; - children = ( - A574B3592964570000C2BB91 /* Web3Inbox */, - A59F876828B53E6400A9CD80 /* Chat */, - ); - path = PresentationLayer; - sourceTree = ""; - }; - A58E7D112872A49E0082D443 /* ApplicationLayer */ = { - isa = PBXGroup; - children = ( - A58E7D162872A57B0082D443 /* Configurator */, - A58E7D122872A4A80082D443 /* Application.swift */, - A58E7CEA28729F550082D443 /* AppDelegate.swift */, - A58E7CEC28729F550082D443 /* SceneDelegate.swift */, - ); - path = ApplicationLayer; - sourceTree = ""; - }; - A58E7D162872A57B0082D443 /* Configurator */ = { - isa = PBXGroup; - children = ( - A58E7D172872A57B0082D443 /* Configurator.swift */, - A58E7D182872A57B0082D443 /* ThirdPartyConfigurator.swift */, - A58E7D192872A57B0082D443 /* ApplicationConfigurator.swift */, - A58E7D1B2872A57B0082D443 /* MigrationConfigurator.swift */, - A58E7D1C2872A57B0082D443 /* AppearanceConfigurator.swift */, - ); - path = Configurator; - sourceTree = ""; - }; - A58E7D282872D52A0082D443 /* Main */ = { - isa = PBXGroup; - children = ( - A58E7D402872E9A10082D443 /* Model */, - A58E7D072872A45B0082D443 /* MainModule.swift */, - A58E7D082872A45B0082D443 /* MainPresenter.swift */, - A58E7D092872A45B0082D443 /* MainRouter.swift */, - A58E7D232872AB130082D443 /* MainViewController.swift */, - ); - path = Main; - sourceTree = ""; - }; - A58E7D332872D55F0082D443 /* Chat */ = { - isa = PBXGroup; - children = ( - A58E7D462872EF5B0082D443 /* Models */, - A58E7D412872EE270082D443 /* Views */, - A58E7D342872D55F0082D443 /* ChatModule.swift */, - A58E7D352872D55F0082D443 /* ChatRouter.swift */, - A58E7D362872D55F0082D443 /* ChatInteractor.swift */, - A58E7D372872D55F0082D443 /* ChatPresenter.swift */, - A58E7D382872D55F0082D443 /* ChatView.swift */, - ); - path = Chat; - sourceTree = ""; - }; - A58E7D402872E9A10082D443 /* Model */ = { - isa = PBXGroup; - children = ( - A58E7D3E2872E99A0082D443 /* TabPage.swift */, - ); - path = Model; - sourceTree = ""; - }; - A58E7D412872EE270082D443 /* Views */ = { - isa = PBXGroup; - children = ( - A58E7D422872EE320082D443 /* MessageView.swift */, - A58E7D442872EE570082D443 /* ContentMessageView.swift */, - A578FA382873FCE000AA7720 /* ChatScrollView.swift */, - ); - path = Views; - sourceTree = ""; - }; - A58E7D462872EF5B0082D443 /* Models */ = { - isa = PBXGroup; - children = ( - A58E7D472872EF610082D443 /* MessageViewModel.swift */, - ); - path = Models; - sourceTree = ""; - }; - A59F876828B53E6400A9CD80 /* Chat */ = { - isa = PBXGroup; - children = ( - A5C20213287E1FC8007E3188 /* Import */, - A5C20205287D9DB9007E3188 /* Welcome */, - A5629AD82876CC5B00094373 /* InviteList */, - A5629ACD2876CC4A00094373 /* Invite */, - A5629AB72876CBA700094373 /* ChatList */, - A58E7D332872D55F0082D443 /* Chat */, - A58E7D282872D52A0082D443 /* Main */, - ); - path = Chat; - sourceTree = ""; - }; A5A4FC732840C12C00BBEC1E /* UITests */ = { isa = PBXGroup; children = ( @@ -1404,6 +984,8 @@ 84CB43D429B9FC88004DDA31 /* Tests */, A5629AEF2877F73000094373 /* DefaultSocketFactory.swift */, A59CF4F5292F83D50031A42F /* DefaultSignerFactory.swift */, + A50B6A372B06697B00162B01 /* ProfilingService.swift */, + 84AEC2502B4D42C100E27A5B /* AlertPresenter.swift */, A5A0843B29D2F60A000B9B17 /* DefaultCryptoProvider.swift */, A51606F72A2F47BD00CACB92 /* DefaultBIP44Provider.swift */, A5417BBD299BFC3E00B469F3 /* ImportAccount.swift */, @@ -1416,47 +998,12 @@ A5BB7FAB28B6AA7100707FC6 /* Common */ = { isa = PBXGroup; children = ( - A51AC0D828E436A3001BACF9 /* InputConfig.swift */, A5BB7FAC28B6AA7D00707FC6 /* QRCodeGenerator.swift */, + 84D093EA2B4EA6CB005B1925 /* ActivityIndicatorManager.swift */, ); path = Common; sourceTree = ""; }; - A5C20205287D9DB9007E3188 /* Welcome */ = { - isa = PBXGroup; - children = ( - A5C20206287D9DEE007E3188 /* WelcomeModule.swift */, - A5C20207287D9DEE007E3188 /* WelcomePresenter.swift */, - A5C2022A287EB89A007E3188 /* WelcomeInteractor.swift */, - A5C20208287D9DEE007E3188 /* WelcomeRouter.swift */, - A5C2020A287D9DEE007E3188 /* WelcomeView.swift */, - ); - path = Welcome; - sourceTree = ""; - }; - A5C20213287E1FC8007E3188 /* Import */ = { - isa = PBXGroup; - children = ( - A5C20214287E1FD8007E3188 /* ImportModule.swift */, - A5C20215287E1FD8007E3188 /* ImportPresenter.swift */, - A5C20216287E1FD8007E3188 /* ImportRouter.swift */, - A5C20217287E1FD8007E3188 /* ImportInteractor.swift */, - A5C20218287E1FD8007E3188 /* ImportView.swift */, - ); - path = Import; - sourceTree = ""; - }; - A5C2021F287EA5AF007E3188 /* Components */ = { - isa = PBXGroup; - children = ( - A578FA312873036400AA7720 /* InputView.swift */, - A5C20220287EA5B8007E3188 /* TextFieldView.swift */, - A5C20222287EA7E2007E3188 /* BrandButton.swift */, - A58EC615299D5C6400F3452A /* PlainButton.swift */, - ); - path = Components; - sourceTree = ""; - }; A5D610CB2AB358ED00C20083 /* BusinessLayer */ = { isa = PBXGroup; children = ( @@ -1478,28 +1025,15 @@ A5E03DEE286464DB00888481 /* IntegrationTests */ = { isa = PBXGroup; children = ( + 84D2A66728A4F5260088AE09 /* Auth */, 847F07FE2A25DBC700B2A5A4 /* XPlatform */, - A5321C292A25035A006CADC3 /* History */, - A561C80129DFCCD300DF540D /* Sync */, 849D7A91292E2115006A2BD4 /* Push */, - 84CEC64728D8A98900D081A8 /* Pairing */, A5E03E0A28646A8A00888481 /* Stubs */, A5E03E0928646A8100888481 /* Sign */, - A5E03E0828646A7B00888481 /* Chat */, - 84D2A66728A4F5260088AE09 /* Auth */, ); path = IntegrationTests; sourceTree = ""; }; - A5E03E0828646A7B00888481 /* Chat */ = { - isa = PBXGroup; - children = ( - A5E03E02286466F400888481 /* ChatTests.swift */, - 7694A5252874296A0001257E /* RegistryTests.swift */, - ); - path = Chat; - sourceTree = ""; - }; A5E03E0928646A8100888481 /* Sign */ = { isa = PBXGroup; children = ( @@ -1554,7 +1088,6 @@ C55D347A295DD7140004314A /* AuthRequestModule.swift */, C55D347B295DD7140004314A /* AuthRequestPresenter.swift */, C55D347C295DD7140004314A /* AuthRequestRouter.swift */, - C55D347D295DD7140004314A /* AuthRequestInteractor.swift */, C55D347E295DD7140004314A /* AuthRequestView.swift */, ); path = AuthRequest; @@ -1664,6 +1197,7 @@ C56EE2A1293F6B9E004840D1 /* Helpers */, C56EE262293F56D6004840D1 /* Extensions */, C56EE263293F56D6004840D1 /* VIPER */, + 84AEC24E2B4D1EE400E27A5B /* ActivityIndicatorManager.swift */, ); path = Common; sourceTree = ""; @@ -1721,7 +1255,6 @@ C56EE280293F5757004840D1 /* Application.swift */, C56EE27F293F5757004840D1 /* AppDelegate.swift */, C56EE281293F5757004840D1 /* SceneDelegate.swift */, - A50B6A372B06697B00162B01 /* ProfilingService.swift */, 84DB38F22983CDAE00BFEE37 /* PushRegisterer.swift */, A51811972A52E21A00A52B15 /* ConfigurationService.swift */, 8487A9472A83AD680003D5AF /* LoggingService.swift */, @@ -1806,18 +1339,6 @@ path = Sign; sourceTree = ""; }; - C5B4C4CD2AF12F0B00B4274A /* Auth */ = { - isa = PBXGroup; - children = ( - C5BE01D62AF691CD0064FC88 /* AuthModule.swift */, - C5BE01D82AF691FE0064FC88 /* AuthPresenter.swift */, - C5BE01DA2AF692060064FC88 /* AuthRouter.swift */, - C5BE01DC2AF692100064FC88 /* AuthInteractor.swift */, - C5B4C4CE2AF12F1600B4274A /* AuthView.swift */, - ); - path = Auth; - sourceTree = ""; - }; C5BE01E02AF692F80064FC88 /* ApplicationLayer */ = { isa = PBXGroup; children = ( @@ -1838,27 +1359,6 @@ path = NewPairing; sourceTree = ""; }; - C5BE02062AF777AD0064FC88 /* Main */ = { - isa = PBXGroup; - children = ( - C5BE02072AF777AD0064FC88 /* MainModule.swift */, - C5BE020B2AF777AD0064FC88 /* MainPresenter.swift */, - C5BE02092AF777AD0064FC88 /* MainInteractor.swift */, - C5BE02082AF777AD0064FC88 /* MainRouter.swift */, - C5BE020A2AF777AD0064FC88 /* MainViewController.swift */, - C5BE020C2AF777AD0064FC88 /* Model */, - ); - path = Main; - sourceTree = ""; - }; - C5BE020C2AF777AD0064FC88 /* Model */ = { - isa = PBXGroup; - children = ( - C5BE020D2AF777AD0064FC88 /* TabPage.swift */, - ); - path = Model; - sourceTree = ""; - }; C5BE02152AF79B860064FC88 /* SessionAccount */ = { isa = PBXGroup; children = ( @@ -1874,9 +1374,8 @@ C5BE02202AF7DDE70064FC88 /* Modules */ = { isa = PBXGroup; children = ( - C5BE02062AF777AD0064FC88 /* Main */, C5B4C4C52AF12C2900B4274A /* Sign */, - C5B4C4CD2AF12F0B00B4274A /* Auth */, + 846E35A02C00655500E63DF4 /* Configuration */, ); path = Modules; sourceTree = ""; @@ -1886,7 +1385,6 @@ children = ( C5F32A2B2954814200A6476E /* ConnectionDetailsModule.swift */, C5F32A2D2954814A00A6476E /* ConnectionDetailsRouter.swift */, - C5F32A2F2954816100A6476E /* ConnectionDetailsInteractor.swift */, C5F32A312954816C00A6476E /* ConnectionDetailsPresenter.swift */, C5F32A332954817600A6476E /* ConnectionDetailsView.swift */, ); @@ -1966,6 +1464,32 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 8445118E2C8B689D00A6A86C /* AppKitLab */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8445119C2C8B689F00A6A86C /* Build configuration list for PBXNativeTarget "AppKitLab" */; + buildPhases = ( + 8445118B2C8B689D00A6A86C /* Sources */, + 8445118C2C8B689D00A6A86C /* Frameworks */, + 8445118D2C8B689D00A6A86C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AppKitLab; + packageProductDependencies = ( + 844511B52C8B69F200A6A86C /* Starscream */, + 844511B92C8B6BC800A6A86C /* Atlantis */, + 844511BB2C8B6BE600A6A86C /* Web3ContractABI */, + 844511BD2C8B6BF000A6A86C /* ReownAppKitUI */, + 844511BF2C8B6BF800A6A86C /* Web3 */, + 844511C12C8B6C0600A6A86C /* SwiftMessages */, + 844511C32C8B6C0D00A6A86C /* ReownAppKit */, + ); + productName = AppKitLab; + productReference = 8445118F2C8B689D00A6A86C /* AppKitLab.app */; + productType = "com.apple.product-type.application"; + }; 844749F229B9E5B9005F520B /* RelayIntegrationTests */ = { isa = PBXNativeTarget; buildConfigurationList = 844749FB29B9E5B9005F520B /* Build configuration list for PBXNativeTarget "RelayIntegrationTests" */; @@ -2003,14 +1527,12 @@ packageProductDependencies = ( 8448F1D327E4726F0000B866 /* WalletConnect */, A5D85227286333E300DAF5C3 /* Starscream */, - A5BB7FA228B6A50400707FC6 /* WalletConnectAuth */, A54195A42934E83F0035AD19 /* Web3 */, A573C53829EC365000E3CBFD /* HDWalletKit */, - 8487A9432A836C2A0003D5AF /* Sentry */, A5B6C0F02A6EAB0800927332 /* WalletConnectNotify */, 84943C7A2A9BA206007EBAC2 /* Mixpanel */, - C5BE01DE2AF692D80064FC88 /* WalletConnectRouter */, - C579FEB52AFA86CD008855EB /* Web3Modal */, + 8486EDD22B4F2EA6008E53C3 /* SwiftMessages */, + 8421447A2C80A2B8004FF494 /* ReownAppKit */, ); productName = DApp; productReference = 84CE641C27981DED00142511 /* DApp.app */; @@ -2032,38 +1554,12 @@ packageProductDependencies = ( A5B6C0F62A6EAB3200927332 /* WalletConnectNotify */, A5A650C92B062A1400F9AD4B /* Mixpanel */, + 842144802C818684004FF494 /* ReownWalletKit */, ); productName = PNDecryptionService; productReference = 84E6B84729787A8000428BAF /* PNDecryptionService.appex */; productType = "com.apple.product-type.app-extension"; }; - A58E7CE728729F550082D443 /* Showcase */ = { - isa = PBXNativeTarget; - buildConfigurationList = A58E7CFB28729F550082D443 /* Build configuration list for PBXNativeTarget "Showcase" */; - buildPhases = ( - A58E7CE428729F550082D443 /* Sources */, - A58E7CE528729F550082D443 /* Frameworks */, - A58E7CE628729F550082D443 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Showcase; - packageProductDependencies = ( - A5629AE92877F2D600094373 /* WalletConnectChat */, - A5629AF12877F75100094373 /* Starscream */, - A59F877528B5462900A9CD80 /* WalletConnectAuth */, - A59FAEC828B7B93A002BB66F /* Web3 */, - A58EC610299D57B800F3452A /* AsyncButton */, - A58EC617299D665A00F3452A /* Web3Inbox */, - A561C7FF29DF32CE00DF540D /* HDWalletKit */, - CF25F2882A432476009C7E49 /* WalletConnectModal */, - ); - productName = Showcase; - productReference = A58E7CE828729F550082D443 /* Showcase.app */; - productType = "com.apple.product-type.application"; - }; A5A4FC712840C12C00BBEC1E /* UITests */ = { isa = PBXNativeTarget; buildConfigurationList = A5A4FC7A2840C12C00BBEC1E /* Build configuration list for PBXNativeTarget "UITests" */; @@ -2098,14 +1594,10 @@ packageProductDependencies = ( A5E03DF42864651200888481 /* Starscream */, A5E03DFE2864662500888481 /* WalletConnect */, - A5E03E00286466EA00888481 /* WalletConnectChat */, - 84DDB4EC28ABB663003D66ED /* WalletConnectAuth */, A5C8BE84292FE20B006CC85C /* Web3 */, - C5DD5BE0294E09E3008FD3A4 /* Web3Wallet */, - A561C80429DFCD4500DF540D /* WalletConnectSync */, A573C53A29EC365800E3CBFD /* HDWalletKit */, - A50DF19C2A25084A0036EA6C /* WalletConnectHistory */, A5B6C0F22A6EAB1700927332 /* WalletConnectNotify */, + 842144822C818928004FF494 /* ReownWalletKit */, ); productName = IntegrationTests; productReference = A5E03DED286464DB00888481 /* IntegrationTests.xctest */; @@ -2128,18 +1620,16 @@ name = WalletApp; packageProductDependencies = ( C56EE254293F569A004840D1 /* Starscream */, - C56EE27A293F56F8004840D1 /* WalletConnectAuth */, - C56EE27C293F56F8004840D1 /* WalletConnectChat */, C5133A77294125CC00A8314C /* Web3 */, - C55D349829630D440004314A /* Web3Wallet */, C5B2F7042970573D000DBA0E /* SolanaSwift */, A573C53C29EC366500E3CBFD /* HDWalletKit */, - 8487A9452A836C3F0003D5AF /* Sentry */, A5B6C0F42A6EAB2800927332 /* WalletConnectNotify */, 84943C7C2A9BA328007EBAC2 /* Mixpanel */, A59D25ED2AB3672700D7EA3A /* AsyncButton */, - A5F1526E2ACDC46B00D745A6 /* Web3ModalUI */, - C54C248F2AEB1B5600DA4BF6 /* WalletConnectRouter */, + 84AEC2532B4D43CD00E27A5B /* SwiftMessages */, + 8421447C2C80A544004FF494 /* ReownAppKitUI */, + 8421447E2C81863A004FF494 /* ReownWalletKit */, + 84CA52162C88965C0069BB33 /* ReownRouter */, ); productName = ChatWallet; productReference = C56EE21B293F55ED004840D1 /* WalletApp.app */; @@ -2171,9 +1661,12 @@ 764E1D3426F8D3FC00A1FB15 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1430; + LastSwiftUpdateCheck = 1540; LastUpgradeCheck = 1250; TargetAttributes = { + 8445118E2C8B689D00A6A86C = { + CreatedOnToolsVersion = 15.4; + }; 844749F229B9E5B9005F520B = { CreatedOnToolsVersion = 14.2; }; @@ -2183,9 +1676,6 @@ 84E6B84629787A8000428BAF = { CreatedOnToolsVersion = 14.2; }; - A58E7CE728729F550082D443 = { - CreatedOnToolsVersion = 13.3; - }; A5A4FC712840C12C00BBEC1E = { CreatedOnToolsVersion = 13.3; }; @@ -2215,9 +1705,9 @@ A5434021291E6A270068F706 /* XCRemoteSwiftPackageReference "solana-swift" */, A58EC60F299D57B800F3452A /* XCRemoteSwiftPackageReference "swiftui-async-button" */, A561C7FE29DF32CE00DF540D /* XCRemoteSwiftPackageReference "HDWallet" */, - 8487A9422A836C2A0003D5AF /* XCRemoteSwiftPackageReference "sentry-cocoa" */, 84943C792A9BA206007EBAC2 /* XCRemoteSwiftPackageReference "mixpanel-swift" */, - A5F1526D2ACDC46B00D745A6 /* XCRemoteSwiftPackageReference "web3modal-swift" */, + 84AEC2522B4D43CD00E27A5B /* XCRemoteSwiftPackageReference "SwiftMessages" */, + 844511B82C8B6BC800A6A86C /* XCRemoteSwiftPackageReference "atlantis" */, ); productRefGroup = 764E1D3D26F8D3FC00A1FB15 /* Products */; projectDirPath = ""; @@ -2226,46 +1716,46 @@ 84CE641B27981DED00142511 /* DApp */, A5A4FC712840C12C00BBEC1E /* UITests */, A5E03DEC286464DB00888481 /* IntegrationTests */, - A58E7CE728729F550082D443 /* Showcase */, C56EE21A293F55ED004840D1 /* WalletApp */, 84E6B84629787A8000428BAF /* PNDecryptionService */, 844749F229B9E5B9005F520B /* RelayIntegrationTests */, CF1A592F29E5873D00AAC16B /* EchoUITests */, + 8445118E2C8B689D00A6A86C /* AppKitLab */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 844749F129B9E5B9005F520B /* Resources */ = { + 8445118D2C8B689D00A6A86C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 840507E32C8BAC7C00148A9B /* Preview Assets.xcassets in Resources */, + 844511B42C8B695500A6A86C /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 84CE641A27981DED00142511 /* Resources */ = { + 844749F129B9E5B9005F520B /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - C5BE02142AF77A940064FC88 /* Colors.xcassets in Resources */, - 84CE642B27981DF000142511 /* LaunchScreen.storyboard in Resources */, - 84CE642827981DF000142511 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; - 84E6B84529787A8000428BAF /* Resources */ = { + 84CE641A27981DED00142511 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + C5BE02142AF77A940064FC88 /* Colors.xcassets in Resources */, + 84CE642B27981DF000142511 /* LaunchScreen.storyboard in Resources */, + 84CE642827981DF000142511 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; - A58E7CE628729F550082D443 /* Resources */ = { + 84E6B84529787A8000428BAF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - A58E7CF728729F550082D443 /* LaunchScreen.storyboard in Resources */, - A58E7CF428729F550082D443 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2302,6 +1792,20 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 8445118B2C8B689D00A6A86C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 844511AF2C8B695500A6A86C /* WCSocketFactory.swift in Sources */, + 844511B12C8B695500A6A86C /* ContentView.swift in Sources */, + 844511AD2C8B695500A6A86C /* ComponentLibraryView.swift in Sources */, + 844511AC2C8B695500A6A86C /* InputConfig.swift in Sources */, + 844511922C8B689D00A6A86C /* AppKitLabApp.swift in Sources */, + 844511B02C8B695500A6A86C /* DefaultCryptoProvider.swift in Sources */, + 844511B32C8B695500A6A86C /* AlertPresenter.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 844749EF29B9E5B9005F520B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2317,46 +1821,43 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 84733CD52C1C2CEB001B2850 /* InputConfig.swift in Sources */, + 84733CD42C1C2C24001B2850 /* ProfilingService.swift in Sources */, + 84733CD32C1C2A4B001B2850 /* AlertPresenter.swift in Sources */, C5BE021C2AF79B9A0064FC88 /* SessionAccountRouter.swift in Sources */, - C5BE02102AF777AD0064FC88 /* MainModule.swift in Sources */, - C5BE01DD2AF692100064FC88 /* AuthInteractor.swift in Sources */, C5B4C4C42AF11C8B00B4274A /* SignView.swift in Sources */, C5BE02042AF7764F0064FC88 /* UIViewController.swift in Sources */, C5BE021E2AF79B9A0064FC88 /* SessionAccountView.swift in Sources */, + 84D093EB2B4EA6CB005B1925 /* ActivityIndicatorManager.swift in Sources */, C5BE02032AF774CB0064FC88 /* NewPairingPresenter.swift in Sources */, 84CE641F27981DED00142511 /* AppDelegate.swift in Sources */, C5BE01E32AF696540064FC88 /* SceneViewController.swift in Sources */, - C5BE020F2AF777AD0064FC88 /* TabPage.swift in Sources */, A5A8E47D293A1CFE00FEB97D /* DefaultSocketFactory.swift in Sources */, + 846E35A22C0065AD00E63DF4 /* ConfigRouter.swift in Sources */, + 846E359F2C00654F00E63DF4 /* ConfigModule.swift in Sources */, C5BE01E52AF697470064FC88 /* Color.swift in Sources */, - C5B4C4CF2AF12F1600B4274A /* AuthView.swift in Sources */, A5BB7FAD28B6AA7D00707FC6 /* QRCodeGenerator.swift in Sources */, - A51AC0D928E436A3001BACF9 /* InputConfig.swift in Sources */, - C5BE02122AF777AD0064FC88 /* MainPresenter.swift in Sources */, C5BE01E22AF693080064FC88 /* Application.swift in Sources */, C5BE021B2AF79B9A0064FC88 /* SessionAccountPresenter.swift in Sources */, A5A8E47E293A1CFE00FEB97D /* DefaultSignerFactory.swift in Sources */, - C5BE020E2AF777AD0064FC88 /* MainRouter.swift in Sources */, A5A0843D29D2F624000B9B17 /* DefaultCryptoProvider.swift in Sources */, C5BE021F2AF79B9A0064FC88 /* SessionAccountModule.swift in Sources */, C5BE01E42AF697100064FC88 /* UIColor.swift in Sources */, - C5BE01DB2AF692060064FC88 /* AuthRouter.swift in Sources */, C5BE01E62AF697FA0064FC88 /* String.swift in Sources */, C5BE02012AF774CB0064FC88 /* NewPairingModule.swift in Sources */, C5BE02002AF774CB0064FC88 /* NewPairingRouter.swift in Sources */, C5BE01F82AF6CB270064FC88 /* SignInteractor.swift in Sources */, C5BE01D12AF661D70064FC88 /* NewPairingView.swift in Sources */, + 846E35A42C0065B600E63DF4 /* ConfigPresenter.swift in Sources */, 84CE642127981DED00142511 /* SceneDelegate.swift in Sources */, C5BE02022AF774CB0064FC88 /* NewPairingInteractor.swift in Sources */, - C5BE01D92AF691FE0064FC88 /* AuthPresenter.swift in Sources */, - C5BE02112AF777AD0064FC88 /* MainViewController.swift in Sources */, C5BE021D2AF79B9A0064FC88 /* SessionAccountInteractor.swift in Sources */, A51606F82A2F47BD00CACB92 /* DefaultBIP44Provider.swift in Sources */, + 846E35A62C0065C100E63DF4 /* ConfigView.swift in Sources */, C5BE01FB2AF6CB270064FC88 /* SignRouter.swift in Sources */, - C5BE01D72AF691CD0064FC88 /* AuthModule.swift in Sources */, C5BE01F72AF6CB250064FC88 /* SignModule.swift in Sources */, C5BE01FA2AF6CB270064FC88 /* SignPresenter.swift in Sources */, - C5BE02132AF777AD0064FC88 /* MainInteractor.swift in Sources */, + 846E35A82C006C5600E63DF4 /* Constants.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2369,86 +1870,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - A58E7CE428729F550082D443 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - A58E7D3B2872D55F0082D443 /* ChatInteractor.swift in Sources */, - A5417BBE299BFC3E00B469F3 /* ImportAccount.swift in Sources */, - A58E7D1F2872A57B0082D443 /* ApplicationConfigurator.swift in Sources */, - A51AC0DF28E4379F001BACF9 /* InputConfig.swift in Sources */, - A58E7D452872EE570082D443 /* ContentMessageView.swift in Sources */, - A5C20223287EA7E2007E3188 /* BrandButton.swift in Sources */, - A5629ADF2876CC6E00094373 /* InviteListPresenter.swift in Sources */, - A58E7D392872D55F0082D443 /* ChatModule.swift in Sources */, - A58E7D222872A57B0082D443 /* AppearanceConfigurator.swift in Sources */, - A50F3946288005B200064555 /* Types.swift in Sources */, - A58E7D212872A57B0082D443 /* MigrationConfigurator.swift in Sources */, - A5629ABE2876CBC000094373 /* ChatListPresenter.swift in Sources */, - A58E7D0E2872A45B0082D443 /* MainRouter.swift in Sources */, - A58E7D432872EE320082D443 /* MessageView.swift in Sources */, - A58E7D3F2872E99A0082D443 /* TabPage.swift in Sources */, - A58EC616299D5C6400F3452A /* PlainButton.swift in Sources */, - A58E7D3C2872D55F0082D443 /* ChatPresenter.swift in Sources */, - A5C2020B287D9DEE007E3188 /* WelcomeModule.swift in Sources */, - A58E7D152872A5410082D443 /* UIViewController.swift in Sources */, - A58E7D132872A4A80082D443 /* Application.swift in Sources */, - A58E7D002872A1050082D443 /* SceneViewController.swift in Sources */, - A58E7D242872AB130082D443 /* MainViewController.swift in Sources */, - A5629AE02876CC6E00094373 /* InviteListRouter.swift in Sources */, - A58E7D032872A1630082D443 /* String.swift in Sources */, - A58E7D3D2872D55F0082D443 /* ChatView.swift in Sources */, - A5629ABD2876CBC000094373 /* ChatListModule.swift in Sources */, - A58E7CEB28729F550082D443 /* AppDelegate.swift in Sources */, - A51606FA2A2F47BD00CACB92 /* DefaultBIP44Provider.swift in Sources */, - A578FA35287304A300AA7720 /* Color.swift in Sources */, - A5629ADE2876CC6E00094373 /* InviteListModule.swift in Sources */, - A5E776BA29F4362D00172091 /* AlertError.swift in Sources */, - A578FA322873036400AA7720 /* InputView.swift in Sources */, - A5A0843F29D2F625000B9B17 /* DefaultCryptoProvider.swift in Sources */, - A5C2021B287E1FD8007E3188 /* ImportRouter.swift in Sources */, - A5629AE42876E6D200094373 /* ThreadViewModel.swift in Sources */, - A58E7D0C2872A45B0082D443 /* MainModule.swift in Sources */, - A5C2021C287E1FD8007E3188 /* ImportInteractor.swift in Sources */, - A58E7D0D2872A45B0082D443 /* MainPresenter.swift in Sources */, - A518A98829683FB60035247E /* Web3InboxModule.swift in Sources */, - A5C20219287E1FD8007E3188 /* ImportModule.swift in Sources */, - A5629AD62876CC5700094373 /* InviteInteractor.swift in Sources */, - A5629AE12876CC6E00094373 /* InviteListInteractor.swift in Sources */, - A58E7CED28729F550082D443 /* SceneDelegate.swift in Sources */, - A5C2020F287D9DEE007E3188 /* WelcomeView.swift in Sources */, - A518A98929683FB60035247E /* Web3InboxRouter.swift in Sources */, - A5C5153329BB7A6A004210BA /* InviteType.swift in Sources */, - A5C2020D287D9DEE007E3188 /* WelcomeRouter.swift in Sources */, - A578FA372873D8EE00AA7720 /* UIColor.swift in Sources */, - A518A98729683FB60035247E /* Web3InboxViewController.swift in Sources */, - A5C2021D287E1FD8007E3188 /* ImportView.swift in Sources */, - A5C2021A287E1FD8007E3188 /* ImportPresenter.swift in Sources */, - A5629AE828772A0100094373 /* InviteViewModel.swift in Sources */, - A5629AA92876A23100094373 /* ChatService.swift in Sources */, - A5C20229287EB34C007E3188 /* AccountStorage.swift in Sources */, - A5629AC02876CBC000094373 /* ChatListInteractor.swift in Sources */, - A5629AE22876CC6E00094373 /* InviteListView.swift in Sources */, - A5A8E47F293A1D0000FEB97D /* DefaultSocketFactory.swift in Sources */, - A578FA3D2874002400AA7720 /* View.swift in Sources */, - A5629AD72876CC5700094373 /* InviteView.swift in Sources */, - A5C20221287EA5B8007E3188 /* TextFieldView.swift in Sources */, - A5A8E480293A1D0000FEB97D /* DefaultSignerFactory.swift in Sources */, - A5C2022B287EB89A007E3188 /* WelcomeInteractor.swift in Sources */, - A5C2020C287D9DEE007E3188 /* WelcomePresenter.swift in Sources */, - A58E7D1D2872A57B0082D443 /* Configurator.swift in Sources */, - A58E7D482872EF610082D443 /* MessageViewModel.swift in Sources */, - A5629AD32876CC5700094373 /* InviteModule.swift in Sources */, - A5629AD52876CC5700094373 /* InviteRouter.swift in Sources */, - A5629ABF2876CBC000094373 /* ChatListRouter.swift in Sources */, - A5629AC12876CBC000094373 /* ChatListView.swift in Sources */, - A578FA392873FCE000AA7720 /* ChatScrollView.swift in Sources */, - A58E7D1E2872A57B0082D443 /* ThirdPartyConfigurator.swift in Sources */, - A5629AD42876CC5700094373 /* InvitePresenter.swift in Sources */, - A58E7D3A2872D55F0082D443 /* ChatRouter.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; A5A4FC6E2840C12C00BBEC1E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2469,24 +1890,17 @@ buildActionMask = 2147483647; files = ( A51606F92A2F47BD00CACB92 /* DefaultBIP44Provider.swift in Sources */, - A573C53729EC34A600E3CBFD /* SyncDerivationServiceTests.swift in Sources */, A5A0843E29D2F624000B9B17 /* DefaultCryptoProvider.swift in Sources */, - 84CEC64628D89D6B00D081A8 /* PairingTests.swift in Sources */, - A561C80329DFCCDC00DF540D /* SyncTests.swift in Sources */, 767DC83528997F8E00080FA9 /* EthSendTransaction.swift in Sources */, 8439CB89293F658E00F2F2E2 /* PushMessage.swift in Sources */, A518B31428E33A6500A2CE93 /* InputConfig.swift in Sources */, A541959E2934BFEF0035AD19 /* CacaoSignerTests.swift in Sources */, A59CF4F6292F83D50031A42F /* DefaultSignerFactory.swift in Sources */, 847F08012A25DBFF00B2A5A4 /* XPlatformW3WTests.swift in Sources */, - A5E03E03286466F400888481 /* ChatTests.swift in Sources */, 849D7A93292E2169006A2BD4 /* NotifyTests.swift in Sources */, 845B8D8C2934B36C0084A966 /* Account.swift in Sources */, - 84D2A66628A4F51E0088AE09 /* AuthTests.swift in Sources */, 84FE684628ACDB4700C893FF /* RequestParams.swift in Sources */, - 7694A5262874296A0001257E /* RegistryTests.swift in Sources */, A541959F2934BFEF0035AD19 /* SignerTests.swift in Sources */, - A5321C2B2A250367006CADC3 /* HistoryTests.swift in Sources */, A58A1ECC29BF458600A82A20 /* ENSResolverTests.swift in Sources */, A5E03DFA286465C700888481 /* SignClientTests.swift in Sources */, 84A6E3C32A386BBC008A0571 /* Publisher.swift in Sources */, @@ -2510,10 +1924,11 @@ A51811A02A52E83100A52B15 /* SettingsPresenter.swift in Sources */, 847BD1DA2989492500076C90 /* MainRouter.swift in Sources */, C5F32A2E2954814A00A6476E /* ConnectionDetailsRouter.swift in Sources */, - C55D3482295DD7140004314A /* AuthRequestInteractor.swift in Sources */, + 84AEC24F2B4D1EE400E27A5B /* ActivityIndicatorManager.swift in Sources */, C55D34B12965FB750004314A /* SessionProposalInteractor.swift in Sources */, C56EE247293F566D004840D1 /* ScanModule.swift in Sources */, C56EE28D293F5757004840D1 /* AppearanceConfigurator.swift in Sources */, + 84AEC2512B4D42C100E27A5B /* AlertPresenter.swift in Sources */, 847BD1D82989492500076C90 /* MainModule.swift in Sources */, 847BD1E7298A806800076C90 /* NotificationsInteractor.swift in Sources */, C56EE241293F566D004840D1 /* WalletModule.swift in Sources */, @@ -2624,7 +2039,6 @@ C55D34AF2965FB750004314A /* SessionProposalPresenter.swift in Sources */, A5D610D22AB35B1100C20083 /* Listings.swift in Sources */, A5B4F7C82ABB21190099AF7C /* CacheAsyncImage.swift in Sources */, - C5F32A302954816100A6476E /* ConnectionDetailsInteractor.swift in Sources */, 847BD1E8298A806800076C90 /* NotificationsView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2684,14 +2098,6 @@ name = LaunchScreen.storyboard; sourceTree = ""; }; - A58E7CF528729F550082D443 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - A58E7CF628729F550082D443 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ @@ -2730,7 +2136,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 184; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -2794,7 +2200,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 184; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -2818,12 +2224,87 @@ }; name = Release; }; + 8445119A2C8B689F00A6A86C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = AppKitLab/AppKitLab.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 184; + DEVELOPMENT_ASSET_PATHS = "\"AppKitLab/Preview Content\""; + DEVELOPMENT_TEAM = W5R8AG9K22; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = AppKitLab/Info.plist; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.web3modal.sample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 8445119B2C8B689F00A6A86C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_ENTITLEMENTS = AppKitLab/AppKitLab.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 184; + DEVELOPMENT_ASSET_PATHS = "\"AppKitLab/Preview Content\""; + DEVELOPMENT_TEAM = W5R8AG9K22; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = AppKitLab/Info.plist; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.web3modal.sample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; 844749F929B9E5B9005F520B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = W5R8AG9K22; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -2841,7 +2322,7 @@ buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = W5R8AG9K22; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -2860,9 +2341,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CODE_SIGN_ENTITLEMENTS = DApp/DApp.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = W5R8AG9K22; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = DApp/Info.plist; @@ -2895,10 +2377,13 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CODE_SIGN_ENTITLEMENTS = DApp/DAppRelease.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; - DEVELOPMENT_TEAM = W5R8AG9K22; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 184; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = DApp/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = dApp; @@ -2918,6 +2403,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.dapp; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.walletconnect.dapp"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -2931,7 +2417,7 @@ CODE_SIGN_ENTITLEMENTS = PNDecryptionService/PNDecryptionService.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = W5R8AG9K22; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = PNDecryptionService/Info.plist; @@ -2962,7 +2448,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; GENERATE_INFOPLIST_FILE = YES; @@ -2987,83 +2473,12 @@ }; name = Release; }; - A58E7CF928729F550082D443 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CODE_SIGN_IDENTITY = "Apple Development"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 7; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = Showcase/Other/Info.plist; - INFOPLIST_KEY_NSCameraUsageDescription = "Allow the app to scan for QR codes"; - INFOPLIST_KEY_NSMicrophoneUsageDescription = "If you want to use the microphone, you have to give permission."; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.chat; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match Development com.walletconnect.chat"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - A58E7CFA28729F550082D443 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 7; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = Showcase/Other/Info.plist; - INFOPLIST_KEY_NSCameraUsageDescription = "Allow the app to scan for QR codes"; - INFOPLIST_KEY_NSMicrophoneUsageDescription = "If you want to use the microphone, you have to give permission."; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.chat; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.walletconnect.chat"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; A5A4FC782840C12C00BBEC1E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = W5R8AG9K22; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; @@ -3081,7 +2496,7 @@ buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = W5R8AG9K22; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; @@ -3099,7 +2514,7 @@ buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = W5R8AG9K22; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -3122,7 +2537,7 @@ buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = W5R8AG9K22; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -3144,7 +2559,7 @@ CODE_SIGN_ENTITLEMENTS = WalletApp/WalletApp.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = W5R8AG9K22; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -3178,10 +2593,10 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_ENTITLEMENTS = WalletApp/WalletAppRelease.entitlements; - CODE_SIGN_IDENTITY = "Apple Distribution"; + CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 7; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5R8AG9K22; ENABLE_PREVIEWS = YES; @@ -3214,7 +2629,7 @@ buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = W5R8AG9K22; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -3232,7 +2647,7 @@ buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 184; DEVELOPMENT_TEAM = W5R8AG9K22; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -3257,6 +2672,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 8445119C2C8B689F00A6A86C /* Build configuration list for PBXNativeTarget "AppKitLab" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8445119A2C8B689F00A6A86C /* Debug */, + 8445119B2C8B689F00A6A86C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 844749FB29B9E5B9005F520B /* Build configuration list for PBXNativeTarget "RelayIntegrationTests" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -3284,15 +2708,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - A58E7CFB28729F550082D443 /* Build configuration list for PBXNativeTarget "Showcase" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - A58E7CF928729F550082D443 /* Debug */, - A58E7CFA28729F550082D443 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; A5A4FC7A2840C12C00BBEC1E /* Build configuration list for PBXNativeTarget "UITests" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -3332,12 +2747,12 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 8487A9422A836C2A0003D5AF /* XCRemoteSwiftPackageReference "sentry-cocoa" */ = { + 844511B82C8B6BC800A6A86C /* XCRemoteSwiftPackageReference "atlantis" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/getsentry/sentry-cocoa.git"; + repositoryURL = "https://github.com/ProxymanApp/atlantis"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 8.0.0; + minimumVersion = 1.24.0; }; }; 84943C792A9BA206007EBAC2 /* XCRemoteSwiftPackageReference "mixpanel-swift" */ = { @@ -3348,6 +2763,14 @@ kind = branch; }; }; + 84AEC2522B4D43CD00E27A5B /* XCRemoteSwiftPackageReference "SwiftMessages" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SwiftKickMobile/SwiftMessages"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 9.0.9; + }; + }; A5434021291E6A270068F706 /* XCRemoteSwiftPackageReference "solana-swift" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/flypaper0/solana-swift"; @@ -3388,17 +2811,62 @@ version = 3.1.2; }; }; - A5F1526D2ACDC46B00D745A6 /* XCRemoteSwiftPackageReference "web3modal-swift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/WalletConnect/web3modal-swift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.0.9; - }; - }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 8421447A2C80A2B8004FF494 /* ReownAppKit */ = { + isa = XCSwiftPackageProductDependency; + productName = ReownAppKit; + }; + 8421447C2C80A544004FF494 /* ReownAppKitUI */ = { + isa = XCSwiftPackageProductDependency; + productName = ReownAppKitUI; + }; + 8421447E2C81863A004FF494 /* ReownWalletKit */ = { + isa = XCSwiftPackageProductDependency; + productName = ReownWalletKit; + }; + 842144802C818684004FF494 /* ReownWalletKit */ = { + isa = XCSwiftPackageProductDependency; + productName = ReownWalletKit; + }; + 842144822C818928004FF494 /* ReownWalletKit */ = { + isa = XCSwiftPackageProductDependency; + productName = ReownWalletKit; + }; + 844511B52C8B69F200A6A86C /* Starscream */ = { + isa = XCSwiftPackageProductDependency; + package = A5D85224286333D500DAF5C3 /* XCRemoteSwiftPackageReference "Starscream" */; + productName = Starscream; + }; + 844511B92C8B6BC800A6A86C /* Atlantis */ = { + isa = XCSwiftPackageProductDependency; + package = 844511B82C8B6BC800A6A86C /* XCRemoteSwiftPackageReference "atlantis" */; + productName = Atlantis; + }; + 844511BB2C8B6BE600A6A86C /* Web3ContractABI */ = { + isa = XCSwiftPackageProductDependency; + package = A5AE354528A1A2AC0059AE8A /* XCRemoteSwiftPackageReference "Web3" */; + productName = Web3ContractABI; + }; + 844511BD2C8B6BF000A6A86C /* ReownAppKitUI */ = { + isa = XCSwiftPackageProductDependency; + productName = ReownAppKitUI; + }; + 844511BF2C8B6BF800A6A86C /* Web3 */ = { + isa = XCSwiftPackageProductDependency; + package = A5AE354528A1A2AC0059AE8A /* XCRemoteSwiftPackageReference "Web3" */; + productName = Web3; + }; + 844511C12C8B6C0600A6A86C /* SwiftMessages */ = { + isa = XCSwiftPackageProductDependency; + package = 84AEC2522B4D43CD00E27A5B /* XCRemoteSwiftPackageReference "SwiftMessages" */; + productName = SwiftMessages; + }; + 844511C32C8B6C0D00A6A86C /* ReownAppKit */ = { + isa = XCSwiftPackageProductDependency; + productName = ReownAppKit; + }; 844749FC29B9E6B2005F520B /* WalletConnectNetworking */ = { isa = XCSwiftPackageProductDependency; productName = WalletConnectNetworking; @@ -3412,15 +2880,10 @@ isa = XCSwiftPackageProductDependency; productName = WalletConnect; }; - 8487A9432A836C2A0003D5AF /* Sentry */ = { - isa = XCSwiftPackageProductDependency; - package = 8487A9422A836C2A0003D5AF /* XCRemoteSwiftPackageReference "sentry-cocoa" */; - productName = Sentry; - }; - 8487A9452A836C3F0003D5AF /* Sentry */ = { + 8486EDD22B4F2EA6008E53C3 /* SwiftMessages */ = { isa = XCSwiftPackageProductDependency; - package = 8487A9422A836C2A0003D5AF /* XCRemoteSwiftPackageReference "sentry-cocoa" */; - productName = Sentry; + package = 84AEC2522B4D43CD00E27A5B /* XCRemoteSwiftPackageReference "SwiftMessages" */; + productName = SwiftMessages; }; 84943C7A2A9BA206007EBAC2 /* Mixpanel */ = { isa = XCSwiftPackageProductDependency; @@ -3432,37 +2895,20 @@ package = 84943C792A9BA206007EBAC2 /* XCRemoteSwiftPackageReference "mixpanel-swift" */; productName = Mixpanel; }; - 84DDB4EC28ABB663003D66ED /* WalletConnectAuth */ = { + 84AEC2532B4D43CD00E27A5B /* SwiftMessages */ = { isa = XCSwiftPackageProductDependency; - productName = WalletConnectAuth; + package = 84AEC2522B4D43CD00E27A5B /* XCRemoteSwiftPackageReference "SwiftMessages" */; + productName = SwiftMessages; }; - A50DF19C2A25084A0036EA6C /* WalletConnectHistory */ = { + 84CA52162C88965C0069BB33 /* ReownRouter */ = { isa = XCSwiftPackageProductDependency; - productName = WalletConnectHistory; + productName = ReownRouter; }; A54195A42934E83F0035AD19 /* Web3 */ = { isa = XCSwiftPackageProductDependency; package = A5AE354528A1A2AC0059AE8A /* XCRemoteSwiftPackageReference "Web3" */; productName = Web3; }; - A561C7FF29DF32CE00DF540D /* HDWalletKit */ = { - isa = XCSwiftPackageProductDependency; - package = A561C7FE29DF32CE00DF540D /* XCRemoteSwiftPackageReference "HDWallet" */; - productName = HDWalletKit; - }; - A561C80429DFCD4500DF540D /* WalletConnectSync */ = { - isa = XCSwiftPackageProductDependency; - productName = WalletConnectSync; - }; - A5629AE92877F2D600094373 /* WalletConnectChat */ = { - isa = XCSwiftPackageProductDependency; - productName = WalletConnectChat; - }; - A5629AF12877F75100094373 /* Starscream */ = { - isa = XCSwiftPackageProductDependency; - package = A5D85224286333D500DAF5C3 /* XCRemoteSwiftPackageReference "Starscream" */; - productName = Starscream; - }; A573C53829EC365000E3CBFD /* HDWalletKit */ = { isa = XCSwiftPackageProductDependency; package = A561C7FE29DF32CE00DF540D /* XCRemoteSwiftPackageReference "HDWallet" */; @@ -3478,29 +2924,11 @@ package = A561C7FE29DF32CE00DF540D /* XCRemoteSwiftPackageReference "HDWallet" */; productName = HDWalletKit; }; - A58EC610299D57B800F3452A /* AsyncButton */ = { - isa = XCSwiftPackageProductDependency; - package = A58EC60F299D57B800F3452A /* XCRemoteSwiftPackageReference "swiftui-async-button" */; - productName = AsyncButton; - }; - A58EC617299D665A00F3452A /* Web3Inbox */ = { - isa = XCSwiftPackageProductDependency; - productName = Web3Inbox; - }; A59D25ED2AB3672700D7EA3A /* AsyncButton */ = { isa = XCSwiftPackageProductDependency; package = A58EC60F299D57B800F3452A /* XCRemoteSwiftPackageReference "swiftui-async-button" */; productName = AsyncButton; }; - A59F877528B5462900A9CD80 /* WalletConnectAuth */ = { - isa = XCSwiftPackageProductDependency; - productName = WalletConnectAuth; - }; - A59FAEC828B7B93A002BB66F /* Web3 */ = { - isa = XCSwiftPackageProductDependency; - package = A5AE354528A1A2AC0059AE8A /* XCRemoteSwiftPackageReference "Web3" */; - productName = Web3; - }; A5A650C92B062A1400F9AD4B /* Mixpanel */ = { isa = XCSwiftPackageProductDependency; package = 84943C792A9BA206007EBAC2 /* XCRemoteSwiftPackageReference "mixpanel-swift" */; @@ -3522,10 +2950,6 @@ isa = XCSwiftPackageProductDependency; productName = WalletConnectNotify; }; - A5BB7FA228B6A50400707FC6 /* WalletConnectAuth */ = { - isa = XCSwiftPackageProductDependency; - productName = WalletConnectAuth; - }; A5C8BE84292FE20B006CC85C /* Web3 */ = { isa = XCSwiftPackageProductDependency; package = A5AE354528A1A2AC0059AE8A /* XCRemoteSwiftPackageReference "Web3" */; @@ -3545,63 +2969,21 @@ isa = XCSwiftPackageProductDependency; productName = WalletConnect; }; - A5E03E00286466EA00888481 /* WalletConnectChat */ = { - isa = XCSwiftPackageProductDependency; - productName = WalletConnectChat; - }; - A5F1526E2ACDC46B00D745A6 /* Web3ModalUI */ = { - isa = XCSwiftPackageProductDependency; - package = A5F1526D2ACDC46B00D745A6 /* XCRemoteSwiftPackageReference "web3modal-swift" */; - productName = Web3ModalUI; - }; C5133A77294125CC00A8314C /* Web3 */ = { isa = XCSwiftPackageProductDependency; package = A5AE354528A1A2AC0059AE8A /* XCRemoteSwiftPackageReference "Web3" */; productName = Web3; }; - C54C248F2AEB1B5600DA4BF6 /* WalletConnectRouter */ = { - isa = XCSwiftPackageProductDependency; - productName = WalletConnectRouter; - }; - C55D349829630D440004314A /* Web3Wallet */ = { - isa = XCSwiftPackageProductDependency; - productName = Web3Wallet; - }; C56EE254293F569A004840D1 /* Starscream */ = { isa = XCSwiftPackageProductDependency; package = A5D85224286333D500DAF5C3 /* XCRemoteSwiftPackageReference "Starscream" */; productName = Starscream; }; - C56EE27A293F56F8004840D1 /* WalletConnectAuth */ = { - isa = XCSwiftPackageProductDependency; - productName = WalletConnectAuth; - }; - C56EE27C293F56F8004840D1 /* WalletConnectChat */ = { - isa = XCSwiftPackageProductDependency; - productName = WalletConnectChat; - }; - C579FEB52AFA86CD008855EB /* Web3Modal */ = { - isa = XCSwiftPackageProductDependency; - package = A5F1526D2ACDC46B00D745A6 /* XCRemoteSwiftPackageReference "web3modal-swift" */; - productName = Web3Modal; - }; C5B2F7042970573D000DBA0E /* SolanaSwift */ = { isa = XCSwiftPackageProductDependency; package = A5434021291E6A270068F706 /* XCRemoteSwiftPackageReference "solana-swift" */; productName = SolanaSwift; }; - C5BE01DE2AF692D80064FC88 /* WalletConnectRouter */ = { - isa = XCSwiftPackageProductDependency; - productName = WalletConnectRouter; - }; - C5DD5BE0294E09E3008FD3A4 /* Web3Wallet */ = { - isa = XCSwiftPackageProductDependency; - productName = Web3Wallet; - }; - CF25F2882A432476009C7E49 /* WalletConnectModal */ = { - isa = XCSwiftPackageProductDependency; - productName = WalletConnectModal; - }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 764E1D3426F8D3FC00A1FB15 /* Project object */; diff --git a/Example/ExampleApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Example/ExampleApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index dceba93f5..628dc6270 100644 --- a/Example/ExampleApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Example/ExampleApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,13 +1,22 @@ { "object": { "pins": [ + { + "package": "Atlantis", + "repositoryURL": "https://github.com/ProxymanApp/atlantis", + "state": { + "branch": null, + "revision": "5145a7041ec71421d09653db87dcc80c81792004", + "version": "1.24.0" + } + }, { "package": "BigInt", "repositoryURL": "https://github.com/attaswift/BigInt.git", "state": { "branch": null, - "revision": "0ed110f7555c34ff468e72e1686e59721f2b0da6", - "version": "5.3.0" + "revision": "793a7fac0bfc318e85994bf6900652e827aef33e", + "version": "5.4.1" } }, { @@ -15,8 +24,8 @@ "repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift.git", "state": { "branch": null, - "revision": "db51c407d3be4a051484a141bf0bff36c43d3b1e", - "version": "1.8.0" + "revision": "678d442c6f7828def400a70ae15968aef67ef52d", + "version": "1.8.3" } }, { @@ -33,7 +42,7 @@ "repositoryURL": "https://github.com/mixpanel/mixpanel-swift", "state": { "branch": "master", - "revision": "1ce27d937009d5ecce74dad97d69898ffea49c75", + "revision": "61ce9b40817466fb1334db1d7a582fbaf616ab4c", "version": null } }, @@ -64,15 +73,6 @@ "version": "0.1.7" } }, - { - "package": "Sentry", - "repositoryURL": "https://github.com/getsentry/sentry-cocoa.git", - "state": { - "branch": null, - "revision": "14aa6e47b03b820fd2b338728637570b9e969994", - "version": "8.12.0" - } - }, { "package": "SolanaSwift", "repositoryURL": "https://github.com/flypaper0/solana-swift", @@ -96,13 +96,13 @@ "repositoryURL": "https://github.com/apple/swift-docc-plugin", "state": { "branch": null, - "revision": "26ac5758409154cc448d7ab82389c520fa8a8247", - "version": "1.3.0" + "revision": "2eb22993b3dfd0c0d32729b357c8dabb6cd44680", + "version": "1.4.2" } }, { "package": "SymbolKit", - "repositoryURL": "https://github.com/apple/swift-docc-symbolkit", + "repositoryURL": "https://github.com/swiftlang/swift-docc-symbolkit", "state": { "branch": null, "revision": "b45d1f2ed151d057b54504d653e0da5552844e34", @@ -118,6 +118,15 @@ "version": "1.0.3" } }, + { + "package": "swift-snapshot-testing", + "repositoryURL": "https://github.com/pointfreeco/swift-snapshot-testing", + "state": { + "branch": null, + "revision": "f29e2014f6230cf7d5138fc899da51c7f513d467", + "version": "1.10.0" + } + }, { "package": "SwiftImageReadWrite", "repositoryURL": "https://github.com/dagronf/SwiftImageReadWrite", @@ -127,6 +136,15 @@ "version": "1.1.6" } }, + { + "package": "SwiftMessages", + "repositoryURL": "https://github.com/SwiftKickMobile/SwiftMessages", + "state": { + "branch": null, + "revision": "62e12e138fc3eedf88c7553dd5d98712aa119f40", + "version": "9.0.9" + } + }, { "package": "swiftui-async-button", "repositoryURL": "https://github.com/lorenzofiamingo/swiftui-async-button", @@ -155,21 +173,21 @@ } }, { - "package": "Web3", - "repositoryURL": "https://github.com/WalletConnect/Web3.swift", + "package": "CoinbaseWalletSDK", + "repositoryURL": "https://github.com/WalletConnect/wallet-mobile-sdk", "state": { "branch": null, - "revision": "569255adcfff0b37e4cb8004aea29d0e2d6266df", - "version": "1.0.2" + "revision": "b6dfb7d6b8447c7c5b238a10443a1ac28223f38f", + "version": "1.0.0" } }, { - "package": "swift-web3modal", - "repositoryURL": "https://github.com/WalletConnect/web3modal-swift", + "package": "Web3", + "repositoryURL": "https://github.com/WalletConnect/Web3.swift", "state": { "branch": null, - "revision": "831410cfd6e68afa7212a5547483fb2d180f0fa7", - "version": "1.0.10" + "revision": "569255adcfff0b37e4cb8004aea29d0e2d6266df", + "version": "1.0.2" } } ] diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/BuildAll.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/BuildAll.xcscheme index 6b4a6df22..2c44051d9 100644 --- a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/BuildAll.xcscheme +++ b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/BuildAll.xcscheme @@ -62,6 +62,20 @@ ReferencedContainer = "container:ExampleApp.xcodeproj"> + + + + + + + + diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/PNDecryptionService.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/PNDecryptionService.xcscheme new file mode 100644 index 000000000..026a57bb3 --- /dev/null +++ b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/PNDecryptionService.xcscheme @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/PushDecryptionService.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/PushDecryptionService.xcscheme deleted file mode 100644 index 07e071581..000000000 --- a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/PushDecryptionService.xcscheme +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/Showcase.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/Showcase.xcscheme deleted file mode 100644 index f9350d24d..000000000 --- a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/Showcase.xcscheme +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/Wallet.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/Wallet.xcscheme deleted file mode 100644 index d786c3306..000000000 --- a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/Wallet.xcscheme +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletApp.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletApp.xcscheme index 036e15875..6d01f5811 100644 --- a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletApp.xcscheme +++ b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletApp.xcscheme @@ -20,6 +20,20 @@ ReferencedContainer = "container:ExampleApp.xcodeproj"> + + + + - - - - + + + + - - - - - - - - @@ -292,9 +272,9 @@ skipped = "NO"> @@ -320,9 +300,9 @@ diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectAuth.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectAuth.xcscheme deleted file mode 100644 index 3a5aff949..000000000 --- a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectAuth.xcscheme +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectChat.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectChat.xcscheme deleted file mode 100644 index ae2c82e99..000000000 --- a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectChat.xcscheme +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectPairing.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectPairing.xcscheme index dc1c7488b..f4bd38aa8 100644 --- a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectPairing.xcscheme +++ b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectPairing.xcscheme @@ -28,6 +28,16 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectVerify.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectVerify.xcscheme index 5b4aa4030..0f35eb712 100644 --- a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectVerify.xcscheme +++ b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/WalletConnectVerify.xcscheme @@ -28,6 +28,16 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example/IntegrationTests/Auth/AuthTests.swift b/Example/IntegrationTests/Auth/AuthTests.swift deleted file mode 100644 index 276e14e84..000000000 --- a/Example/IntegrationTests/Auth/AuthTests.swift +++ /dev/null @@ -1,209 +0,0 @@ -import Foundation -import XCTest -@testable import WalletConnectUtils -@testable import WalletConnectKMS -import WalletConnectRelay -import Combine -@testable import Auth -import WalletConnectPairing -import WalletConnectNetworking -import WalletConnectVerify - -final class AuthTests: XCTestCase { - var appPairingClient: PairingClient! - var walletPairingClient: PairingClient! - - var appAuthClient: AuthClient! - var walletAuthClient: AuthClient! - - let walletAccount = Account(chainIdentifier: "eip155:1", address: "0x724d0D2DaD3fbB0C168f947B87Fa5DBe36F1A8bf")! - let prvKey = Data(hex: "462c1dad6832d7d96ccf87bd6a686a4110e114aaaebd5512e552c0e3a87b480f") - let eip1271Signature = "0xc1505719b2504095116db01baaf276361efd3a73c28cf8cc28dabefa945b8d536011289ac0a3b048600c1e692ff173ca944246cf7ceb319ac2262d27b395c82b1c" - private var publishers = [AnyCancellable]() - - override func setUp() { - setupClients() - } - - private func setupClients(iatProvider: IATProvider = DefaultIATProvider()) { - (appPairingClient, appAuthClient) = makeClients(prefix: "🤖 App", iatProvider: iatProvider) - (walletPairingClient, walletAuthClient) = makeClients(prefix: "🐶 Wallet", iatProvider: iatProvider) - } - - func makeClients(prefix: String, iatProvider: IATProvider) -> (PairingClient, AuthClient) { - let logger = ConsoleLogger(prefix: prefix, loggingLevel: .debug) - let keyValueStorage = RuntimeKeyValueStorage() - let keychain = KeychainStorageMock() - let relayClient = RelayClientFactory.create( - relayHost: InputConfig.relayHost, - projectId: InputConfig.projectId, - keyValueStorage: keyValueStorage, - keychainStorage: keychain, - socketFactory: DefaultSocketFactory(), - logger: logger) - - let networkingClient = NetworkingClientFactory.create( - relayClient: relayClient, - logger: logger, - keychainStorage: keychain, - keyValueStorage: keyValueStorage) - - let pairingClient = PairingClientFactory.create( - logger: logger, - keyValueStorage: keyValueStorage, - keychainStorage: keychain, - networkingClient: networkingClient) - - let authClient = AuthClientFactory.create( - metadata: AppMetadata(name: name, description: "", url: "", icons: [""], redirect: AppMetadata.Redirect(native: "", universal: nil)), - projectId: InputConfig.projectId, - crypto: DefaultCryptoProvider(), - logger: logger, - keyValueStorage: keyValueStorage, - keychainStorage: keychain, - networkingClient: networkingClient, - pairingRegisterer: pairingClient, - iatProvider: iatProvider) - - let clientId = try! networkingClient.getClientId() - logger.debug("My client id is: \(clientId)") - - return (pairingClient, authClient) - } - - func testRequest() async { - let requestExpectation = expectation(description: "request delivered to wallet") - let uri = try! await appPairingClient.create() - try! await appAuthClient.request(RequestParams.stub(), topic: uri.topic) - - try? await walletPairingClient.pair(uri: uri) - walletAuthClient.authRequestPublisher.sink { _ in - requestExpectation.fulfill() - }.store(in: &publishers) - wait(for: [requestExpectation], timeout: InputConfig.defaultTimeout) - } - - func testEIP191RespondSuccess() async { - let responseExpectation = expectation(description: "successful response delivered") - let uri = try! await appPairingClient.create() - try! await appAuthClient.request(RequestParams.stub(), topic: uri.topic) - - try? await walletPairingClient.pair(uri: uri) - walletAuthClient.authRequestPublisher.sink { [unowned self] request in - Task(priority: .high) { - let signerFactory = DefaultSignerFactory() - let signer = MessageSignerFactory(signerFactory: signerFactory).create(projectId: InputConfig.projectId) - let payload = try! request.0.payload.cacaoPayload(address: walletAccount.address) - let signature = try! signer.sign(payload: payload, privateKey: prvKey, type: .eip191) - try! await walletAuthClient.respond(requestId: request.0.id, signature: signature, from: walletAccount) - } - } - .store(in: &publishers) - appAuthClient.authResponsePublisher.sink { (_, result) in - guard case .success = result else { XCTFail(); return } - responseExpectation.fulfill() - } - .store(in: &publishers) - wait(for: [responseExpectation], timeout: InputConfig.defaultTimeout) - } - - func testEIP1271RespondSuccess() async { - setupClients(iatProvider: IATProviderMock()) - - let account = Account(chainIdentifier: "eip155:1", address: "0x2faf83c542b68f1b4cdc0e770e8cb9f567b08f71")! - - let responseExpectation = expectation(description: "successful response delivered") - let uri = try! await appPairingClient.create() - try! await appAuthClient.request(RequestParams( - domain: "localhost", - chainId: "eip155:1", - nonce: "1665443015700", - aud: "http://localhost:3000/", - nbf: nil, - exp: "2022-10-11T23:03:35.700Z", - statement: nil, - requestId: nil, - resources: nil - ), topic: uri.topic) - - try? await walletPairingClient.pair(uri: uri) - walletAuthClient.authRequestPublisher.sink { [unowned self] request in - Task(priority: .high) { - let signature = CacaoSignature(t: .eip1271, s: eip1271Signature) - try! await walletAuthClient.respond(requestId: request.0.id, signature: signature, from: account) - } - } - .store(in: &publishers) - appAuthClient.authResponsePublisher.sink { (_, result) in - guard case .success = result else { XCTFail(); return } - responseExpectation.fulfill() - } - .store(in: &publishers) - wait(for: [responseExpectation], timeout: InputConfig.defaultTimeout) - } - - func testEIP191RespondError() async { - let responseExpectation = expectation(description: "error response delivered") - let uri = try! await appPairingClient.create() - try! await appAuthClient.request(RequestParams.stub(), topic: uri.topic) - - try? await walletPairingClient.pair(uri: uri) - walletAuthClient.authRequestPublisher.sink { [unowned self] request in - Task(priority: .high) { - let signature = CacaoSignature(t: .eip1271, s: eip1271Signature) - try! await walletAuthClient.respond(requestId: request.0.id, signature: signature, from: walletAccount) - } - } - .store(in: &publishers) - appAuthClient.authResponsePublisher.sink { (_, result) in - guard case let .failure(error) = result, error == .signatureVerificationFailed else { XCTFail(); return } - responseExpectation.fulfill() - } - .store(in: &publishers) - wait(for: [responseExpectation], timeout: InputConfig.defaultTimeout) - } - - func testUserRespondError() async { - let responseExpectation = expectation(description: "error response delivered") - let uri = try! await appPairingClient.create() - try! await appAuthClient.request(RequestParams.stub(), topic: uri.topic) - - try? await walletPairingClient.pair(uri: uri) - walletAuthClient.authRequestPublisher.sink { [unowned self] request in - Task(priority: .high) { - try! await walletAuthClient.reject(requestId: request.0.id) - } - } - .store(in: &publishers) - appAuthClient.authResponsePublisher.sink { (_, result) in - guard case .failure(let error) = result else { XCTFail(); return } - XCTAssertEqual(error, .userRejeted) - responseExpectation.fulfill() - } - .store(in: &publishers) - wait(for: [responseExpectation], timeout: InputConfig.defaultTimeout) - } - - func testRespondSignatureVerificationFailed() async { - let responseExpectation = expectation(description: "invalid signature response delivered") - let uri = try! await appPairingClient.create() - try! await appAuthClient.request(RequestParams.stub(), topic: uri.topic) - - try? await walletPairingClient.pair(uri: uri) - walletAuthClient.authRequestPublisher.sink { [unowned self] request in - Task(priority: .high) { - let invalidSignature = "438effc459956b57fcd9f3dac6c675f9cee88abf21acab7305e8e32aa0303a883b06dcbd956279a7a2ca21ffa882ff55cc22e8ab8ec0f3fe90ab45f306938cfa1b" - let cacaoSignature = CacaoSignature(t: .eip191, s: invalidSignature) - try! await walletAuthClient.respond(requestId: request.0.id, signature: cacaoSignature, from: walletAccount) - } - } - .store(in: &publishers) - appAuthClient.authResponsePublisher.sink { (_, result) in - guard case .failure(let error) = result else { XCTFail(); return } - XCTAssertEqual(error, .signatureVerificationFailed) - responseExpectation.fulfill() - } - .store(in: &publishers) - wait(for: [responseExpectation], timeout: InputConfig.defaultTimeout) - } -} diff --git a/Example/IntegrationTests/Auth/Signer/CacaoSignerTests.swift b/Example/IntegrationTests/Auth/Signer/CacaoSignerTests.swift index 285173cc3..c35cd57d5 100644 --- a/Example/IntegrationTests/Auth/Signer/CacaoSignerTests.swift +++ b/Example/IntegrationTests/Auth/Signer/CacaoSignerTests.swift @@ -1,11 +1,14 @@ import Foundation import XCTest -@testable import Auth +@testable import WalletConnectUtils +@testable import WalletConnectSigner +@testable import WalletConnectSign + class CacaoSignerTest: XCTestCase { let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()) - .create(projectId: InputConfig.projectId) + .create() let verifier = MessageVerifierFactory(crypto: DefaultCryptoProvider()).create(projectId: InputConfig.projectId) let privateKey = Data(hex: "305c6cde3846927892cd32762f6120539f3ec74c9e3a16b9b798b1e85351ae2a") @@ -27,11 +30,11 @@ class CacaoSignerTest: XCTestCase { - https://example.com/my-web2-claim.json """ - let payload = AuthPayload(requestParams: RequestParams( + let payload = try! AuthPayload(requestParams: AuthRequestParams( domain: "service.invalid", - chainId: "eip155:1", + chains: ["eip155:1"], nonce: "32891756", - aud: "https://service.invalid/login", + uri: "https://service.invalid/login", nbf: nil, exp: nil, statement: "I accept the ServiceOrg Terms of Service: https://service.invalid/tos", @@ -39,15 +42,16 @@ class CacaoSignerTest: XCTestCase { resources: [ "ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/", "https://example.com/my-web2-claim.json" - ] + ], + methods: nil ), iat: "2021-09-30T16:25:24Z") let signature = CacaoSignature(t: .eip191, s: "0x2755a5cf4542e8649fadcfca8c983068ef3bda6057550ecd1ead32b75125a4547ed8e91ef76ef17e969434ffa4ac2e4dc1e8cd8be55d342ad9e223c64fbfe1dd1b") func testCacaoSign() throws { - let address = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" - let cacaoPayload = try payload.cacaoPayload(address: address) - let formatted = try SIWECacaoFormatter().formatMessage(from: cacaoPayload) + let account = Account("eip155:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")! + let cacaoPayload = try CacaoPayloadBuilder.makeCacaoPayload(authPayload: payload, account: account) + let formatted = try SIWEFromCacaoPayloadFormatter().formatMessage(from: cacaoPayload) XCTAssertEqual(formatted, message) XCTAssertEqual(try signer.sign(payload: cacaoPayload, privateKey: privateKey, type: .eip191), signature) } diff --git a/Example/IntegrationTests/Auth/Signer/EIP1271VerifierTests.swift b/Example/IntegrationTests/Auth/Signer/EIP1271VerifierTests.swift index 4bf4fba1b..c04236342 100644 --- a/Example/IntegrationTests/Auth/Signer/EIP1271VerifierTests.swift +++ b/Example/IntegrationTests/Auth/Signer/EIP1271VerifierTests.swift @@ -1,6 +1,6 @@ import Foundation import XCTest -@testable import Auth +@testable import WalletConnectUtils @testable import WalletConnectSigner import JSONRPC diff --git a/Example/IntegrationTests/Auth/Signer/EIP191VerifierTests.swift b/Example/IntegrationTests/Auth/Signer/EIP191VerifierTests.swift index ae565315c..9245780b2 100644 --- a/Example/IntegrationTests/Auth/Signer/EIP191VerifierTests.swift +++ b/Example/IntegrationTests/Auth/Signer/EIP191VerifierTests.swift @@ -1,6 +1,5 @@ import Foundation import XCTest -@testable import Auth @testable import WalletConnectSigner class EIP191VerifierTests: XCTestCase { @@ -15,6 +14,8 @@ class EIP191VerifierTests: XCTestCase { try await verifier.verify(signature: signature, message: message, address: address) } + // passes with https://etherscan.io/verifiedSignatures# + // for testing with etherscan remove prefix func testEtherscanSignature() async throws { let address = "0x6721591d424c18b7173d55895efa1839aa57d9c2" let message = "\u{19}Ethereum Signed Message:\n139[Etherscan.io 12/08/2022 09:26:23] I, hereby verify that I am the owner/creator of the address [0x7e77dcb127f99ece88230a64db8d595f31f1b068]".data(using: .utf8)! diff --git a/Example/IntegrationTests/Auth/Signer/SignerTests.swift b/Example/IntegrationTests/Auth/Signer/SignerTests.swift index 8f6381237..1828ff5ee 100644 --- a/Example/IntegrationTests/Auth/Signer/SignerTests.swift +++ b/Example/IntegrationTests/Auth/Signer/SignerTests.swift @@ -1,6 +1,6 @@ import Foundation import XCTest -@testable import Auth +@testable import WalletConnectUtils import WalletConnectRelay class SignerTest: XCTestCase { diff --git a/Example/IntegrationTests/Chat/ChatTests.swift b/Example/IntegrationTests/Chat/ChatTests.swift deleted file mode 100644 index 04cdc7e68..000000000 --- a/Example/IntegrationTests/Chat/ChatTests.swift +++ /dev/null @@ -1,175 +0,0 @@ -import Foundation -import XCTest -@testable import WalletConnectChat -import WalletConnectUtils -@testable import WalletConnectKMS -@testable import WalletConnectSync -@testable import WalletConnectHistory -import WalletConnectRelay -import Combine -import Web3 - -final class ChatTests: XCTestCase { - var invitee1: ChatClient! - var inviter1: ChatClient! - var invitee2: ChatClient! - var inviter2: ChatClient! - private var publishers = [AnyCancellable]() - - var inviteeAccount: Account { - return Account("eip155:1:" + pk1.address.hex(eip55: true))! - } - - var inviterAccount: Account { - return Account("eip155:1:" + pk2.address.hex(eip55: true))! - } - - let pk1 = try! EthereumPrivateKey() - let pk2 = try! EthereumPrivateKey() - - var privateKey1: Data { - return Data(pk1.rawPrivateKey) - } - var privateKey2: Data { - return Data(pk2.rawPrivateKey) - } - - override func setUp() async throws { - invitee1 = makeClient(prefix: "🦖 Invitee", account: inviteeAccount) - inviter1 = makeClient(prefix: "🍄 Inviter", account: inviterAccount) - - try await invitee1.register(account: inviteeAccount, domain: "") { message in - return self.sign(message, privateKey: self.privateKey1) - } - try await inviter1.register(account: inviterAccount, domain: "") { message in - return self.sign(message, privateKey: self.privateKey2) - } - } - - func makeClient(prefix: String, account: Account) -> ChatClient { - let keyserverURL = URL(string: "https://keys.walletconnect.com")! - let logger = ConsoleLogger(prefix: prefix, loggingLevel: .debug) - let keyValueStorage = RuntimeKeyValueStorage() - let keychain = KeychainStorageMock() - let relayClient = RelayClientFactory.create( - relayHost: InputConfig.relayHost, - projectId: InputConfig.projectId, - keyValueStorage: keyValueStorage, - keychainStorage: keychain, - socketFactory: DefaultSocketFactory(), - logger: logger) - - let networkingInteractor = NetworkingClientFactory.create( - relayClient: relayClient, - logger: logger, - keychainStorage: keychain, - keyValueStorage: keyValueStorage) - - let syncClient = SyncClientFactory.create( - networkInteractor: networkingInteractor, - bip44: DefaultBIP44Provider(), - keychain: keychain - ) - - let historyClient = HistoryClientFactory.create( - historyUrl: "https://history.walletconnect.com", - relayUrl: "wss://relay.walletconnect.com", - keyValueStorage: keyValueStorage, - keychain: keychain, - logger: logger - ) - - let clientId = try! networkingInteractor.getClientId() - logger.debug("My client id is: \(clientId)") - - return ChatClientFactory.create(keyserverURL: keyserverURL, relayClient: relayClient, networkingInteractor: networkingInteractor, keychain: keychain, logger: logger, storage: keyValueStorage, syncClient: syncClient, historyClient: historyClient) - } - - func testInvite() async throws { - let inviteExpectation = expectation(description: "invitation expectation") - inviteExpectation.expectedFulfillmentCount = 2 - - invitee1.newReceivedInvitePublisher.sink { _ in - inviteExpectation.fulfill() - }.store(in: &publishers) - - inviter1.newSentInvitePublisher.sink { _ in - inviteExpectation.fulfill() - }.store(in: &publishers) - - let inviteePublicKey = try await inviter1.resolve(account: inviteeAccount) - let invite = Invite(message: "", inviterAccount: inviterAccount, inviteeAccount: inviteeAccount, inviteePublicKey: inviteePublicKey) - _ = try await inviter1.invite(invite: invite) - - wait(for: [inviteExpectation], timeout: InputConfig.defaultTimeout) - } - - func testAcceptAndCreateNewThread() async throws { - let newThreadInviterExpectation = expectation(description: "new thread on inviting client expectation") - let newThreadinviteeExpectation = expectation(description: "new thread on invitee client expectation") - - invitee1.newReceivedInvitePublisher.sink { [unowned self] invite in - Task { try! await invitee1.accept(inviteId: invite.id) } - }.store(in: &publishers) - - invitee1.newThreadPublisher.sink { _ in - newThreadinviteeExpectation.fulfill() - }.store(in: &publishers) - - inviter1.newThreadPublisher.sink { _ in - newThreadInviterExpectation.fulfill() - }.store(in: &publishers) - - let inviteePublicKey = try await inviter1.resolve(account: inviteeAccount) - let invite = Invite(message: "", inviterAccount: inviterAccount, inviteeAccount: inviteeAccount, inviteePublicKey: inviteePublicKey) - try await inviter1.invite(invite: invite) - - wait(for: [newThreadinviteeExpectation, newThreadInviterExpectation], timeout: InputConfig.defaultTimeout) - } - - func testMessage() async throws { - let messageExpectation = expectation(description: "message received") - messageExpectation.expectedFulfillmentCount = 4 - - invitee1.newReceivedInvitePublisher.sink { [unowned self] invite in - Task { try! await invitee1.accept(inviteId: invite.id) } - }.store(in: &publishers) - - invitee1.newThreadPublisher.sink { [unowned self] thread in - Task { try! await invitee1.message(topic: thread.topic, message: "message1") } - }.store(in: &publishers) - - inviter1.newThreadPublisher.sink { [unowned self] thread in - Task { try! await inviter1.message(topic: thread.topic, message: "message2") } - }.store(in: &publishers) - - inviter1.newMessagePublisher.sink { message in - if message.authorAccount == self.inviterAccount { - XCTAssertEqual(message.message, "message2") - } else { - XCTAssertEqual(message.message, "message1") - } - messageExpectation.fulfill() - }.store(in: &publishers) - - invitee1.newMessagePublisher.sink { message in - if message.authorAccount == self.inviteeAccount { - XCTAssertEqual(message.message, "message1") - } else { - XCTAssertEqual(message.message, "message2") - } - messageExpectation.fulfill() - }.store(in: &publishers) - - let inviteePublicKey = try await inviter1.resolve(account: inviteeAccount) - let invite = Invite(message: "", inviterAccount: inviterAccount, inviteeAccount: inviteeAccount, inviteePublicKey: inviteePublicKey) - try await inviter1.invite(invite: invite) - - wait(for: [messageExpectation], timeout: InputConfig.defaultTimeout) - } - - private func sign(_ message: String, privateKey: Data) -> SigningResult { - let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create(projectId: InputConfig.projectId) - return .signed(try! signer.sign(message: message, privateKey: privateKey, type: .eip191)) - } -} diff --git a/Example/IntegrationTests/Chat/RegistryTests.swift b/Example/IntegrationTests/Chat/RegistryTests.swift deleted file mode 100644 index a6de83f9e..000000000 --- a/Example/IntegrationTests/Chat/RegistryTests.swift +++ /dev/null @@ -1,64 +0,0 @@ -import XCTest -import WalletConnectNetworking -import WalletConnectKMS -import WalletConnectUtils -@testable import WalletConnectChat -@testable import WalletConnectIdentity - -final class RegistryTests: XCTestCase { - - let account = Account("eip155:1:0x15bca56b6e2728aec2532df9d436bd1600e86688")! - let privateKey = Data(hex: "305c6cde3846927892cd32762f6120539f3ec74c9e3a16b9b798b1e85351ae2a") - - var sut: IdentityService! - var storage: IdentityStorage! - var signer: MessageSigner! - - override func setUp() { - let keyserverURL = URL(string: "https://keys.walletconnect.com")! - let httpService = HTTPNetworkClient(host: keyserverURL.host!) - let identityNetworkService = IdentityNetworkService(httpService: httpService) - let keychain = KeychainStorageMock() - let ksm = KeyManagementService(keychain: keychain) - storage = IdentityStorage(keychain: keychain) - sut = IdentityService ( - keyserverURL: keyserverURL, - kms: ksm, - storage: storage, - networkService: identityNetworkService, - iatProvader: DefaultIATProvider(), - messageFormatter: SIWECacaoFormatter() - ) - signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create(projectId: InputConfig.projectId) - } - -// func testRegisterIdentityAndInviteKey() async throws { -// let publicKey = try await sut.registerIdentity(account: account, onSign: onSign) -// -// let iss = DIDKey(rawData: Data(hex: publicKey)).did(variant: .ED25519) -// let resolvedAccount = try await sut.resolveIdentity(iss: iss) -// XCTAssertEqual(resolvedAccount, account) -// -// let recovered = try storage.getIdentityKey(for: account).publicKey.hexRepresentation -// XCTAssertEqual(publicKey, recovered) -// -// let inviteKey = try await sut.registerInvite(account: account) -// -// let recoveredKey = try storage.getInviteKey(for: account) -// XCTAssertEqual(inviteKey, recoveredKey) -// -// let resolvedKey = try await sut.resolveInvite(account: account) -// XCTAssertEqual(inviteKey.did, resolvedKey) -// -// _ = try await sut.goPrivate(account: account) -// try await sut.unregister(account: account, onSign: onSign) -// } -} - -private extension RegistryTests { - - func onSign(_ message: String) -> SigningResult { - let signature = try! signer.sign(message: message, privateKey: privateKey, type: .eip191) - return .signed(signature) - } -} diff --git a/Example/IntegrationTests/History/HistoryTests.swift b/Example/IntegrationTests/History/HistoryTests.swift deleted file mode 100644 index d96e0f811..000000000 --- a/Example/IntegrationTests/History/HistoryTests.swift +++ /dev/null @@ -1,81 +0,0 @@ -import Foundation -import Combine -import XCTest -@testable import WalletConnectHistory - -final class HistoryTests: XCTestCase { - - var publishers = Set() - - let relayUrl = "wss://relay.walletconnect.com" - let historyUrl = "https://history.walletconnect.com" - - var relayClient1: RelayClient! - var relayClient2: RelayClient! - - var historyClient: HistoryNetworkService! - - override func setUp() { - let keychain1 = KeychainStorageMock() - let keychain2 = KeychainStorageMock() - let logger1 = ConsoleLoggerMock() - let defaults1 = RuntimeKeyValueStorage() - relayClient1 = makeRelayClient(prefix: "🐄", keychain: keychain1) - relayClient2 = makeRelayClient(prefix: "🐫", keychain: keychain2) - historyClient = makeHistoryClient(defaults: defaults1, keychain: keychain1, logger: logger1) - } - - private func makeRelayClient(prefix: String, keychain: KeychainStorageProtocol) -> RelayClient { - return RelayClientFactory.create( - relayHost: InputConfig.relayHost, - projectId: InputConfig.projectId, - keyValueStorage: RuntimeKeyValueStorage(), - keychainStorage: keychain, - socketFactory: DefaultSocketFactory(), - logger: ConsoleLogger(prefix: prefix + " [Relay]", loggingLevel: .debug)) - } - - private func makeHistoryClient(defaults: KeyValueStorage, keychain: KeychainStorageProtocol, logger: ConsoleLogging) -> HistoryNetworkService { - let clientIdStorage = ClientIdStorage(defaults: defaults, keychain: keychain, logger: logger) - return HistoryNetworkService(clientIdStorage: clientIdStorage) - } - - func testRegister() async throws { - let payload = RegisterPayload(tags: ["7000"], relayUrl: relayUrl) - - try await historyClient.registerTags(payload: payload, historyUrl: historyUrl) - } - - func testGetMessages() async throws { - let exp = expectation(description: "Test Get Messages") - let tag = 7000 - let payload = "{}" - let agreement = AgreementPrivateKey() - let topic = agreement.publicKey.rawRepresentation.sha256().hex - - relayClient2.messagePublisher.sink { (topic, message, publishedAt) in - exp.fulfill() - }.store(in: &publishers) - - try await historyClient.registerTags( - payload: RegisterPayload(tags: [String(tag)], relayUrl: relayUrl), - historyUrl: historyUrl) - - try await relayClient2.subscribe(topic: topic) - try await relayClient1.publish(topic: topic, payload: payload, tag: tag, prompt: false, ttl: 3000) - - wait(for: [exp], timeout: InputConfig.defaultTimeout) - - sleep(5) // History server has a queue - - let messages = try await historyClient.getMessages( - payload: GetMessagesPayload( - topic: topic, - originId: nil, - messageCount: 200, - direction: .forward), - historyUrl: historyUrl) - - XCTAssertEqual(messages.messages, [payload]) - } -} diff --git a/Example/IntegrationTests/Pairing/PairingTests.swift b/Example/IntegrationTests/Pairing/PairingTests.swift deleted file mode 100644 index bbea6aa46..000000000 --- a/Example/IntegrationTests/Pairing/PairingTests.swift +++ /dev/null @@ -1,147 +0,0 @@ -import Foundation -import XCTest -@testable import WalletConnectUtils -@testable import WalletConnectKMS -import WalletConnectRelay -import Combine -import WalletConnectNetworking -import WalletConnectPush -@testable import Auth -@testable import WalletConnectPairing -@testable import WalletConnectSync -@testable import WalletConnectHistory - -final class PairingTests: XCTestCase { - - var appPairingClient: PairingClient! - var walletPairingClient: PairingClient! - - var appAuthClient: AuthClient! - var walletAuthClient: AuthClient! - - var pairingStorage: PairingStorage! - - private var publishers = [AnyCancellable]() - - func makeClientDependencies(prefix: String) -> (PairingClient, NetworkingInteractor, KeychainStorageProtocol, KeyValueStorage) { - let keychain = KeychainStorageMock() - let keyValueStorage = RuntimeKeyValueStorage() - - let relayLogger = ConsoleLogger(prefix: prefix + " [Relay]", loggingLevel: .debug) - let pairingLogger = ConsoleLogger(prefix: prefix + " [Pairing]", loggingLevel: .debug) - let networkingLogger = ConsoleLogger(prefix: prefix + " [Networking]", loggingLevel: .debug) - - let relayClient = RelayClientFactory.create( - relayHost: InputConfig.relayHost, - projectId: InputConfig.projectId, - keyValueStorage: RuntimeKeyValueStorage(), - keychainStorage: keychain, - socketFactory: DefaultSocketFactory(), - logger: relayLogger) - - let networkingClient = NetworkingClientFactory.create( - relayClient: relayClient, - logger: networkingLogger, - keychainStorage: keychain, - keyValueStorage: keyValueStorage) - - let pairingClient = PairingClientFactory.create( - logger: pairingLogger, - keyValueStorage: keyValueStorage, - keychainStorage: keychain, - networkingClient: networkingClient) - let clientId = try! networkingClient.getClientId() - networkingLogger.debug("My client id is: \(clientId)") - - return (pairingClient, networkingClient, keychain, keyValueStorage) - } - - func makeDappClients() { - let prefix = "🤖 Dapp: " - let (pairingClient, networkingInteractor, keychain, keyValueStorage) = makeClientDependencies(prefix: prefix) - let notifyLogger = ConsoleLogger(prefix: prefix + " [Notify]", loggingLevel: .debug) - appPairingClient = pairingClient - - appAuthClient = AuthClientFactory.create( - metadata: AppMetadata(name: name, description: "", url: "", icons: [""], redirect: AppMetadata.Redirect(native: "wcdapp://", universal: nil)), - projectId: InputConfig.projectId, - crypto: DefaultCryptoProvider(), - logger: notifyLogger, - keyValueStorage: keyValueStorage, - keychainStorage: keychain, - networkingClient: networkingInteractor, - pairingRegisterer: pairingClient, - iatProvider: IATProviderMock()) - } - - func makeWalletClients() { - let prefix = "🐶 Wallet: " - let (pairingClient, networkingInteractor, keychain, keyValueStorage) = makeClientDependencies(prefix: prefix) - let notifyLogger = ConsoleLogger(prefix: prefix + " [Notify]", loggingLevel: .debug) - let defaults = RuntimeKeyValueStorage() - walletPairingClient = pairingClient - let historyClient = HistoryClientFactory.create( - historyUrl: "https://history.walletconnect.com", - relayUrl: "wss://relay.walletconnect.com", - keyValueStorage: defaults, - keychain: keychain, - logger: notifyLogger - ) - appAuthClient = AuthClientFactory.create( - metadata: AppMetadata(name: name, description: "", url: "", icons: [""], redirect: AppMetadata.Redirect(native: "", universal: nil)), - projectId: InputConfig.projectId, - crypto: DefaultCryptoProvider(), - logger: notifyLogger, - keyValueStorage: keyValueStorage, - keychainStorage: keychain, - networkingClient: networkingInteractor, - pairingRegisterer: pairingClient, - iatProvider: IATProviderMock()) - } - - func makeWalletPairingClient() { - let prefix = "🐶 Wallet: " - let (pairingClient, _, _, _) = makeClientDependencies(prefix: prefix) - walletPairingClient = pairingClient - } - - override func setUp() { - makeDappClients() - } - - func testPing() async { - let expectation = expectation(description: "expects ping response") - makeWalletClients() - let uri = try! await appPairingClient.create() - try? await walletPairingClient.pair(uri: uri) - try! await walletPairingClient.ping(topic: uri.topic) - walletPairingClient.pingResponsePublisher - .sink { topic in - XCTAssertEqual(topic, uri.topic) - expectation.fulfill() - }.store(in: &publishers) - wait(for: [expectation], timeout: InputConfig.defaultTimeout) - } - - func testResponseErrorForMethodUnregistered() async { - makeWalletPairingClient() - let expectation = expectation(description: "wallet responds unsupported method for unregistered method") - - appAuthClient.authResponsePublisher.sink { (_, response) in - XCTAssertEqual(response, .failure(AuthError(code: 10001)!)) - expectation.fulfill() - }.store(in: &publishers) - - let uri = try! await appPairingClient.create() - - try? await walletPairingClient.pair(uri: uri) - - try! await appAuthClient.request(RequestParams.stub(), topic: uri.topic) - - wait(for: [expectation], timeout: InputConfig.defaultTimeout) - } - - func testDisconnect() { - // TODO - } -} diff --git a/Example/IntegrationTests/Push/NotifyTests.swift b/Example/IntegrationTests/Push/NotifyTests.swift index 108ba3e37..2b08baca7 100644 --- a/Example/IntegrationTests/Push/NotifyTests.swift +++ b/Example/IntegrationTests/Push/NotifyTests.swift @@ -1,3 +1,4 @@ + import Foundation import XCTest import WalletConnectUtils @@ -8,7 +9,6 @@ import Combine import WalletConnectNetworking import WalletConnectPush @testable import WalletConnectNotify -@testable import WalletConnectPairing import WalletConnectIdentity import WalletConnectSigner @@ -30,12 +30,11 @@ final class NotifyTests: XCTestCase { private var publishers = Set() - func makeClientDependencies(prefix: String) -> (PairingClient, NetworkInteracting, KeychainStorageProtocol, KeyValueStorage) { + func makeClientDependencies(prefix: String) -> (NetworkInteracting, KeychainStorageProtocol, KeyValueStorage) { let keychain = KeychainStorageMock() let keyValueStorage = RuntimeKeyValueStorage() let relayLogger = ConsoleLogger(prefix: prefix + " [Relay]", loggingLevel: .debug) - let pairingLogger = ConsoleLogger(prefix: prefix + " [Pairing]", loggingLevel: .debug) let networkingLogger = ConsoleLogger(prefix: prefix + " [Networking]", loggingLevel: .debug) let kmsLogger = ConsoleLogger(prefix: prefix + " [KMS]", loggingLevel: .debug) @@ -45,6 +44,7 @@ final class NotifyTests: XCTestCase { keyValueStorage: keyValueStorage, keychainStorage: keychain, socketFactory: DefaultSocketFactory(), + networkMonitor: NetworkMonitor(), logger: relayLogger) let networkingClient = NetworkingClientFactory.create( @@ -54,19 +54,13 @@ final class NotifyTests: XCTestCase { keyValueStorage: keyValueStorage, kmsLogger: kmsLogger) - let pairingClient = PairingClientFactory.create( - logger: pairingLogger, - keyValueStorage: keyValueStorage, - keychainStorage: keychain, - networkingClient: networkingClient) - let clientId = try! networkingClient.getClientId() networkingLogger.debug("My client id is: \(clientId)") - return (pairingClient, networkingClient, keychain, keyValueStorage) + return (networkingClient, keychain, keyValueStorage) } func makeWalletClient(prefix: String = "🦋 Wallet: ") -> NotifyClient { - let (pairingClient, networkingInteractor, keychain, keyValueStorage) = makeClientDependencies(prefix: prefix) + let (networkingInteractor, keychain, keyValueStorage) = makeClientDependencies(prefix: prefix) let notifyLogger = ConsoleLogger(prefix: prefix + " [Notify]", loggingLevel: .debug) let pushClient = PushClientFactory.create(projectId: "", pushHost: "echo.walletconnect.com", @@ -80,11 +74,9 @@ final class NotifyTests: XCTestCase { keyserverURL: keyserverURL, sqlite: sqlite, logger: notifyLogger, - keyValueStorage: keyValueStorage, keychainStorage: keychain, groupKeychainStorage: KeychainStorageMock(), networkInteractor: networkingInteractor, - pairingRegisterer: pairingClient, pushClient: pushClient, crypto: DefaultCryptoProvider(), notifyHost: InputConfig.notifyHost, @@ -165,7 +157,7 @@ final class NotifyTests: XCTestCase { try await clientB.deleteSubscription(topic: subscription.topic) } } - + func testWalletCreatesAndUpdatesSubscription() async throws { let created = expectation(description: "Subscription created") @@ -193,13 +185,12 @@ final class NotifyTests: XCTestCase { await fulfillment(of: [created], timeout: InputConfig.defaultTimeout) - let updateScope = Set([subscription.scope.keys.first!]) - try await walletNotifyClientA.update(topic: subscription.topic, scope: updateScope) + try await walletNotifyClientA.update(topic: subscription.topic, scope: []) await fulfillment(of: [updated], timeout: InputConfig.defaultTimeout) - let updatedScope = Set(subscription.scope.filter { $0.value.enabled == true }.keys) - XCTAssertEqual(updatedScope, updateScope) + let updatedScope = subscription.scope.filter { $0.value.enabled == true } + XCTAssertTrue(updatedScope.isEmpty) try await walletNotifyClientA.deleteSubscription(topic: subscription.topic) } @@ -255,12 +246,45 @@ 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() + 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) + } } private extension NotifyTests { - func sign(_ message: String) -> SigningResult { - let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create(projectId: InputConfig.projectId) - return .signed(try! signer.sign(message: message, privateKey: privateKey, type: .eip191)) + func sign(_ message: String) -> CacaoSignature { + let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create() + return try! signer.sign(message: message, privateKey: privateKey, type: .eip191) } } + +private extension NotifyClient { + + func register(account: Account, domain: String, onSign: @escaping (String) -> CacaoSignature) async throws { + let params = try await prepareRegistration(account: account, domain: "https://\(domain)") + let signature = onSign(params.message) + try await register(params: params, signature: signature) + } +} + diff --git a/Example/IntegrationTests/Sign/SignClientTests.swift b/Example/IntegrationTests/Sign/SignClientTests.swift index 4cecd7bb0..3274ea31c 100644 --- a/Example/IntegrationTests/Sign/SignClientTests.swift +++ b/Example/IntegrationTests/Sign/SignClientTests.swift @@ -4,6 +4,7 @@ import JSONRPC @testable import WalletConnectKMS @testable import WalletConnectSign @testable import WalletConnectRelay +@testable import WalletConnectUtils import WalletConnectPairing import WalletConnectNetworking import Combine @@ -13,10 +14,17 @@ final class SignClientTests: XCTestCase { var dappPairingClient: PairingClient! var wallet: SignClient! var walletPairingClient: PairingClient! + var dappKeyValueStorage: RuntimeKeyValueStorage! + var dappRelayClient: RelayClient! + var walletRelayClient: RelayClient! private var publishers = Set() + let walletAccount = Account(chainIdentifier: "eip155:1", address: "0x724d0D2DaD3fbB0C168f947B87Fa5DBe36F1A8bf")! + let prvKey = Data(hex: "462c1dad6832d7d96ccf87bd6a686a4110e114aaaebd5512e552c0e3a87b480f") + let eip1271Signature = "0xdeaddeaddead4095116db01baaf276361efd3a73c28cf8cc28dabefa945b8d536011289ac0a3b048600c1e692ff173ca944246cf7ceb319ac2262d27b395c82b1c" + let walletLinkModeUniversalLink = "https://test" - static private func makeClients(name: String) -> (PairingClient, SignClient) { + static private func makeClients(name: String, linkModeUniversalLink: String? = "https://x.com", supportLinkMode: Bool = false) -> (PairingClient, SignClient, RuntimeKeyValueStorage, RelayClient) { let logger = ConsoleLogger(prefix: name, loggingLevel: .debug) let keychain = KeychainStorageMock() let keyValueStorage = RuntimeKeyValueStorage() @@ -26,6 +34,7 @@ final class SignClientTests: XCTestCase { keyValueStorage: keyValueStorage, keychainStorage: keychain, socketFactory: DefaultSocketFactory(), + networkMonitor: NetworkMonitor(), logger: logger ) @@ -39,31 +48,50 @@ final class SignClientTests: XCTestCase { logger: logger, keyValueStorage: keyValueStorage, keychainStorage: keychain, - networkingClient: networkingClient + networkingClient: networkingClient, + eventsClient: MockEventsClient() ) + let metadata = AppMetadata(name: name, description: "", url: "", icons: [""], redirect: try! AppMetadata.Redirect(native: "", universal: linkModeUniversalLink, linkMode: supportLinkMode)) + let client = SignClientFactory.create( - metadata: AppMetadata(name: name, description: "", url: "", icons: [""], redirect: AppMetadata.Redirect(native: "", universal: nil)), + metadata: metadata, logger: logger, keyValueStorage: keyValueStorage, keychainStorage: keychain, pairingClient: pairingClient, - networkingClient: networkingClient + networkingClient: networkingClient, + iatProvider: IATProviderMock(), + projectId: InputConfig.projectId, + crypto: DefaultCryptoProvider(), + eventsClient: MockEventsClient() ) let clientId = try! networkingClient.getClientId() logger.debug("My client id is: \(clientId)") - return (pairingClient, client) + return (pairingClient, client, keyValueStorage, relayClient) } override func setUp() async throws { - (dappPairingClient, dapp) = Self.makeClients(name: "🍏P") - (walletPairingClient, wallet) = Self.makeClients(name: "🍎R") + (dappPairingClient, dapp, dappKeyValueStorage, dappRelayClient) = Self.makeClients(name: "🍏Dapp") + (walletPairingClient, wallet, _, walletRelayClient) = Self.makeClients(name: "🍎Wallet", linkModeUniversalLink: walletLinkModeUniversalLink) + } + + func setUpDappForLinkMode() async throws { + try await tearDown() + (dappPairingClient, dapp, dappKeyValueStorage, dappRelayClient) = Self.makeClients(name: "🍏Dapp", supportLinkMode: true) + (walletPairingClient, wallet, _, walletRelayClient) = Self.makeClients(name: "🍎Wallet", linkModeUniversalLink: walletLinkModeUniversalLink, supportLinkMode: true) } override func tearDown() { + // Synchronously wait for 0.1 seconds + Thread.sleep(forTimeInterval: 0.1) + + // Now set properties to nil dapp = nil wallet = nil + + super.tearDown() // Ensure superclass tearDown is called } func testSessionPropose() async throws { @@ -75,7 +103,7 @@ final class SignClientTests: XCTestCase { wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in Task(priority: .high) { do { - try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) + _ = try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { XCTFail("\(error)") } @@ -84,14 +112,13 @@ final class SignClientTests: XCTestCase { dapp.sessionSettlePublisher.sink { _ in dappSettlementExpectation.fulfill() }.store(in: &publishers) - dapp.sessionSettlePublisher.sink { _ in + wallet.sessionSettlePublisher.sink { _ in walletSettlementExpectation.fulfill() }.store(in: &publishers) - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces) try await walletPairingClient.pair(uri: uri) - wait(for: [dappSettlementExpectation, walletSettlementExpectation], timeout: InputConfig.defaultTimeout) + await fulfillment(of: [dappSettlementExpectation, walletSettlementExpectation], timeout: InputConfig.defaultTimeout) } func testSessionReject() async throws { @@ -100,24 +127,26 @@ final class SignClientTests: XCTestCase { class Store { var rejectedProposal: Session.Proposal? } let store = Store() + let semaphore = DispatchSemaphore(value: 0) - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces) try await walletPairingClient.pair(uri: uri) 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.rejectSession(proposalId: proposal.id, reason: .unsupportedChains) store.rejectedProposal = proposal + semaphore.signal() } catch { XCTFail("\(error)") } } }.store(in: &publishers) dapp.sessionRejectionPublisher.sink { proposal, _ in + semaphore.wait() XCTAssertEqual(store.rejectedProposal, proposal) - sessionRejectExpectation.fulfill() // TODO: Assert reason code + sessionRejectExpectation.fulfill() }.store(in: &publishers) - wait(for: [sessionRejectExpectation], timeout: InputConfig.defaultTimeout) + await fulfillment(of: [sessionRejectExpectation], timeout: InputConfig.defaultTimeout) } func testSessionDelete() async throws { @@ -127,7 +156,7 @@ final class SignClientTests: XCTestCase { wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in Task(priority: .high) { - do { try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { XCTFail("\(error)") } + do { _ = try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { XCTFail("\(error)") } } }.store(in: &publishers) dapp.sessionSettlePublisher.sink { [unowned self] settledSession in @@ -139,10 +168,9 @@ final class SignClientTests: XCTestCase { sessionDeleteExpectation.fulfill() }.store(in: &publishers) - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces) try await walletPairingClient.pair(uri: uri) - wait(for: [sessionDeleteExpectation], timeout: InputConfig.defaultTimeout) + await fulfillment(of: [sessionDeleteExpectation], timeout: InputConfig.defaultTimeout) } func testSessionPing() async throws { @@ -169,11 +197,11 @@ final class SignClientTests: XCTestCase { expectation.fulfill() }.store(in: &publishers) - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces) + try await walletPairingClient.pair(uri: uri) - wait(for: [expectation], timeout: InputConfig.defaultTimeout) + await fulfillment(of: [expectation], timeout: InputConfig.defaultTimeout) } func testSessionRequest() async throws { @@ -186,18 +214,20 @@ final class SignClientTests: XCTestCase { let requestParams = [EthSendTransaction.stub()] let responseParams = "0xdeadbeef" let chain = Blockchain("eip155:1")! - + + // sleep is needed as emitRequestIfPending() will be called on client init and then on request itself, second request would be debouced + sleep(1) wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in Task(priority: .high) { do { - try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { + _ = try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { XCTFail("\(error)") } } }.store(in: &publishers) dapp.sessionSettlePublisher.sink { [unowned self] settledSession in Task(priority: .high) { - let request = Request(id: RPCID(0), topic: settledSession.topic, method: requestMethod, params: requestParams, chainId: chain, expiry: nil) + let request = try! Request(id: RPCID(0), topic: settledSession.topic, method: requestMethod, params: requestParams, chainId: chain) try await dapp.request(params: request) } }.store(in: &publishers) @@ -220,10 +250,10 @@ final class SignClientTests: XCTestCase { responseExpectation.fulfill() }.store(in: &publishers) - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces) + try await walletPairingClient.pair(uri: uri) - wait(for: [requestExpectation, responseExpectation], timeout: InputConfig.defaultTimeout) + await fulfillment(of: [requestExpectation, responseExpectation], timeout: InputConfig.defaultTimeout) } func testSessionRequestFailureResponse() async throws { @@ -237,6 +267,8 @@ final class SignClientTests: XCTestCase { let chain = Blockchain("eip155:1")! + // sleep is needed as emitRequestIfPending() will be called on client init and then on request itself, second request would be debouced + sleep(1) wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in Task(priority: .high) { try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) @@ -244,7 +276,7 @@ final class SignClientTests: XCTestCase { }.store(in: &publishers) dapp.sessionSettlePublisher.sink { [unowned self] settledSession in Task(priority: .high) { - let request = Request(id: RPCID(0), topic: settledSession.topic, method: requestMethod, params: requestParams, chainId: chain, expiry: nil) + let request = try! Request(id: RPCID(0), topic: settledSession.topic, method: requestMethod, params: requestParams, chainId: chain) try await dapp.request(params: request) } }.store(in: &publishers) @@ -263,48 +295,10 @@ final class SignClientTests: XCTestCase { expectation.fulfill() }.store(in: &publishers) - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, topic: uri.topic) - try await walletPairingClient.pair(uri: uri) - wait(for: [expectation], timeout: InputConfig.defaultTimeout) - } - - func testNewSessionOnExistingPairing() async throws { - let dappSettlementExpectation = expectation(description: "Dapp settles session") - dappSettlementExpectation.expectedFulfillmentCount = 2 - let walletSettlementExpectation = expectation(description: "Wallet settles session") - walletSettlementExpectation.expectedFulfillmentCount = 2 - let requiredNamespaces = ProposalNamespace.stubRequired() - let sessionNamespaces = SessionNamespace.make(toRespond: requiredNamespaces) - var initiatedSecondSession = false + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces) - wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in - Task(priority: .high) { - do { - try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) - } catch { - XCTFail("\(error)") - } - } - }.store(in: &publishers) - dapp.sessionSettlePublisher.sink { [unowned self] _ in - dappSettlementExpectation.fulfill() - let pairingTopic = dappPairingClient.getPairings().first!.topic - if !initiatedSecondSession { - Task(priority: .high) { - _ = try! await dapp.connect(requiredNamespaces: requiredNamespaces, topic: pairingTopic) - } - initiatedSecondSession = true - } - }.store(in: &publishers) - wallet.sessionSettlePublisher.sink { _ in - walletSettlementExpectation.fulfill() - }.store(in: &publishers) - - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, topic: uri.topic) try await walletPairingClient.pair(uri: uri) - wait(for: [dappSettlementExpectation, walletSettlementExpectation], timeout: InputConfig.defaultTimeout) + await fulfillment(of: [expectation], timeout: InputConfig.defaultTimeout) } func testSuccessfulSessionUpdateNamespaces() async throws { @@ -319,16 +313,20 @@ final class SignClientTests: XCTestCase { }.store(in: &publishers) dapp.sessionSettlePublisher.sink { [unowned self] settledSession in Task(priority: .high) { - try! await wallet.update(topic: settledSession.topic, namespaces: sessionNamespaces) + let updateNamespace = SessionNamespace.make( + toRespond: ProposalNamespace.stubRequired(chains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!]) + ) + try! await wallet.update(topic: settledSession.topic, namespaces: updateNamespace) } }.store(in: &publishers) - dapp.sessionUpdatePublisher.sink { _, _ in + dapp.sessionUpdatePublisher.sink { _, namespace in + XCTAssertEqual(namespace.values.first?.accounts.count, 2) expectation.fulfill() }.store(in: &publishers) - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces) + try await walletPairingClient.pair(uri: uri) - wait(for: [expectation], timeout: InputConfig.defaultTimeout) + await fulfillment(of: [expectation], timeout: InputConfig.defaultTimeout) } func testSuccessfulSessionExtend() async throws { @@ -353,11 +351,11 @@ final class SignClientTests: XCTestCase { } }.store(in: &publishers) - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces) + try await walletPairingClient.pair(uri: uri) - wait(for: [expectation], timeout: InputConfig.defaultTimeout) + await fulfillment(of: [expectation], timeout: InputConfig.defaultTimeout) } func testSessionEventSucceeds() async throws { @@ -384,11 +382,11 @@ final class SignClientTests: XCTestCase { } }.store(in: &publishers) - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces) + try await walletPairingClient.pair(uri: uri) - wait(for: [expectation], timeout: InputConfig.defaultTimeout) + await fulfillment(of: [expectation], timeout: InputConfig.defaultTimeout) } func testSessionEventFails() async throws { @@ -412,11 +410,11 @@ final class SignClientTests: XCTestCase { } }.store(in: &publishers) - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces) + try await walletPairingClient.pair(uri: uri) - wait(for: [expectation], timeout: InputConfig.defaultTimeout) + await fulfillment(of: [expectation], timeout: InputConfig.defaultTimeout) } func testCaip25SatisfyAllRequiredAllOptionalNamespacesSuccessful() async throws { @@ -441,7 +439,7 @@ final class SignClientTests: XCTestCase { events: ["any"] ), "solana": ProposalNamespace( - chains: [Blockchain("solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ")!], + chains: [Blockchain("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp")!], methods: ["solana_signMessage"], events: ["any"] ) @@ -454,7 +452,7 @@ final class SignClientTests: XCTestCase { requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces, sessionProperties: nil, - proposal: SessionProposal(relays: [], proposer: Participant(publicKey: "", metadata: AppMetadata(name: "", description: "", url: "", icons: [], redirect: AppMetadata.Redirect(native: "", universal: nil))), requiredNamespaces: [:], optionalNamespaces: [:], sessionProperties: [:]) + proposal: SessionProposal(relays: [], proposer: Participant(publicKey: "", metadata: AppMetadata.stub()), requiredNamespaces: [:], optionalNamespaces: [:], sessionProperties: [:]) ) let sessionNamespaces = try AutoNamespaces.build( @@ -463,12 +461,12 @@ final class SignClientTests: XCTestCase { Blockchain("eip155:137")!, Blockchain("eip155:1")!, Blockchain("eip155:5")!, - Blockchain("solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ")! + Blockchain("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp")! ], methods: ["personal_sign", "eth_sendTransaction", "solana_signMessage"], events: ["any"], accounts: [ - Account(blockchain: Blockchain("solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ")!, address: "4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ")!, + Account(blockchain: Blockchain("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp")!, address: "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp")!, Account(blockchain: Blockchain("eip155:1")!, address: "0x00")!, Account(blockchain: Blockchain("eip155:137")!, address: "0x00")!, Account(blockchain: Blockchain("eip155:5")!, address: "0x00")! @@ -478,7 +476,7 @@ final class SignClientTests: XCTestCase { wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in Task(priority: .high) { do { - try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) + _ = try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { XCTFail("\(error)") } @@ -491,10 +489,9 @@ final class SignClientTests: XCTestCase { walletSettlementExpectation.fulfill() }.store(in: &publishers) - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces) try await walletPairingClient.pair(uri: uri) - wait(for: [dappSettlementExpectation, walletSettlementExpectation], timeout: InputConfig.defaultTimeout) + await fulfillment(of: [dappSettlementExpectation, walletSettlementExpectation], timeout: InputConfig.defaultTimeout) } func testCaip25SatisfyAllRequiredNamespacesSuccessful() async throws { @@ -523,11 +520,11 @@ final class SignClientTests: XCTestCase { let sessionProposal = Session.Proposal( id: "", pairingTopic: "", - proposer: AppMetadata(name: "", description: "", url: "", icons: [], redirect: AppMetadata.Redirect(native: "", universal: nil)), + proposer: AppMetadata.stub(), requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces, sessionProperties: nil, - proposal: SessionProposal(relays: [], proposer: Participant(publicKey: "", metadata: AppMetadata(name: "", description: "", url: "", icons: [], redirect: AppMetadata.Redirect(native: "", universal: nil))), requiredNamespaces: [:], optionalNamespaces: [:], sessionProperties: [:]) + proposal: SessionProposal(relays: [], proposer: Participant(publicKey: "", metadata: AppMetadata.stub()), requiredNamespaces: [:], optionalNamespaces: [:], sessionProperties: [:]) ) let sessionNamespaces = try AutoNamespaces.build( @@ -547,23 +544,23 @@ final class SignClientTests: XCTestCase { wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in Task(priority: .high) { do { - try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) + _ = try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { XCTFail("\(error)") } } }.store(in: &publishers) - dapp.sessionSettlePublisher.sink { [unowned self] _ in + dapp.sessionSettlePublisher.sink { _ in dappSettlementExpectation.fulfill() }.store(in: &publishers) wallet.sessionSettlePublisher.sink { _ in walletSettlementExpectation.fulfill() }.store(in: &publishers) - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces) + try await walletPairingClient.pair(uri: uri) - wait(for: [dappSettlementExpectation, walletSettlementExpectation], timeout: InputConfig.defaultTimeout) + await fulfillment(of: [dappSettlementExpectation, walletSettlementExpectation], timeout: InputConfig.defaultTimeout) } func testCaip25SatisfyEmptyRequiredNamespacesExtraOptionalNamespacesSuccessful() async throws { @@ -582,11 +579,11 @@ final class SignClientTests: XCTestCase { let sessionProposal = Session.Proposal( id: "", pairingTopic: "", - proposer: AppMetadata(name: "", description: "", url: "", icons: [], redirect: AppMetadata.Redirect(native: "", universal: nil)), + proposer: AppMetadata.stub(), requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces, sessionProperties: nil, - proposal: SessionProposal(relays: [], proposer: Participant(publicKey: "", metadata: AppMetadata(name: "", description: "", url: "", icons: [], redirect: AppMetadata.Redirect(native: "", universal: nil))), requiredNamespaces: [:], optionalNamespaces: [:], sessionProperties: [:]) + proposal: SessionProposal(relays: [], proposer: Participant(publicKey: "", metadata: AppMetadata.stub()), requiredNamespaces: [:], optionalNamespaces: [:], sessionProperties: [:]) ) let sessionNamespaces = try AutoNamespaces.build( @@ -606,7 +603,7 @@ final class SignClientTests: XCTestCase { wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in Task(priority: .high) { do { - try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) + _ = try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { XCTFail("\(error)") } @@ -619,10 +616,10 @@ final class SignClientTests: XCTestCase { walletSettlementExpectation.fulfill() }.store(in: &publishers) - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces) + try await walletPairingClient.pair(uri: uri) - wait(for: [dappSettlementExpectation, walletSettlementExpectation], timeout: InputConfig.defaultTimeout) + await fulfillment(of: [dappSettlementExpectation, walletSettlementExpectation], timeout: InputConfig.defaultTimeout) } func testCaip25SatisfyPartiallyRequiredNamespacesFails() async throws { @@ -649,11 +646,11 @@ final class SignClientTests: XCTestCase { let sessionProposal = Session.Proposal( id: "", pairingTopic: "", - proposer: AppMetadata(name: "", description: "", url: "", icons: [], redirect: AppMetadata.Redirect(native: "", universal: nil)), + proposer: AppMetadata.stub(), requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces, sessionProperties: nil, - proposal: SessionProposal(relays: [], proposer: Participant(publicKey: "", metadata: AppMetadata(name: "", description: "", url: "", icons: [], redirect: AppMetadata.Redirect(native: "", universal: nil))), requiredNamespaces: [:], optionalNamespaces: [:], sessionProperties: [:]) + proposal: SessionProposal(relays: [], proposer: Participant(publicKey: "", metadata: AppMetadata.stub()), requiredNamespaces: [:], optionalNamespaces: [:], sessionProperties: [:]) ) do { @@ -672,7 +669,7 @@ final class SignClientTests: XCTestCase { wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in Task(priority: .high) { do { - try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) + _ = try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { settlementFailedExpectation.fulfill() } @@ -682,10 +679,10 @@ final class SignClientTests: XCTestCase { settlementFailedExpectation.fulfill() } - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces) + try await walletPairingClient.pair(uri: uri) - wait(for: [settlementFailedExpectation], timeout: 1) + await fulfillment(of: [settlementFailedExpectation], timeout: InputConfig.defaultTimeout) } func testCaip25SatisfyPartiallyRequiredNamespacesMethodsFails() async throws { @@ -713,11 +710,11 @@ final class SignClientTests: XCTestCase { let sessionProposal = Session.Proposal( id: "", pairingTopic: "", - proposer: AppMetadata(name: "", description: "", url: "", icons: [], redirect: AppMetadata.Redirect(native: "", universal: nil)), + proposer: AppMetadata.stub(), requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces, sessionProperties: nil, - proposal: SessionProposal(relays: [], proposer: Participant(publicKey: "", metadata: AppMetadata(name: "", description: "", url: "", icons: [], redirect: AppMetadata.Redirect(native: "", universal: nil))), requiredNamespaces: [:], optionalNamespaces: [:], sessionProperties: [:]) + proposal: SessionProposal(relays: [], proposer: Participant(publicKey: "", metadata: AppMetadata.stub()), requiredNamespaces: [:], optionalNamespaces: [:], sessionProperties: [:]) ) do { @@ -738,7 +735,7 @@ final class SignClientTests: XCTestCase { wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in Task(priority: .high) { do { - try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) + _ = try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { settlementFailedExpectation.fulfill() } @@ -748,9 +745,643 @@ final class SignClientTests: XCTestCase { settlementFailedExpectation.fulfill() } - let uri = try! await dappPairingClient.create() - try await dapp.connect(requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces, topic: uri.topic) + let uri = try! await dapp.connect(requiredNamespaces: requiredNamespaces, optionalNamespaces: optionalNamespaces) + + try await walletPairingClient.pair(uri: uri) + await fulfillment(of: [settlementFailedExpectation], timeout: 1) + } + + + func testEIP191SessionAuthenticated() async throws { + let responseExpectation = expectation(description: "successful response delivered") + + wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in + Task(priority: .high) { + let signerFactory = DefaultSignerFactory() + let signer = MessageSignerFactory(signerFactory: signerFactory).create() + + let supportedAuthPayload = try! wallet.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!], supportedMethods: ["eth_signTransaction", "personal_sign"]) + + let siweMessage = try! wallet.formatAuthMessage(payload: supportedAuthPayload, account: walletAccount) + + let signature = try signer.sign( + message: siweMessage, + privateKey: prvKey, + type: .eip191) + + let auth = try wallet.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: signature, account: walletAccount) + + _ = try! await wallet.approveSessionAuthenticate(requestId: request.id, auths: [auth]) + } + } + .store(in: &publishers) + dapp.authResponsePublisher.sink { (_, result) in + guard case .success = result else { XCTFail(); return } + responseExpectation.fulfill() + } + .store(in: &publishers) + + + let uri = try await dapp.authenticate(AuthRequestParams.stub())! + try await walletPairingClient.pair(uri: uri) + await fulfillment(of: [responseExpectation], timeout: InputConfig.defaultTimeout) + } + + func testEIP191SessionAuthenticateEmptyMethods() async throws { + let responseExpectation = expectation(description: "successful response delivered") + + wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in + Task(priority: .high) { + let signerFactory = DefaultSignerFactory() + let signer = MessageSignerFactory(signerFactory: signerFactory).create() + + let supportedAuthPayload = try! wallet.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!], supportedMethods: ["eth_signTransaction", "personal_sign"]) + + let siweMessage = try! wallet.formatAuthMessage(payload: supportedAuthPayload, account: walletAccount) + + let signature = try signer.sign( + message: siweMessage, + privateKey: prvKey, + type: .eip191) + + let auth = try wallet.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: signature, account: walletAccount) + + _ = try! await wallet.approveSessionAuthenticate(requestId: request.id, auths: [auth]) + } + } + .store(in: &publishers) + dapp.authResponsePublisher.sink { (_, result) in + guard case .success = result else { XCTFail(); return } + responseExpectation.fulfill() + } + .store(in: &publishers) + + + let uri = try await dapp.authenticate(AuthRequestParams.stub(methods: nil))! + try await walletPairingClient.pair(uri: uri) + await fulfillment(of: [responseExpectation], timeout: InputConfig.defaultTimeout) + } + + func testEIP191SessionAuthenticatedMultiCacao() async throws { + let responseExpectation = expectation(description: "successful response delivered") + + wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in + Task(priority: .high) { + let signerFactory = DefaultSignerFactory() + let signer = MessageSignerFactory(signerFactory: signerFactory).create() + + var cacaos = [Cacao]() + + request.payload.chains.forEach { chain in + + let account = Account(blockchain: Blockchain(chain)!, address: walletAccount.address)! + + let supportedAuthPayload = try! wallet.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!], supportedMethods: ["eth_sendTransaction", "personal_sign"]) + + let siweMessage = try! wallet.formatAuthMessage(payload: supportedAuthPayload, account: account) + + let signature = try! signer.sign( + message: siweMessage, + privateKey: prvKey, + type: .eip191) + + let cacao = try! wallet.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: signature, account: account) + cacaos.append(cacao) + + } + _ = try! await wallet.approveSessionAuthenticate(requestId: request.id, auths: cacaos) + } + } + .store(in: &publishers) + dapp.authResponsePublisher.sink { (_, result) in + guard case .success(let (session, _)) = result, + let session = session else { XCTFail(); return } + XCTAssertEqual(session.accounts.count, 2) + XCTAssertEqual(session.namespaces["eip155"]?.methods.count, 2) + XCTAssertEqual(session.namespaces["eip155"]?.accounts.count, 2) + responseExpectation.fulfill() + } + .store(in: &publishers) + + + let uri = try await dapp.authenticate(AuthRequestParams.stub(chains: ["eip155:1", "eip155:137"]))! + try await walletPairingClient.pair(uri: uri) + await fulfillment(of: [responseExpectation], timeout: InputConfig.defaultTimeout) + } + + func testEIP1271SessionAuthenticated() async throws { + + let account = Account(chainIdentifier: "eip155:1", address: "0x6DF3d14554742D67068BB7294C80107a3c655A56")! + let eip1271Signature = "0xb518b65724f224f8b12dedeeb06f8b278eb7d3b42524959bed5d0dfa49801bd776c7ee05de396eadc38ee693c917a04d93b20981d68c4a950cbc42ea7f4264bc1c" + + let responseExpectation = expectation(description: "successful response delivered") + let uri = try! await dapp.authenticate(AuthRequestParams( + domain: "etherscan.io", + chains: ["eip155:1"], + nonce: "DTYxeNr95Ne7Sape5", + uri: "https://etherscan.io/verifiedSignatures#", + nbf: nil, + exp: nil, + statement: "Sign message to verify ownership of the address 0x6DF3d14554742D67068BB7294C80107a3c655A56 on etherscan.io", + requestId: nil, + resources: nil, + methods: nil + ))! + try await walletPairingClient.pair(uri: uri) - wait(for: [settlementFailedExpectation], timeout: 1) + + wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in + Task(priority: .high) { + let signature = CacaoSignature(t: .eip1271, s: eip1271Signature) + let cacao = try! wallet.buildSignedAuthObject(authPayload: request.payload, signature: signature, account: account) + _ = try await wallet.approveSessionAuthenticate(requestId: request.id, auths: [cacao]) + } + } + .store(in: &publishers) + dapp.authResponsePublisher.sink { (_, result) in + guard case .success = result else { XCTFail(); return } + responseExpectation.fulfill() + } + .store(in: &publishers) + await fulfillment(of: [responseExpectation], timeout: InputConfig.defaultTimeout) } + + func testEIP191SessionAuthenticateSignatureVerificationFailed() async { + let requestExpectation = expectation(description: "error response delivered") + let uri = try! await dapp.authenticate(AuthRequestParams.stub())! + + try? await walletPairingClient.pair(uri: uri) + wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in + Task(priority: .high) { + let invalidSignature = CacaoSignature(t: .eip1271, s: eip1271Signature) + + + let supportedAuthPayload = try! wallet.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!], supportedMethods: ["eth_signTransaction", "personal_sign"]) + + let cacao = try! wallet.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: invalidSignature, account: walletAccount) + + await XCTAssertThrowsErrorAsync(try await wallet.approveSessionAuthenticate(requestId: request.id, auths: [cacao])) + requestExpectation.fulfill() + } + } + .store(in: &publishers) + await fulfillment(of: [requestExpectation], timeout: InputConfig.defaultTimeout) + } + + func testSessionAuthenticateUserRespondError() async { + let responseExpectation = expectation(description: "error response delivered") + let uri = try! await dapp.authenticate(AuthRequestParams.stub())! + + try? await walletPairingClient.pair(uri: uri) + wallet.authenticateRequestPublisher.sink { [unowned self] request in + Task(priority: .high) { + try! await wallet.rejectSession(requestId: request.0.id) + } + } + .store(in: &publishers) + dapp.authResponsePublisher.sink { (_, result) in + guard case .failure(let error) = result else { XCTFail(); return } + XCTAssertEqual(error, .userRejeted) + responseExpectation.fulfill() + } + .store(in: &publishers) + await fulfillment(of: [responseExpectation], timeout: InputConfig.defaultTimeout) + } + + func testSessionRequestOnAuthenticatedSession() async throws { + let requestExpectation = expectation(description: "Wallet expects to receive a request") + let responseExpectation = expectation(description: "Dapp expects to receive a response") + + let requestMethod = "eth_sendTransaction" + let requestParams = [EthSendTransaction.stub()] + let responseParams = "0xdeadbeef" + let chain = Blockchain("eip155:1")! + // sleep is needed as emitRequestIfPending() will be called on client init and then on request itself, second request would be debouced + sleep(1) + wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in + Task(priority: .high) { + let signerFactory = DefaultSignerFactory() + let signer = MessageSignerFactory(signerFactory: signerFactory).create() + + let supportedAuthPayload = try! wallet.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!], supportedMethods: ["eth_sendTransaction", "personal_sign"]) + + let siweMessage = try! wallet.formatAuthMessage(payload: supportedAuthPayload, account: walletAccount) + + let signature = try! signer.sign( + message: siweMessage, + privateKey: prvKey, + type: .eip191) + + let cacao = try! wallet.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: signature, account: walletAccount) + + _ = try! await wallet.approveSessionAuthenticate(requestId: request.id, auths: [cacao]) + } + } + .store(in: &publishers) + dapp.authResponsePublisher.sink { [unowned self] (_, result) in + guard case .success(let (session, _)) = result, + let session = session else { XCTFail(); return } + Task(priority: .high) { + let request = try Request(id: RPCID(0), topic: session.topic, method: requestMethod, params: requestParams, chainId: Blockchain("eip155:1")!) + try await dapp.request(params: request) + } + } + .store(in: &publishers) + + wallet.sessionRequestPublisher.sink { [unowned self] (sessionRequest, _) in + let receivedParams = try! sessionRequest.params.get([EthSendTransaction].self) + XCTAssertEqual(receivedParams, requestParams) + XCTAssertEqual(sessionRequest.method, requestMethod) + requestExpectation.fulfill() + Task(priority: .high) { + try await wallet.respond(topic: sessionRequest.topic, requestId: sessionRequest.id, response: .response(AnyCodable(responseParams))) + } + }.store(in: &publishers) + + dapp.sessionResponsePublisher.sink { response in + switch response.result { + case .response(let response): + XCTAssertEqual(try! response.get(String.self), responseParams) + case .error: + XCTFail() + } + responseExpectation.fulfill() + }.store(in: &publishers) + + + let uri = try await dapp.authenticate(AuthRequestParams.stub())! + + try await walletPairingClient.pair(uri: uri) + await fulfillment(of: [requestExpectation, responseExpectation], timeout: InputConfig.defaultTimeout) + } + + + func testSessionRequestOnAuthenticatedSessionForAChainNotIncludedInCacao() async throws { + let requestExpectation = expectation(description: "Wallet expects to receive a request") + let responseExpectation = expectation(description: "Dapp expects to receive a response") + + let requestMethod = "eth_sendTransaction" + let requestParams = [EthSendTransaction.stub()] + let responseParams = "0xdeadbeef" + let chain = Blockchain("eip155:1")! + // sleep is needed as emitRequestIfPending() will be called on client init and then on request itself, second request would be debouced + sleep(1) + wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in + Task(priority: .high) { + let signerFactory = DefaultSignerFactory() + let signer = MessageSignerFactory(signerFactory: signerFactory).create() + + let supportedAuthPayload = try! wallet.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!], supportedMethods: ["eth_sendTransaction", "personal_sign"]) + + let signingAccount = Account(chainIdentifier: "eip155:1", address: "0x724d0D2DaD3fbB0C168f947B87Fa5DBe36F1A8bf")! + let siweMessage = try! wallet.formatAuthMessage(payload: supportedAuthPayload, account: signingAccount) + + let signature = try! signer.sign( + message: siweMessage, + privateKey: prvKey, + type: .eip191) + + let cacao = try! wallet.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: signature, account: walletAccount) + + _ = try! await wallet.approveSessionAuthenticate(requestId: request.id, auths: [cacao]) + } + } + .store(in: &publishers) + dapp.authResponsePublisher.sink { [unowned self] (_, result) in + guard case .success(let (session, _)) = result, + let session = session else { XCTFail(); return } + Task(priority: .high) { + let request = try Request(id: RPCID(0), topic: session.topic, method: requestMethod, params: requestParams, chainId: Blockchain("eip155:137")!) + try await dapp.request(params: request) + } + } + .store(in: &publishers) + + wallet.sessionRequestPublisher.sink { [unowned self] (sessionRequest, _) in + let receivedParams = try! sessionRequest.params.get([EthSendTransaction].self) + XCTAssertEqual(receivedParams, requestParams) + XCTAssertEqual(sessionRequest.method, requestMethod) + requestExpectation.fulfill() + Task(priority: .high) { + try await wallet.respond(topic: sessionRequest.topic, requestId: sessionRequest.id, response: .response(AnyCodable(responseParams))) + } + }.store(in: &publishers) + + dapp.sessionResponsePublisher.sink { response in + switch response.result { + case .response(let response): + XCTAssertEqual(try! response.get(String.self), responseParams) + case .error: + XCTFail() + } + responseExpectation.fulfill() + }.store(in: &publishers) + + + let uri = try await dapp.authenticate(AuthRequestParams.stub(chains: ["eip155:1", "eip155:137"]))! + + try await walletPairingClient.pair(uri: uri) + await fulfillment(of: [requestExpectation, responseExpectation], timeout: InputConfig.defaultTimeout) + } + + func testFalbackForm_2_5_DappToSessionProposeOnWallet() async throws { + + let fallbackExpectation = expectation(description: "fallback to wc_sessionPropose") + let requiredNamespaces = ProposalNamespace.stubRequired() + let sessionNamespaces = SessionNamespace.make(toRespond: requiredNamespaces) + + + wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in + Task(priority: .high) { + do { _ = try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { XCTFail("\(error)") } + } + }.store(in: &publishers) + + dapp.sessionSettlePublisher.sink { settledSession in + Task(priority: .high) { + fallbackExpectation.fulfill() + } + }.store(in: &publishers) + + let uri = try await dapp.authenticate(AuthRequestParams.stub())! + let uriStringWithoutMethods = uri.absoluteString.replacingOccurrences(of: "&methods=wc_sessionAuthenticate", with: "") + let uriWithoutMethods = try WalletConnectURI(uriString: uriStringWithoutMethods) + try await walletPairingClient.pair(uri: uriWithoutMethods) + await fulfillment(of: [fallbackExpectation], timeout: InputConfig.defaultTimeout) + } + + + func testFallbackToSessionProposeIfWalletIsNotSubscribingSessionAuthenticate() async throws { + + let responseExpectation = expectation(description: "successful response delivered") + + let requiredNamespaces = ProposalNamespace.stubRequired() + let sessionNamespaces = SessionNamespace.make(toRespond: requiredNamespaces) + + wallet.sessionProposalPublisher.sink { [unowned self] (proposal, _) in + Task(priority: .high) { + do { _ = try await wallet.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { XCTFail("\(error)") } + } + }.store(in: &publishers) + + dapp.sessionSettlePublisher.sink { settledSession in + Task(priority: .high) { + responseExpectation.fulfill() + } + }.store(in: &publishers) + + let uri = try await dapp.authenticate(AuthRequestParams.stub())! + try await walletPairingClient.pair(uri: uri) + await fulfillment(of: [responseExpectation], timeout: InputConfig.defaultTimeout) + } + + // Link Mode + + func testLinkAuthRequest() async throws { + try await setUpDappForLinkMode() + dappRelayClient.blockPublishing = true + walletRelayClient.blockPublishing = true + + let responseExpectation = expectation(description: "successful response delivered") + + // Set Wallet's universal link in dapp storage to mock wallet proof on link mode support + let walletUniversalLink = "https://test" + let dappLinkModeLinksStore = CodableStore(defaults: dappKeyValueStorage, identifier: SignStorageIdentifiers.linkModeLinks.rawValue) + dappLinkModeLinksStore.set(true, forKey: walletUniversalLink) + + wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in + Task(priority: .high) { + let signerFactory = DefaultSignerFactory() + let signer = MessageSignerFactory(signerFactory: signerFactory).create() + + let supportedAuthPayload = try! wallet.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!], supportedMethods: ["eth_signTransaction", "personal_sign"]) + + let siweMessage = try! wallet.formatAuthMessage(payload: supportedAuthPayload, account: walletAccount) + + let signature = try signer.sign( + message: siweMessage, + privateKey: prvKey, + type: .eip191) + + let auth = try wallet.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: signature, account: walletAccount) + + let (_, approveEnvelope) = try! await wallet.approveSessionAuthenticateLinkMode(requestId: request.id, auths: [auth]) + try dapp.dispatchEnvelope(approveEnvelope) + } + } + .store(in: &publishers) + dapp.authResponsePublisher.sink { (_, result) in + guard case .success = result else { XCTFail(); return } + responseExpectation.fulfill() + } + .store(in: &publishers) + + + let requestEnvelope = try await dapp.authenticateLinkMode(AuthRequestParams.stub(), walletUniversalLink: walletUniversalLink) + try wallet.dispatchEnvelope(requestEnvelope) + await fulfillment(of: [responseExpectation], timeout: InputConfig.defaultTimeout) + } + + func testLinkSessionRequest() async throws { + try await setUpDappForLinkMode() + dappRelayClient.blockPublishing = true + walletRelayClient.blockPublishing = true + let requestExpectation = expectation(description: "Wallet expects to receive a request") + let responseExpectation = expectation(description: "Dapp expects to receive a response") + + let requestMethod = "personal_sign" + let requestParams = [EthSendTransaction.stub()] + let responseParams = "0xdeadbeef" + + let semaphore = DispatchSemaphore(value: 0) + + // Set Wallet's universal link in dapp storage to mock wallet proof on link mode support + let walletUniversalLink = "https://test" + let dappLinkModeLinksStore = CodableStore(defaults: dappKeyValueStorage, identifier: SignStorageIdentifiers.linkModeLinks.rawValue) + dappLinkModeLinksStore.set(true, forKey: walletUniversalLink) + + wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in + Task(priority: .high) { + let signerFactory = DefaultSignerFactory() + let signer = MessageSignerFactory(signerFactory: signerFactory).create() + + let supportedAuthPayload = try! wallet.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!], supportedMethods: ["eth_signTransaction", "personal_sign"]) + + let siweMessage = try! wallet.formatAuthMessage(payload: supportedAuthPayload, account: walletAccount) + + let signature = try signer.sign( + message: siweMessage, + privateKey: prvKey, + type: .eip191) + + let auth = try wallet.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: signature, account: walletAccount) + + let (_, approveEnvelope) = try! await wallet.approveSessionAuthenticateLinkMode(requestId: request.id, auths: [auth]) + try dapp.dispatchEnvelope(approveEnvelope) + semaphore.signal() + } + } + .store(in: &publishers) + dapp.authResponsePublisher.sink { [unowned self] (_, result) in + semaphore.wait() + guard case .success(let (session, _)) = result, + let session = session else { XCTFail(); return } + Task(priority: .high) { + let request = try! Request(id: RPCID(0), topic: session.topic, method: requestMethod, params: requestParams, chainId: Blockchain("eip155:1")!) + let requestEnvelope = try! await dapp.requestLinkMode(params: request)! + try! wallet.dispatchEnvelope(requestEnvelope) + semaphore.signal() + } + } + .store(in: &publishers) + + wallet.sessionRequestPublisher.sink { [unowned self] (sessionRequest, _) in + semaphore.wait() + let receivedParams = try! sessionRequest.params.get([EthSendTransaction].self) + XCTAssertEqual(receivedParams, requestParams) + XCTAssertEqual(sessionRequest.method, requestMethod) + requestExpectation.fulfill() + Task(priority: .high) { + let envelope = try! await wallet.respondLinkMode(topic: sessionRequest.topic, requestId: sessionRequest.id, response: .response(AnyCodable(responseParams)))! + try! dapp.dispatchEnvelope(envelope) + } + semaphore.signal() + }.store(in: &publishers) + + dapp.sessionResponsePublisher.sink { response in + semaphore.wait() + switch response.result { + case .response(let response): + XCTAssertEqual(try! response.get(String.self), responseParams) + case .error: + XCTFail() + } + responseExpectation.fulfill() + }.store(in: &publishers) + + let requestEnvelope = try await dapp.authenticateLinkMode(AuthRequestParams.stub(), walletUniversalLink: walletUniversalLink) + try wallet.dispatchEnvelope(requestEnvelope) + + await fulfillment(of: [requestExpectation, responseExpectation], timeout: InputConfig.defaultTimeout) + } + + func testLinkModeFailsWhenDappDoesNotHaveProofThatWalletSupportsLinkMode() async throws { + // ensure link mode fails before the upgrade + do { + try await self.dapp.authenticateLinkMode(AuthRequestParams.stub(), walletUniversalLink: self.walletLinkModeUniversalLink) + XCTFail("Expected error but got success.") + } catch { + if let authError = error as? LinkAuthRequester.Errors, authError == .walletLinkSupportNotProven { + } else { + XCTFail("Unexpected error: \(error)") + } + } + } + + func testUpgradeFromRelayToLinkMode() async throws { + try await setUpDappForLinkMode() + + let linkModeUpgradeExpectation = expectation(description: "successful upgraded to link mode") + wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in + Task(priority: .high) { + let signerFactory = DefaultSignerFactory() + let signer = MessageSignerFactory(signerFactory: signerFactory).create() + + let supportedAuthPayload = try! wallet.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!], supportedMethods: ["eth_signTransaction", "personal_sign"]) + + let siweMessage = try! wallet.formatAuthMessage(payload: supportedAuthPayload, account: walletAccount) + + let signature = try signer.sign( + message: siweMessage, + privateKey: prvKey, + type: .eip191) + + let auth = try wallet.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: signature, account: walletAccount) + + _ = try! await wallet.approveSessionAuthenticate(requestId: request.id, auths: [auth]) + walletRelayClient.blockPublishing = true + } + } + .store(in: &publishers) + dapp.authResponsePublisher.sink { [unowned self] (_, result) in + dappRelayClient.blockPublishing = true + guard case .success = result else { XCTFail(); return } + + + Task { [unowned self] in + try! await self.dapp.authenticateLinkMode(AuthRequestParams.stub(), walletUniversalLink: self.walletLinkModeUniversalLink) + linkModeUpgradeExpectation.fulfill() + } + } + .store(in: &publishers) + + + let uri = try await dapp.authenticate(AuthRequestParams.stub(), walletUniversalLink: walletLinkModeUniversalLink)! + try await walletPairingClient.pair(uri: uri) + await fulfillment(of: [linkModeUpgradeExpectation], timeout: InputConfig.defaultTimeout) + } + + func testUpgradeSessionToLinkModeAndSendRequestOverLinkMode() async throws { + + try await setUpDappForLinkMode() + let requestMethod = "personal_sign" + let requestParams = [EthSendTransaction.stub()] + let sessionResponseOnLinkModeExpectation = expectation(description: "Dapp expects to receive a response") + + let responseParams = "0xdeadbeef" + let semaphore = DispatchSemaphore(value: 0) + + wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in + + Task(priority: .high) { + let signerFactory = DefaultSignerFactory() + let signer = MessageSignerFactory(signerFactory: signerFactory).create() + + let supportedAuthPayload = try! wallet.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!], supportedMethods: ["eth_signTransaction", "personal_sign"]) + + let siweMessage = try! wallet.formatAuthMessage(payload: supportedAuthPayload, account: walletAccount) + + let signature = try signer.sign( + message: siweMessage, + privateKey: prvKey, + type: .eip191) + + let auth = try wallet.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: signature, account: walletAccount) + + _ = try! await wallet.approveSessionAuthenticate(requestId: request.id, auths: [auth]) + semaphore.signal() + } + } + .store(in: &publishers) + dapp.authResponsePublisher.sink { [unowned self] (_, result) in + semaphore.wait() + dappRelayClient.blockPublishing = true + walletRelayClient.blockPublishing = true + guard case .success(let (session, _)) = result, + let session = session else { XCTFail(); return } + + Task { [unowned self] in + let request = try! Request(id: RPCID(0), topic: session.topic, method: requestMethod, params: requestParams, chainId: Blockchain("eip155:1")!) + let requestEnvelope = try! await self.dapp.requestLinkMode(params: request)! + try! self.wallet.dispatchEnvelope(requestEnvelope) + } + } + .store(in: &publishers) + + wallet.sessionRequestPublisher.sink { [unowned self] (sessionRequest, _) in + Task(priority: .high) { + let envelope = try! await wallet.respondLinkMode(topic: sessionRequest.topic, requestId: sessionRequest.id, response: .response(AnyCodable(responseParams)))! + try! dapp.dispatchEnvelope(envelope) + } + }.store(in: &publishers) + + dapp.sessionResponsePublisher.sink { response in + sessionResponseOnLinkModeExpectation.fulfill() + }.store(in: &publishers) + + let uri = try await dapp.authenticate(AuthRequestParams.stub(), walletUniversalLink: walletLinkModeUniversalLink)! + try await walletPairingClient.pair(uri: uri) + await fulfillment(of: [sessionResponseOnLinkModeExpectation], timeout: InputConfig.defaultTimeout) + } + } diff --git a/Example/IntegrationTests/Stubs/PushMessage.swift b/Example/IntegrationTests/Stubs/PushMessage.swift index 634d78ea1..68d08b36e 100644 --- a/Example/IntegrationTests/Stubs/PushMessage.swift +++ b/Example/IntegrationTests/Stubs/PushMessage.swift @@ -9,6 +9,7 @@ extension NotifyMessage { body: "body", icon: "https://images.unsplash.com/photo-1581224463294-908316338239?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=250&q=80", url: "https://web3inbox.com", - type: type) + type: type, + sentAt: Date()) } } diff --git a/Example/IntegrationTests/Stubs/RequestParams.swift b/Example/IntegrationTests/Stubs/RequestParams.swift index 5c1a30db4..457c9300b 100644 --- a/Example/IntegrationTests/Stubs/RequestParams.swift +++ b/Example/IntegrationTests/Stubs/RequestParams.swift @@ -1,24 +1,24 @@ -import Foundation -@testable import Auth - -extension RequestParams { - static func stub(domain: String = "service.invalid", - chainId: String = "eip155:1", - nonce: String = "32891756", - aud: String = "https://service.invalid/login", - nbf: String? = nil, - exp: String? = nil, - statement: String? = "I accept the ServiceOrg Terms of Service: https://service.invalid/tos", - requestId: String? = nil, - resources: [String]? = ["ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/", "https://example.com/my-web2-claim.json"]) -> RequestParams { - return RequestParams(domain: domain, - chainId: chainId, - nonce: nonce, - aud: aud, - nbf: nbf, - exp: exp, - statement: statement, - requestId: requestId, - resources: resources) - } -} +//import Foundation +//@testable import WalletConnectUtils +// +//extension RequestParams { +// static func stub(domain: String = "service.invalid", +// chainId: String = "eip155:1", +// nonce: String = "32891756", +// aud: String = "https://service.invalid/login", +// nbf: String? = nil, +// exp: String? = nil, +// statement: String? = "I accept the ServiceOrg Terms of Service: https://service.invalid/tos", +// requestId: String? = nil, +// resources: [String]? = ["ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/", "https://example.com/my-web2-claim.json"]) -> RequestParams { +// return RequestParams(domain: domain, +// chainId: chainId, +// nonce: nonce, +// aud: aud, +// nbf: nbf, +// exp: exp, +// statement: statement, +// requestId: requestId, +// resources: resources) +// } +//} diff --git a/Example/IntegrationTests/Stubs/Stubs.swift b/Example/IntegrationTests/Stubs/Stubs.swift index 366d8970f..ec330c0b8 100644 --- a/Example/IntegrationTests/Stubs/Stubs.swift +++ b/Example/IntegrationTests/Stubs/Stubs.swift @@ -1,10 +1,10 @@ import WalletConnectSign extension ProposalNamespace { - static func stubRequired() -> [String: ProposalNamespace] { + static func stubRequired(chains: [Blockchain] = [Blockchain("eip155:1")!]) -> [String: ProposalNamespace] { return [ "eip155": ProposalNamespace( - chains: [Blockchain("eip155:1")!], + chains: chains, methods: ["personal_sign", "eth_sendTransaction"], events: ["any"]) ] @@ -15,7 +15,7 @@ extension SessionNamespace { static func make(toRespond namespaces: [String: ProposalNamespace]) -> [String: SessionNamespace] { return namespaces.mapValues { proposalNamespace in SessionNamespace( - accounts: Set(proposalNamespace.chains!.map { Account(blockchain: $0, address: "0x00")! }), + accounts: proposalNamespace.chains!.map { Account(blockchain: $0, address: "0x00")! }, methods: proposalNamespace.methods, events: proposalNamespace.events ) @@ -30,7 +30,7 @@ extension AppMetadata { description: "WalletConnectSwift", url: "https://walletconnect.com", icons: [], - redirect: AppMetadata.Redirect(native: "wcdapp://", universal: nil) + redirect: try! AppMetadata.Redirect(native: "wcdapp://", universal: nil) ) } } diff --git a/Example/IntegrationTests/Sync/SyncDerivationServiceTests.swift b/Example/IntegrationTests/Sync/SyncDerivationServiceTests.swift deleted file mode 100644 index 549ed6929..000000000 --- a/Example/IntegrationTests/Sync/SyncDerivationServiceTests.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Foundation -import XCTest -@testable import WalletConnectSync -@testable import WalletConnectSigner - -class SyncDerivationServiceTests: XCTestCase { - - func testDerivation() throws { - let account = Account("eip155:1:0x1FF34C90a0850Fe7227fcFA642688b9712477482")! - let signature = "0xc91265eadb1473d90f8d49d31b7016feb7f7761a2a986ca2146a4b8964f3357569869680154927596a5829ceea925f4196b8a853a29c2c1d5915832fc9f1c6a01c" - let keychain = KeychainStorageMock() - let syncStorage = SyncSignatureStore(keychain: keychain) - let kms = KeyManagementService(keychain: keychain) - let derivationService = SyncDerivationService( - syncStorage: syncStorage, - bip44: DefaultBIP44Provider(), - kms: kms - ) - - try syncStorage.saveSignature(signature, for: account) - - let topic = try derivationService.deriveTopic(account: account, store: "my-user-profile") - - XCTAssertEqual(topic, "741f8902d339c4c16f33fa598a6598b63e5ed125d761374511b2e06562b033eb") - } -} diff --git a/Example/IntegrationTests/Sync/SyncTests.swift b/Example/IntegrationTests/Sync/SyncTests.swift deleted file mode 100644 index adcfdc532..000000000 --- a/Example/IntegrationTests/Sync/SyncTests.swift +++ /dev/null @@ -1,160 +0,0 @@ -import Foundation -import Combine -import XCTest -import Web3 -@testable import WalletConnectSync -@testable import WalletConnectSigner - -final class SyncTests: XCTestCase { - - struct TestObject: DatabaseObject { - let id: String - let value: String - - var databaseId: String { - return id - } - } - - var publishers = Set() - - var client1: SyncClient! - var client2: SyncClient! - - var indexStore1: SyncIndexStore! - var indexStore2: SyncIndexStore! - - var syncStore1: SyncStore! - var syncStore2: SyncStore! - - var signer: MessageSigner! - - let storeName = "SyncTests_store" - - var account: Account { - return Account("eip155:1:" + pk.address.hex(eip55: true))! - } - - let pk = try! EthereumPrivateKey() - - var privateKey: Data { - return Data(pk.rawPrivateKey) - } - - override func setUp() async throws { - indexStore1 = makeIndexStore() - indexStore2 = makeIndexStore() - client1 = makeClient(indexStore: indexStore1, suffix: "❤️") - client2 = makeClient(indexStore: indexStore2, suffix: "💜") - syncStore1 = makeSyncStore(client: client1, indexStore: indexStore1) - syncStore2 = makeSyncStore(client: client2, indexStore: indexStore2) - signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create(projectId: InputConfig.projectId) - } - - func makeClient(indexStore: SyncIndexStore, suffix: String) -> SyncClient { - let syncSignatureStore = SyncSignatureStore(keychain: KeychainStorageMock()) - let keychain = KeychainStorageMock() - let kms = KeyManagementService(keychain: keychain) - let derivationService = SyncDerivationService(syncStorage: syncSignatureStore, bip44: DefaultBIP44Provider(), kms: kms) - let logger = ConsoleLogger(prefix: suffix, loggingLevel: .debug) - let relayClient = RelayClientFactory.create( - relayHost: InputConfig.relayHost, - projectId: InputConfig.projectId, - keyValueStorage: RuntimeKeyValueStorage(), - keychainStorage: keychain, - socketFactory: DefaultSocketFactory(), - logger: logger) - let networkingInteractor = NetworkingClientFactory.create( - relayClient: relayClient, - logger: logger, - keychainStorage: keychain, - keyValueStorage: RuntimeKeyValueStorage()) - let historyStore = CodableStore(defaults: RuntimeKeyValueStorage(), identifier: "historyStore") - let syncHistoryStore = SyncHistoryStore(store: historyStore) - let syncService = SyncService(networkInteractor: networkingInteractor, derivationService: derivationService, signatureStore: syncSignatureStore, indexStore: indexStore, historyStore: syncHistoryStore, logger: logger) - return SyncClient(syncService: syncService, syncSignatureStore: syncSignatureStore) - } - - func makeIndexStore() -> SyncIndexStore { - let store = CodableStore(defaults: RuntimeKeyValueStorage(), identifier: "indexStore") - return SyncIndexStore(store: store) - } - - func makeSyncStore(client: SyncClient, indexStore: SyncIndexStore) -> SyncStore { - let objectStore = KeyedDatabase(storage: RuntimeKeyValueStorage(), identifier: "objectStore") - return SyncStore(name: storeName, syncClient: client, indexStore: indexStore, objectStore: objectStore) - } - - func testSync() async throws { - let setExpectation = expectation(description: "syncSetTest") - let delExpectation = expectation(description: "syncDelTest") - let uptExpectation = expectation(description: "syncUptTest") - - let object = TestObject(id: "id-1", value: "value-1") - let updated = TestObject(id: "id-1", value: "value-2") - - syncStore1.syncUpdatePublisher.sink { (_, _, update) in - switch update { - case .set: - XCTFail() - case .delete: - delExpectation.fulfill() - case .update: - XCTFail() - } - }.store(in: &publishers) - - syncStore2.syncUpdatePublisher.sink { (_, _, update) in - switch update { - case .set: - setExpectation.fulfill() - case .delete: - XCTFail() - case .update: - uptExpectation.fulfill() - } - }.store(in: &publishers) - - // Configure clients - - try await registerClient(client: client1) - try await registerClient(client: client2) - - // Testing SyncStore `set` - - try await syncStore1.set(object: object, for: account) - - wait(for: [setExpectation], timeout: InputConfig.defaultTimeout) - - XCTAssertEqual(try syncStore1.getAll(for: account), [object]) - XCTAssertEqual(try syncStore2.getAll(for: account), [object]) - - // Testing SyncStore `update` - - try await syncStore1.set(object: updated, for: account) - - wait(for: [uptExpectation], timeout: InputConfig.defaultTimeout) - - XCTAssertEqual(try syncStore1.getAll(for: account), [updated]) - XCTAssertEqual(try syncStore2.getAll(for: account), [updated]) - - // Testing SyncStore `delete` - - try await syncStore2.delete(id: object.id, for: account) - - wait(for: [delExpectation], timeout: InputConfig.defaultTimeout) - - XCTAssertEqual(try syncStore1.getAll(for: account), []) - XCTAssertEqual(try syncStore2.getAll(for: account), []) - } - - private func registerClient(client: SyncClient) async throws { - let message = client.getMessage(account: account) - - let signature = try signer.sign(message: message, privateKey: privateKey, type: .eip191) - - try await client.register(account: account, signature: signature) - try await client.create(account: account, store: storeName) - try await client.subscribe(account: account, store: storeName) - } -} diff --git a/Example/IntegrationTests/XPlatform/Web3Wallet/XPlatformW3WTests.swift b/Example/IntegrationTests/XPlatform/Web3Wallet/XPlatformW3WTests.swift index 3d794d18a..712cd36fb 100644 --- a/Example/IntegrationTests/XPlatform/Web3Wallet/XPlatformW3WTests.swift +++ b/Example/IntegrationTests/XPlatform/Web3Wallet/XPlatformW3WTests.swift @@ -1,13 +1,12 @@ import Foundation import XCTest import Combine -@testable import Web3Wallet -@testable import Auth +@testable import ReownWalletKit @testable import WalletConnectSign @testable import WalletConnectPush final class XPlatformW3WTests: XCTestCase { - var w3wClient: Web3WalletClient! + var walletKitClient: WalletKitClient! var javaScriptAutoTestsAPI: JavaScriptAutoTestsAPI! private var publishers = [AnyCancellable]() @@ -33,6 +32,7 @@ final class XPlatformW3WTests: XCTestCase { keyValueStorage: keyValueStorage, keychainStorage: keychain, socketFactory: DefaultSocketFactory(), + networkMonitor: NetworkMonitor(), logger: relayLogger ) @@ -46,30 +46,23 @@ final class XPlatformW3WTests: XCTestCase { logger: pairingLogger, keyValueStorage: keyValueStorage, keychainStorage: keychain, - networkingClient: networkingClient) + networkingClient: networkingClient, + eventsClient: MockEventsClient()) let signClient = SignClientFactory.create( - metadata: AppMetadata(name: name, description: "", url: "", icons: [""], redirect: AppMetadata.Redirect(native: "", universal: nil)), + metadata: AppMetadata(name: name, description: "", url: "", icons: [""], redirect: try! AppMetadata.Redirect(native: "", universal: nil)), logger: signLogger, keyValueStorage: keyValueStorage, keychainStorage: keychain, pairingClient: pairingClient, - networkingClient: networkingClient - ) - - let authClient = AuthClientFactory.create( - metadata: AppMetadata(name: name, description: "", url: "", icons: [""], redirect: AppMetadata.Redirect(native: "", universal: nil)), + networkingClient: networkingClient, + iatProvider: DefaultIATProvider(), projectId: InputConfig.projectId, crypto: DefaultCryptoProvider(), - logger: authLogger, - keyValueStorage: keyValueStorage, - keychainStorage: keychain, - networkingClient: networkingClient, - pairingRegisterer: pairingClient, - iatProvider: DefaultIATProvider()) + eventsClient: MockEventsClient() + ) - w3wClient = Web3WalletClientFactory.create( - authClient: authClient, + walletKitClient = WalletKitClientFactory.create( signClient: signClient, pairingClient: pairingClient, pushClient: PushClientMock()) @@ -79,16 +72,16 @@ final class XPlatformW3WTests: XCTestCase { let expectation = expectation(description: "session settled") - w3wClient.sessionProposalPublisher + walletKitClient.sessionProposalPublisher .sink { [unowned self] (proposal, _) in Task(priority: .high) { let sessionNamespaces = SessionNamespace.make(toRespond: proposal.requiredNamespaces) - try await w3wClient.approve(proposalId: proposal.id, namespaces: sessionNamespaces) + try await walletKitClient.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } } .store(in: &publishers) - w3wClient.sessionSettlePublisher.sink { [unowned self] session in + walletKitClient.sessionSettlePublisher.sink { [unowned self] session in Task { var jsSession: JavaScriptAutoTestsAPI.Session? @@ -112,7 +105,7 @@ final class XPlatformW3WTests: XCTestCase { .store(in: &publishers) let pairingUri = try await javaScriptAutoTestsAPI.quickConnect() - try await w3wClient.pair(uri: pairingUri) + try await walletKitClient.pair(uri: pairingUri) wait(for: [expectation], timeout: InputConfig.defaultTimeout) } diff --git a/Example/PNDecryptionService/NotificationService.swift b/Example/PNDecryptionService/NotificationService.swift index 708444594..b1db7ce6b 100644 --- a/Example/PNDecryptionService/NotificationService.swift +++ b/Example/PNDecryptionService/NotificationService.swift @@ -1,4 +1,5 @@ import UserNotifications +import ReownWalletKit import WalletConnectNotify import Intents import Mixpanel @@ -16,41 +17,90 @@ class NotificationService: UNNotificationServiceExtension { if let content = bestAttemptContent, let topic = content.userInfo["topic"] as? String, - let ciphertext = content.userInfo["blob"] as? String { + let ciphertext = content.userInfo["message"] as? String, + let tag = content.userInfo["tag"] as? UInt { - log("topic and blob found") - - do { - let service = NotifyDecryptionService(groupIdentifier: "group.com.walletconnect.sdk") - let (pushMessage, account) = try service.decryptMessage(topic: topic, ciphertext: ciphertext) + if WalletKitDecryptionService.canHandle(tag: tag) { + let mutableContent = handleWalletKitNotification(content: content, topic: topic, tag: tag, ciphertext: ciphertext) + contentHandler(mutableContent) + } else if NotifyDecryptionService.canHandle(tag: tag) { + let mutableContent = handleNotifyNotification(content: content, topic: topic, ciphertext: ciphertext) + contentHandler(mutableContent) + } else { + let mutableContent = content.mutableCopy() as! UNMutableNotificationContent + mutableContent.title = "Error: unknown message tag" + } + } + } - log("message decrypted", account: account, topic: topic, message: pushMessage) + private func handleWalletKitNotification(content: UNNotificationContent, topic: String, tag: UInt, ciphertext: String) -> UNMutableNotificationContent { - let updatedContent = handle(content: content, pushMessage: pushMessage, topic: topic) + do { + let WalletKitDecryptionService = try WalletKitDecryptionService(groupIdentifier: "group.com.walletconnect.sdk") - let mutableContent = updatedContent.mutableCopy() as! UNMutableNotificationContent - mutableContent.title = pushMessage.title - mutableContent.subtitle = pushMessage.url - mutableContent.body = pushMessage.body + let decryptedPayload = try WalletKitDecryptionService.decryptMessage(topic: topic, ciphertext: ciphertext, tag: tag) - log("message handled", account: account, topic: topic, message: pushMessage) + let mutableContent = content.mutableCopy() as! UNMutableNotificationContent - contentHandler(mutableContent) + guard let metadata = WalletKitDecryptionService.getMetadata(topic: topic) else { + mutableContent.title = "Error: Cannot get peer's metadata" + return mutableContent + } - log("content handled", account: account, topic: topic, message: pushMessage) + switch decryptedPayload.requestMethod { + case .sessionProposal: + mutableContent.title = "New session proposal!" + mutableContent.body = "A new session proposal arrived from \(metadata.name), please check your wallet" + case .sessionRequest: + if let payload = decryptedPayload as? RequestPayload { + mutableContent.title = "New session request!" + mutableContent.body = "A new session request \(payload.request.method) arrived from \(metadata.name), please check your wallet" + } + case .authRequest: + mutableContent.title = "New authentication request!" + mutableContent.body = "A new authentication request arrived from \(metadata.name), please check your wallet" } - catch { - log("error: \(error.localizedDescription)") - let mutableContent = content.mutableCopy() as! UNMutableNotificationContent - mutableContent.title = "Error" - mutableContent.body = error.localizedDescription + return mutableContent + } catch { + let mutableContent = content.mutableCopy() as! UNMutableNotificationContent + mutableContent.title = "Error" + mutableContent.body = error.localizedDescription - contentHandler(mutableContent) - } + return mutableContent } } + + private func handleNotifyNotification(content: UNNotificationContent, topic: String, ciphertext: String) -> UNMutableNotificationContent { + do { + let service = NotifyDecryptionService(groupIdentifier: "group.com.walletconnect.sdk") + let (pushMessage, subscription, account) = try service.decryptMessage(topic: topic, ciphertext: ciphertext) + + log("message decrypted", account: account, topic: topic, message: pushMessage) + + let updatedContent = handle(content: content, pushMessage: pushMessage, subscription: subscription, topic: topic) + + let mutableContent = updatedContent.mutableCopy() as! UNMutableNotificationContent + mutableContent.title = pushMessage.title + mutableContent.subtitle = pushMessage.url + mutableContent.body = pushMessage.body + + log("message handled", account: account, topic: topic, message: pushMessage) + + return mutableContent + } catch { + log("error: \(error.localizedDescription)") + + let mutableContent = content.mutableCopy() as! UNMutableNotificationContent + mutableContent.title = "Error" + mutableContent.body = error.localizedDescription + + return mutableContent + } + } + + override func serviceExtensionTimeWillExpire() { // Called just before the extension will be terminated by the system. // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. @@ -58,66 +108,72 @@ class NotificationService: UNNotificationServiceExtension { contentHandler(bestAttemptContent) } } + + } private extension NotificationService { - func handle(content: UNNotificationContent, pushMessage: NotifyMessage, topic: String) -> UNNotificationContent { - do { - let iconUrl = try pushMessage.icon.asURL() - - let senderThumbnailImageData = try Data(contentsOf: iconUrl) - let senderThumbnailImageFileUrl = try downloadAttachment(data: senderThumbnailImageData, fileName: iconUrl.lastPathComponent) - let senderThumbnailImageFileData = try Data(contentsOf: senderThumbnailImageFileUrl) - let senderAvatar = INImage(imageData: senderThumbnailImageFileData) - - var personNameComponents = PersonNameComponents() - personNameComponents.nickname = pushMessage.title - - let senderPerson = INPerson( - personHandle: INPersonHandle(value: topic, type: .unknown), - nameComponents: personNameComponents, - displayName: pushMessage.title, - image: senderAvatar, - contactIdentifier: nil, - customIdentifier: topic, - isMe: false, - suggestionType: .none - ) - - let selfPerson = INPerson( - personHandle: INPersonHandle(value: "0", type: .unknown), - nameComponents: nil, - displayName: nil, - image: nil, - contactIdentifier: nil, - customIdentifier: nil, - isMe: true, - suggestionType: .none - ) - - let incomingMessagingIntent = INSendMessageIntent( - recipients: [selfPerson], - outgoingMessageType: .outgoingMessageText, - content: pushMessage.body, - speakableGroupName: nil, - conversationIdentifier: pushMessage.type, - serviceName: nil, - sender: senderPerson, - attachments: [] - ) - - incomingMessagingIntent.setImage(senderAvatar, forParameterNamed: \.sender) - - let interaction = INInteraction(intent: incomingMessagingIntent, response: nil) - interaction.direction = .incoming - interaction.donate(completion: nil) - - return try content.updating(from: incomingMessagingIntent) - } - catch { - return content + func handle(content: UNNotificationContent, pushMessage: NotifyMessage, subscription: NotifySubscription, topic: String) -> UNNotificationContent { + + var senderAvatar: INImage? + + if let icon = subscription.messageIcons(ofType: pushMessage.type).md { + do { + let iconUrl = try icon.asURL() + let senderThumbnailImageData = try Data(contentsOf: iconUrl) + let senderThumbnailImageFileUrl = try downloadAttachment(data: senderThumbnailImageData, fileName: iconUrl.lastPathComponent) + let senderThumbnailImageFileData = try Data(contentsOf: senderThumbnailImageFileUrl) + senderAvatar = INImage(imageData: senderThumbnailImageFileData) + } catch { + log("Fetch icon error: \(error)", account: subscription.account, topic: topic, message: pushMessage) + } } + + var personNameComponents = PersonNameComponents() + personNameComponents.nickname = pushMessage.title + + let senderPerson = INPerson( + personHandle: INPersonHandle(value: topic, type: .unknown), + nameComponents: personNameComponents, + displayName: pushMessage.title, + image: senderAvatar, + contactIdentifier: nil, + customIdentifier: topic, + isMe: false, + suggestionType: .none + ) + + let selfPerson = INPerson( + personHandle: INPersonHandle(value: "0", type: .unknown), + nameComponents: nil, + displayName: nil, + image: nil, + contactIdentifier: nil, + customIdentifier: nil, + isMe: true, + suggestionType: .none + ) + + let incomingMessagingIntent = INSendMessageIntent( + recipients: [selfPerson], + outgoingMessageType: .outgoingMessageText, + content: pushMessage.body, + speakableGroupName: nil, + conversationIdentifier: pushMessage.type, + serviceName: nil, + sender: senderPerson, + attachments: [] + ) + + incomingMessagingIntent.setImage(senderAvatar, forParameterNamed: \.sender) + + let interaction = INInteraction(intent: incomingMessagingIntent, response: nil) + interaction.direction = .incoming + interaction.donate(completion: nil) + + let updated = try? content.updating(from: incomingMessagingIntent) + return updated ?? content } func downloadAttachment(data: Data, fileName: String) throws -> URL { @@ -154,6 +210,7 @@ private extension NotificationService { Mixpanel.mainInstance().track( event: "💬 APNS: " + event, properties: [ + "message_id": message?.id, "title": message?.title, "body": message?.body, "icon": message?.icon, diff --git a/Example/RelayIntegrationTests/RelayClientEndToEndTests.swift b/Example/RelayIntegrationTests/RelayClientEndToEndTests.swift index e6e5263ae..2527f379c 100644 --- a/Example/RelayIntegrationTests/RelayClientEndToEndTests.swift +++ b/Example/RelayIntegrationTests/RelayClientEndToEndTests.swift @@ -35,21 +35,33 @@ final class RelayClientEndToEndTests: XCTestCase { let logger = ConsoleLogger(prefix: prefix, loggingLevel: .debug) let clientIdStorage = ClientIdStorage(defaults: keyValueStorage, keychain: KeychainStorageMock(), logger: logger) let socketAuthenticator = ClientIdAuthenticator( - clientIdStorage: clientIdStorage, - url: InputConfig.relayUrl + clientIdStorage: clientIdStorage ) let urlFactory = RelayUrlFactory( relayHost: InputConfig.relayHost, projectId: InputConfig.projectId, socketAuthenticator: socketAuthenticator ) - let socket = WebSocket(url: urlFactory.create(fallback: false)) + let socket = WebSocket(url: urlFactory.create()) let webSocketFactory = WebSocketFactoryMock(webSocket: socket) + let networkMonitor = NetworkMonitor() + + let relayUrlFactory = RelayUrlFactory( + relayHost: "relay.walletconnect.com", + projectId: "1012db890cf3cfb0c1cdc929add657ba", + socketAuthenticator: socketAuthenticator + ) + + let socketStatusProvider = SocketStatusProvider(socket: socket, logger: logger) + let socketConnectionHandler = AutomaticSocketConnectionHandler(socket: socket, subscriptionsTracker: SubscriptionsTracker(logger: logger), logger: logger, socketStatusProvider: socketStatusProvider) let dispatcher = Dispatcher( socketFactory: webSocketFactory, relayUrlFactory: urlFactory, - socketConnectionType: .manual, - logger: logger + networkMonitor: networkMonitor, + socket: socket, + logger: logger, + socketConnectionHandler: socketConnectionHandler, + socketStatusProvider: socketStatusProvider ) let keychain = KeychainStorageMock() let relayClient = RelayClientFactory.create( @@ -58,7 +70,8 @@ final class RelayClientEndToEndTests: XCTestCase { keyValueStorage: keyValueStorage, keychainStorage: keychain, socketFactory: DefaultSocketFactory(), - socketConnectionType: .manual, + socketConnectionType: .manual, + networkMonitor: networkMonitor, logger: logger ) let clientId = try! relayClient.getClientId() @@ -67,6 +80,11 @@ final class RelayClientEndToEndTests: XCTestCase { return relayClient } + override func tearDown() { + Thread.sleep(forTimeInterval: 1.0) + super.tearDown() + } + func testSubscribe() { let relayClient = makeRelayClient(prefix: "") @@ -104,12 +122,12 @@ final class RelayClientEndToEndTests: XCTestCase { expectationA.assertForOverFulfill = false expectationB.assertForOverFulfill = false - relayA.messagePublisher.sink { topic, payload, _ in + relayA.messagePublisher.sink { topic, payload, _, _ in (subscriptionATopic, subscriptionAPayload) = (topic, payload) expectationA.fulfill() }.store(in: &publishers) - relayB.messagePublisher.sink { topic, payload, _ in + relayB.messagePublisher.sink { topic, payload, _, _ in (subscriptionBTopic, subscriptionBPayload) = (topic, payload) Task(priority: .high) { sleep(1) diff --git a/Example/Shared/AlertPresenter.swift b/Example/Shared/AlertPresenter.swift new file mode 100644 index 000000000..5da5d4668 --- /dev/null +++ b/Example/Shared/AlertPresenter.swift @@ -0,0 +1,35 @@ +import Foundation +import SwiftMessages +import UIKit + +struct AlertPresenter { + enum MessageType { + case warning + case error + case info + case success + } + + static func present(message: String, type: AlertPresenter.MessageType) { + DispatchQueue.main.async { + let view = MessageView.viewFromNib(layout: .cardView) + switch type { + case .warning: + view.configureTheme(.warning, iconStyle: .subtle) + case .error: + view.configureTheme(.error, iconStyle: .subtle) + case .info: + view.configureTheme(.info, iconStyle: .subtle) + case .success: + view.configureTheme(.success, iconStyle: .subtle) + } + view.button?.isHidden = true + view.layoutMarginAdditions = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) + view.configureContent(title: "", body: message) + var config = SwiftMessages.Config() + config.presentationStyle = .top + config.duration = .seconds(seconds: 1.5) + SwiftMessages.show(config: config, view: view) + } + } +} diff --git a/Example/Shared/DefaultBIP44Provider.swift b/Example/Shared/DefaultBIP44Provider.swift index 5aed02650..86cc2ff54 100644 --- a/Example/Shared/DefaultBIP44Provider.swift +++ b/Example/Shared/DefaultBIP44Provider.swift @@ -1,8 +1,8 @@ import Foundation -import Auth import Web3 import CryptoSwift import HDWalletKit +import WalletConnectSigner struct DefaultBIP44Provider: BIP44Provider { diff --git a/Example/Shared/DefaultCryptoProvider.swift b/Example/Shared/DefaultCryptoProvider.swift index 3baf2b7e9..d8b270bc2 100644 --- a/Example/Shared/DefaultCryptoProvider.swift +++ b/Example/Shared/DefaultCryptoProvider.swift @@ -1,8 +1,8 @@ import Foundation -import Auth import Web3 import CryptoSwift import HDWalletKit +import WalletConnectSigner struct DefaultCryptoProvider: CryptoProvider { diff --git a/Example/Shared/DefaultSignerFactory.swift b/Example/Shared/DefaultSignerFactory.swift index 133094d00..8748a4aff 100644 --- a/Example/Shared/DefaultSignerFactory.swift +++ b/Example/Shared/DefaultSignerFactory.swift @@ -1,7 +1,7 @@ import Foundation import CryptoSwift import Web3 -import Auth +import WalletConnectSigner public struct DefaultSignerFactory: SignerFactory { diff --git a/Example/Shared/DefaultSocketFactory.swift b/Example/Shared/DefaultSocketFactory.swift index e37b98232..64c8421f5 100644 --- a/Example/Shared/DefaultSocketFactory.swift +++ b/Example/Shared/DefaultSocketFactory.swift @@ -7,7 +7,7 @@ extension WebSocket: WebSocketConnecting { } struct DefaultSocketFactory: WebSocketFactory { func create(with url: URL) -> WebSocketConnecting { let socket = WebSocket(url: url) - let queue = DispatchQueue(label: "com.walletconnect.sdk.sockets", attributes: .concurrent) + let queue = DispatchQueue(label: "com.walletconnect.sdk.sockets", qos: .utility, attributes: .concurrent) socket.callbackQueue = queue return socket } diff --git a/Example/Shared/ImportAccount.swift b/Example/Shared/ImportAccount.swift index 00e4c04e3..63482de99 100644 --- a/Example/Shared/ImportAccount.swift +++ b/Example/Shared/ImportAccount.swift @@ -9,12 +9,12 @@ enum ImportAccount: Codable { case kotlin case js case custom(privateKey: String) - case web3Modal(account: Account, topic: String) + case appKit(account: Account, topic: String) static let swiftId = "swift.eth" static let kotlinId = "kotlin.eth" static let jsId = "js.eth" - static let web3ModalId = "web3Modal" + static let appKit = "web3Modal" init?(input: String) { switch input.lowercased() { @@ -26,12 +26,12 @@ enum ImportAccount: Codable { self = .js default: switch true { - case input.starts(with: ImportAccount.web3ModalId): + case input.starts(with: ImportAccount.appKit): let components = input.components(separatedBy: "-") guard components.count == 3, let account = Account(components[1]) else { return nil } - self = .web3Modal(account: account, topic: components[2]) + self = .appKit(account: account, topic: components[2]) default: if let _ = try? EthereumPrivateKey(hexPrivateKey: "0x" + input, ctx: nil) { @@ -55,8 +55,8 @@ enum ImportAccount: Codable { return ImportAccount.jsId case .custom(let privateKey): return privateKey - case .web3Modal(let account, let topic): - return "\(ImportAccount.web3ModalId)-\(account.absoluteString)-\(topic)" + case .appKit(let account, let topic): + return "\(ImportAccount.appKit)-\(account.absoluteString)-\(topic)" } } @@ -71,7 +71,7 @@ enum ImportAccount: Codable { case .custom(let privateKey): let address = try! EthereumPrivateKey(hexPrivateKey: "0x" + privateKey, ctx: nil).address.hex(eip55: true) return Account("eip155:1:\(address)")! - case .web3Modal(let account, _): + case .appKit(let account, _): return account } } @@ -86,16 +86,16 @@ enum ImportAccount: Codable { return "0e0c9cea8b4854b93e142d1c613d6a6cbd87a506008cd153996275475f20eb7d" case .custom(let privateKey): return privateKey - case .web3Modal: + case .appKit: fatalError("Private key not available") } } - func onSign(message: String) -> SigningResult { + func onSign(message: String) -> CacaoSignature { let privateKey = Data(hex: privateKey) let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create() let signature = try! signer.sign(message: message, privateKey: privateKey, type: .eip191) - return .signed(signature) + return signature } static func new() -> ImportAccount { diff --git a/Example/WalletApp/ApplicationLayer/ProfilingService.swift b/Example/Shared/ProfilingService.swift similarity index 93% rename from Example/WalletApp/ApplicationLayer/ProfilingService.swift rename to Example/Shared/ProfilingService.swift index bfffe219a..c5c3ee119 100644 --- a/Example/WalletApp/ApplicationLayer/ProfilingService.swift +++ b/Example/Shared/ProfilingService.swift @@ -2,12 +2,13 @@ import Foundation import Mixpanel import WalletConnectNetworking import Combine +import WalletConnectSign import WalletConnectNotify final class ProfilingService { public static var instance = ProfilingService() - private let queue = DispatchQueue(label: "com.walletApp.profilingService") + private let queue = DispatchQueue(label: "com.walletApp.profilingService", qos: .utility) private var publishers = [AnyCancellable]() private var isProfiling: Bool { get { @@ -32,8 +33,7 @@ final class ProfilingService { mixpanel.people.set(properties: ["$name": account, "account": account]) handleLogs(from: Networking.instance.logsPublisher) - handleLogs(from: Notify.instance.logsPublisher) - handleLogs(from: Push.instance.logsPublisher) + handleLogs(from: Sign.instance.logsPublisher) } private func handleLogs(from publisher: AnyPublisher) { diff --git a/Example/Shared/Signer/ETHSigner.swift b/Example/Shared/Signer/ETHSigner.swift index 6ff523441..232dcffc2 100644 --- a/Example/Shared/Signer/ETHSigner.swift +++ b/Example/Shared/Signer/ETHSigner.swift @@ -3,7 +3,6 @@ import Commons import Web3 struct ETHSigner { - private let importAccount: ImportAccount init(importAccount: ImportAccount) { @@ -21,8 +20,21 @@ struct ETHSigner { func personalSign(_ params: AnyCodable) -> AnyCodable { let params = try! params.get([String].self) let messageToSign = params[0] - let dataToHash = dataToHash(messageToSign) - let (v, r, s) = try! privateKey.sign(message: .init(hex: dataToHash.toHexString())) + + // Determine if the message is hex-encoded or plain text + let dataToSign: Bytes + if messageToSign.hasPrefix("0x") { + // Hex-encoded message, remove "0x" and convert + let messageData = Data(hex: String(messageToSign.dropFirst(2))) + dataToSign = dataToHash(messageData) + } else { + // Plain text message, convert directly to data + let messageData = Data(messageToSign.utf8) + dataToSign = dataToHash(messageData) + } + + // Sign the data + let (v, r, s) = try! privateKey.sign(message: .init(Data(dataToSign))) let result = "0x" + r.toHexString() + s.toHexString() + String(v + 27, radix: 16) return AnyCodable(result) } @@ -32,23 +44,23 @@ struct ETHSigner { return AnyCodable(result) } - func sendTransaction(_ params: AnyCodable) -> AnyCodable { - let params = try! params.get([EthereumTransaction].self) + func sendTransaction(_ params: AnyCodable) throws -> AnyCodable { + let params = try params.get([EthereumTransaction].self) var transaction = params[0] transaction.gas = EthereumQuantity(quantity: BigUInt("1234")) + transaction.nonce = EthereumQuantity(quantity: BigUInt("0")) + transaction.gasPrice = EthereumQuantity(quantity: BigUInt(0)) print(transaction.description) - let signedTx = try! transaction.sign(with: self.privateKey, chainId: 4) + let signedTx = try transaction.sign(with: self.privateKey, chainId: 4) let (r, s, v) = (signedTx.r, signedTx.s, signedTx.v) let result = r.hex() + s.hex().dropFirst(2) + String(v.quantity, radix: 16) return AnyCodable(result) } - private func dataToHash(_ message: String) -> Bytes { + private func dataToHash(_ data: Data) -> Bytes { let prefix = "\u{19}Ethereum Signed Message:\n" - let messageData = Data(hex: message) - let prefixData = (prefix + String(messageData.count)).data(using: .utf8)! - let prefixedMessageData = prefixData + messageData - let dataToHash: Bytes = .init(hex: prefixedMessageData.toHexString()) - return dataToHash + let prefixData = (prefix + String(data.count)).data(using: .utf8)! + let prefixedMessageData = prefixData + data + return .init(hex: prefixedMessageData.toHexString()) } } diff --git a/Example/Shared/Signer/SOLSigner.swift b/Example/Shared/Signer/SOLSigner.swift index f9f328069..32d97fcfd 100644 --- a/Example/Shared/Signer/SOLSigner.swift +++ b/Example/Shared/Signer/SOLSigner.swift @@ -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))) }() diff --git a/Example/Shared/Signer/Signer.swift b/Example/Shared/Signer/Signer.swift index 16e75775f..3091c6c98 100644 --- a/Example/Shared/Signer/Signer.swift +++ b/Example/Shared/Signer/Signer.swift @@ -20,7 +20,7 @@ final class Signer { return signer.signTypedData(request.params) case "eth_sendTransaction": - return signer.sendTransaction(request.params) + return try signer.sendTransaction(request.params) case "solana_signTransaction": return SOLSigner.signTransaction(request.params) diff --git a/Example/Showcase/Classes/ApplicationLayer/AppDelegate.swift b/Example/Showcase/Classes/ApplicationLayer/AppDelegate.swift deleted file mode 100644 index 0eaa58f26..000000000 --- a/Example/Showcase/Classes/ApplicationLayer/AppDelegate.swift +++ /dev/null @@ -1,20 +0,0 @@ -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - return true - } - - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - - } -} diff --git a/Example/Showcase/Classes/ApplicationLayer/Application.swift b/Example/Showcase/Classes/ApplicationLayer/Application.swift deleted file mode 100644 index 3cc8d8713..000000000 --- a/Example/Showcase/Classes/ApplicationLayer/Application.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Foundation -import WalletConnectChat - -final class Application { - - lazy var chatService: ChatService = { - return ChatService() - }() - - lazy var accountStorage: AccountStorage = { - return AccountStorage(defaults: .standard) - }() -} diff --git a/Example/Showcase/Classes/ApplicationLayer/Configurator/AppearanceConfigurator.swift b/Example/Showcase/Classes/ApplicationLayer/Configurator/AppearanceConfigurator.swift deleted file mode 100644 index 5ad69dfb5..000000000 --- a/Example/Showcase/Classes/ApplicationLayer/Configurator/AppearanceConfigurator.swift +++ /dev/null @@ -1,19 +0,0 @@ -import UIKit - -struct AppearanceConfigurator: Configurator { - - func configure() { - let appearance = UINavigationBarAppearance() - appearance.backgroundColor = .w_background - appearance.shadowColor = .clear - appearance.titleTextAttributes = [ - .foregroundColor: UIColor.w_foreground - ] - - UINavigationBar.appearance().standardAppearance = appearance - UINavigationBar.appearance().scrollEdgeAppearance = appearance - UINavigationBar.appearance().compactAppearance = appearance - - UIApplication.currentWindow.overrideUserInterfaceStyle = .dark - } -} diff --git a/Example/Showcase/Classes/ApplicationLayer/Configurator/ApplicationConfigurator.swift b/Example/Showcase/Classes/ApplicationLayer/Configurator/ApplicationConfigurator.swift deleted file mode 100644 index 810260eef..000000000 --- a/Example/Showcase/Classes/ApplicationLayer/Configurator/ApplicationConfigurator.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Combine - -struct ApplicationConfigurator: Configurator { - - private var publishers = Set() - - private let app: Application - - init(app: Application) { - self.app = app - } - - func configure() { - WelcomeModule.create(app: app).present() - } -} diff --git a/Example/Showcase/Classes/ApplicationLayer/Configurator/Configurator.swift b/Example/Showcase/Classes/ApplicationLayer/Configurator/Configurator.swift deleted file mode 100644 index 2eb6d30cb..000000000 --- a/Example/Showcase/Classes/ApplicationLayer/Configurator/Configurator.swift +++ /dev/null @@ -1,9 +0,0 @@ -protocol Configurator { - func configure() -} - -extension Array where Element == Configurator { - func configure() { - forEach { $0.configure() } - } -} diff --git a/Example/Showcase/Classes/ApplicationLayer/Configurator/MigrationConfigurator.swift b/Example/Showcase/Classes/ApplicationLayer/Configurator/MigrationConfigurator.swift deleted file mode 100644 index 629308aa7..000000000 --- a/Example/Showcase/Classes/ApplicationLayer/Configurator/MigrationConfigurator.swift +++ /dev/null @@ -1,12 +0,0 @@ -struct MigrationConfigurator: Configurator { - - let app: Application - - init(app: Application) { - self.app = app - } - - func configure() { - - } -} diff --git a/Example/Showcase/Classes/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift b/Example/Showcase/Classes/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift deleted file mode 100644 index bdd34c7e1..000000000 --- a/Example/Showcase/Classes/ApplicationLayer/Configurator/ThirdPartyConfigurator.swift +++ /dev/null @@ -1,21 +0,0 @@ -import WalletConnectNetworking -import WalletConnectPairing -import Auth -import WalletConnectModal - -struct ThirdPartyConfigurator: Configurator { - - func configure() { - - let metadata = AppMetadata( - name: "Showcase App", - description: "Showcase description", - url: "example.wallet", - icons: ["https://avatars.githubusercontent.com/u/37784886"] - ) - - Networking.configure(projectId: InputConfig.projectId, socketFactory: DefaultSocketFactory()) - Auth.configure(crypto: DefaultCryptoProvider()) - WalletConnectModal.configure(projectId: InputConfig.projectId, metadata: metadata) - } -} diff --git a/Example/Showcase/Classes/ApplicationLayer/SceneDelegate.swift b/Example/Showcase/Classes/ApplicationLayer/SceneDelegate.swift deleted file mode 100644 index 537e88926..000000000 --- a/Example/Showcase/Classes/ApplicationLayer/SceneDelegate.swift +++ /dev/null @@ -1,41 +0,0 @@ -import UIKit -import Auth -import WalletConnectPairing - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - - var window: UIWindow? - - private let app = Application() - - private var configurators: [Configurator] { - return [ - MigrationConfigurator(app: app), - ThirdPartyConfigurator(), - ApplicationConfigurator(app: app), - AppearanceConfigurator() - ] - } - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = (scene as? UIWindowScene) else { return } - - window = UIWindow(windowScene: windowScene) - window?.makeKeyAndVisible() - - configurators.configure() - } - - func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { - guard let context = URLContexts.first else { return } - - let uri = context.url.absoluteString.replacingOccurrences(of: "showcase://wc?uri=", with: "") - guard let walletConnectUri = WalletConnectURI(string: uri) else { - return - } - - Task { - try await Pair.instance.pair(uri: walletConnectUri) - } - } -} diff --git a/Example/Showcase/Classes/DomainLayer/Chat/ChatService.swift b/Example/Showcase/Classes/DomainLayer/Chat/ChatService.swift deleted file mode 100644 index 265ac3a56..000000000 --- a/Example/Showcase/Classes/DomainLayer/Chat/ChatService.swift +++ /dev/null @@ -1,185 +0,0 @@ -import Foundation -import Combine -import WalletConnectChat -import WalletConnectRelay -import WalletConnectSign - -typealias Stream = AnyPublisher - -final class ChatService { - - private var client: ChatClient = { - Chat.configure(bip44: DefaultBIP44Provider()) - return Chat.instance - }() - - private lazy var networking: NetworkingClient = { - return Networking.instance - }() - - var connectionPublisher: Stream { - return networking.socketConnectionStatusPublisher - .receive(on: DispatchQueue.main) - .eraseToAnyPublisher() - } - - var threadPublisher: Stream<[WalletConnectChat.Thread]> { - return client.threadsPublisher - .receive(on: DispatchQueue.main) - .eraseToAnyPublisher() - } - - var receivedInvitePublisher: Stream<[ReceivedInvite]> { - return client.receivedInvitesPublisher - .receive(on: DispatchQueue.main) - .eraseToAnyPublisher() - } - - var sentInvitePublisher: Stream<[SentInvite]> { - return client.sentInvitesPublisher - .receive(on: DispatchQueue.main) - .eraseToAnyPublisher() - } - - func messagePublisher(thread: WalletConnectChat.Thread) -> Stream<[Message]> { - return client.messagesPublisher - .map { - $0.filter { $0.topic == thread.topic } - } - .receive(on: DispatchQueue.main) - .eraseToAnyPublisher() - } - - func getMessages(thread: WalletConnectChat.Thread) -> [WalletConnectChat.Message] { - client.getMessages(topic: thread.topic) - } - - func getThreads(account: Account) -> [WalletConnectChat.Thread] { - return client.getThreads(account: account) - } - - func getReceivedInvites(account: Account) -> [ReceivedInvite] { - return client.getReceivedInvites(account: account) - } - - func getSentInvites(account: Account) -> [SentInvite] { - return client.getSentInvites(account: account) - } - - func setupSubscriptions(account: Account) { - try! client.setupSubscriptions(account: account) - } - - func sendMessage(topic: String, message: String) async throws { - try await client.message(topic: topic, message: message) - } - - func accept(invite: ReceivedInvite) async throws { - try await client.accept(inviteId: invite.id) - } - - func reject(invite: ReceivedInvite) async throws { - try await client.reject(inviteId: invite.id) - } - - func goPublic(account: Account) async throws { - try await client.goPublic(account: account) - } - - func invite(inviterAccount: Account, inviteeAccount: Account, message: String) async throws { - let inviteePublicKey = try await client.resolve(account: inviteeAccount) - let invite = Invite(message: message, inviterAccount: inviterAccount, inviteeAccount: inviteeAccount, inviteePublicKey: inviteePublicKey) - try await client.invite(invite: invite) - } - - func register(account: Account, importAccount: ImportAccount) async throws { - _ = try await client.register(account: account) { message in - return await self.onSign(message: message, importAccount: importAccount) - } - } - - func unregister(account: Account, importAccount: ImportAccount) async throws { - try await client.unregister(account: account) { message in - return await self.onSign(message: message, importAccount: importAccount) - } - } - - func goPrivate(account: Account) async throws { - try await client.goPrivate(account: account) - } - - func resolve(account: Account) async throws -> String { - return try await client.resolve(account: account) - } -} - -private extension ChatService { - - func onSign(message: String, importAccount: ImportAccount) async -> SigningResult { - switch importAccount { - case .swift, .kotlin, .js, .custom: - return .signed(onSign(message: message, privateKey: importAccount.privateKey)) - case .web3Modal(let account, let topic): - return await onWalletConnectModalSign(message: message, account: account, topic: topic) - } - } - - func onSign(message: String, privateKey: String) -> CacaoSignature { - let privateKey = Data(hex: privateKey) - let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create() - return try! signer.sign(message: message, privateKey: privateKey, type: .eip191) - } - - func onWalletConnectModalSign(message: String, account: Account, topic: String) async -> SigningResult { - guard let session = Sign.instance.getSessions().first(where: { $0.topic == topic }) else { return .rejected } - - do { - let request = makeRequest(session: session, message: message, account: account) - try await Sign.instance.request(params: request) - - let signature: CacaoSignature = try await withCheckedThrowingContinuation { continuation in - var cancellable: AnyCancellable? - cancellable = Sign.instance.sessionResponsePublisher - .sink { response in - defer { cancellable?.cancel() } - switch response.result { - case .response(let value): - do { - let string = try value.get(String.self) - let signature = CacaoSignature(t: .eip191, s: string.deleting0x()) - continuation.resume(returning: signature) - } catch { - continuation.resume(throwing: error) - } - case .error(let error): - continuation.resume(throwing: error) - } - } - } - - return .signed(signature) - } catch { - return .rejected - } - } - - func makeRequest(session: WalletConnectSign.Session, message: String, account: Account) -> Request { - return Request( - topic: session.topic, - method: "personal_sign", - params: AnyCodable(["0x" + message.data(using: .utf8)!.toHexString(), account.address]), - chainId: Blockchain("eip155:1")! - ) - } -} - -fileprivate extension String { - - func deleting0x() -> String { - var string = self - if starts(with: "0x") { - string.removeFirst(2) - } - return string - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatInteractor.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatInteractor.swift deleted file mode 100644 index dab663f14..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatInteractor.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Foundation -import WalletConnectChat - -final class ChatInteractor { - - private let chatService: ChatService - - init(chatService: ChatService) { - self.chatService = chatService - } - - func getMessages(thread: WalletConnectChat.Thread) -> [Message] { - return chatService.getMessages(thread: thread) - } - - func messagesSubscription(thread: WalletConnectChat.Thread) -> Stream<[Message]> { - return chatService.messagePublisher(thread: thread) - } - - func sendMessage(topic: String, message: String) async throws { - try await chatService.sendMessage(topic: topic, message: message) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatModule.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatModule.swift deleted file mode 100644 index a58326276..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatModule.swift +++ /dev/null @@ -1,19 +0,0 @@ -import SwiftUI -import WalletConnectChat - -final class ChatModule { - - @discardableResult - static func create(thread: WalletConnectChat.Thread, app: Application) -> UIViewController { - let router = ChatRouter(app: app) - let interactor = ChatInteractor(chatService: app.chatService) - let presenter = ChatPresenter(thread: thread, interactor: interactor, router: router) - let view = ChatView().environmentObject(presenter) - let viewController = SceneViewController(viewModel: presenter, content: view) - - router.viewController = viewController - - return viewController - } - -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatPresenter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatPresenter.swift deleted file mode 100644 index e19db581b..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatPresenter.swift +++ /dev/null @@ -1,61 +0,0 @@ -import UIKit -import Combine -import WalletConnectChat - -final class ChatPresenter: ObservableObject { - - private let thread: WalletConnectChat.Thread - private let interactor: ChatInteractor - private let router: ChatRouter - private var disposeBag = Set() - - @Published private var messages: [Message] = [] - @Published var input: String = .empty - - var messageViewModels: [MessageViewModel] { - return messages.sorted(by: { $0.timestamp < $1.timestamp }) - .map { MessageViewModel(message: $0, thread: thread) } - } - - init(thread: WalletConnectChat.Thread, interactor: ChatInteractor, router: ChatRouter) { - defer { setupInitialState() } - self.thread = thread - self.interactor = interactor - self.router = router - } - - func didPressSend() { - Task(priority: .userInitiated) { - try await sendMessage() - } - } -} - -// MARK: SceneViewModel - -extension ChatPresenter: SceneViewModel { - - var sceneTitle: String? { - return thread.peerAccount.address - } -} - -// MARK: Privates - -private extension ChatPresenter { - - func setupInitialState() { - messages = interactor.getMessages(thread: thread) - - interactor.messagesSubscription(thread: thread) - .sink { [unowned self] messages in - self.messages = messages - }.store(in: &disposeBag) - } - - @MainActor - func sendMessage() async throws { - try await interactor.sendMessage(topic: thread.topic, message: input) - input = .empty - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatRouter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatRouter.swift deleted file mode 100644 index 83a77a59f..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatRouter.swift +++ /dev/null @@ -1,12 +0,0 @@ -import UIKit - -final class ChatRouter { - - weak var viewController: UIViewController! - - private let app: Application - - init(app: Application) { - self.app = app - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatView.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatView.swift deleted file mode 100644 index 279a30a99..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/ChatView.swift +++ /dev/null @@ -1,37 +0,0 @@ -import SwiftUI - -struct ChatView: View { - - @EnvironmentObject var presenter: ChatPresenter - - var body: some View { - ZStack { - ChatScrollView { - ForEach(presenter.messageViewModels) { message in - MessageView(message: message) - } - - Spacer().frame(height: 72) - } - - VStack { - Spacer() - - HStack { - InputView(title: "Message...", text: $presenter.input) { - presenter.didPressSend() - } - .padding(16.0) - } - } - } - } -} - -#if DEBUG -struct ChatView_Previews: PreviewProvider { - static var previews: some View { - ChatView() - } -} -#endif diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/Models/MessageViewModel.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Chat/Models/MessageViewModel.swift deleted file mode 100644 index 62387c1f7..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/Models/MessageViewModel.swift +++ /dev/null @@ -1,32 +0,0 @@ -import Foundation -import WalletConnectChat - -struct MessageViewModel: Identifiable { - private let message: Message - private let thread: WalletConnectChat.Thread - - var id: UInt64 { - return message.timestamp - } - - init(message: Message, thread: WalletConnectChat.Thread) { - self.message = message - self.thread = thread - } - - var currentAccount: Account { - return thread.selfAccount - } - - var isCurrentUser: Bool { - return currentAccount == message.authorAccount - } - - var text: String { - return message.message - } - - var showAvatar: Bool { - return !isCurrentUser - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/Views/ChatScrollView.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Chat/Views/ChatScrollView.swift deleted file mode 100644 index afd5b24bc..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/Views/ChatScrollView.swift +++ /dev/null @@ -1,25 +0,0 @@ -import SwiftUI - -struct ChatScrollView: View where Content: View { - - @ViewBuilder let content: () -> Content - - var body: some View { - ScrollView(showsIndicators: false) { - VStack(alignment: .leading, spacing: 12) { - Spacer() - .frame( - minWidth: 0, - maxWidth: .infinity, - minHeight: 0, - maxHeight: .infinity, - alignment: .topLeading - ) - - content() - } - .rotationEffect(Angle(degrees: 180)) - } - .rotationEffect(Angle(degrees: 180)) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/Views/ContentMessageView.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Chat/Views/ContentMessageView.swift deleted file mode 100644 index e58deb30e..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/Views/ContentMessageView.swift +++ /dev/null @@ -1,35 +0,0 @@ -import SwiftUI - -struct ContentMessageView: View { - - let text: String - let isCurrentUser: Bool - - var body: some View { - Text(text) - .font(.body) - .padding(.horizontal, 16.0) - .padding(.vertical, 10.0) - .foregroundColor(.white) - .background( - // TODO: Add border - overlayView - .foregroundColor(backgroundColor) - ) - } - - private var overlayView: some View { - return Rectangle() - .cornerRadius(22, corners: [.topLeft, .topRight]) - .cornerRadius(22, corners: isCurrentUser ? .bottomLeft : .bottomRight) - .cornerRadius(4, corners: isCurrentUser ? .bottomRight : .bottomLeft) - } - - private var backgroundColor: Color { - return isCurrentUser ? .w_secondaryBackground : .w_purpleBackground - } - - private var borderColor: Color { - return isCurrentUser ? .w_tertiaryBackground : .w_purpleForeground - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/Views/MessageView.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Chat/Views/MessageView.swift deleted file mode 100644 index 31bc7afd7..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Chat/Views/MessageView.swift +++ /dev/null @@ -1,28 +0,0 @@ -import SwiftUI - -struct MessageView: View { - - let message: MessageViewModel - - var body: some View { - HStack(spacing: 8.0) { - if message.isCurrentUser { - Spacer() - } - - if message.showAvatar { - Image("avatar") - .resizable() - .frame(width: 44, height: 44, alignment: .center) - .cornerRadius(22) - } - - ContentMessageView(text: message.text, isCurrentUser: message.isCurrentUser) - - if !message.isCurrentUser { - Spacer() - } - } - .padding(.horizontal, 16.0) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListInteractor.swift b/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListInteractor.swift deleted file mode 100644 index 0ddb01a9c..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListInteractor.swift +++ /dev/null @@ -1,51 +0,0 @@ -import WalletConnectChat - -final class ChatListInteractor { - - private let chatService: ChatService - private let accountStorage: AccountStorage - - var account: Account? { - return accountStorage.importAccount?.account - } - - init(chatService: ChatService, accountStorage: AccountStorage) { - self.chatService = chatService - self.accountStorage = accountStorage - } - - func getThreads(account: Account) -> [WalletConnectChat.Thread] { - return chatService.getThreads(account: account) - } - - func threadsSubscription() -> Stream<[WalletConnectChat.Thread]> { - return chatService.threadPublisher - } - - func getReceivedInvites(account: Account) -> [ReceivedInvite] { - return chatService.getReceivedInvites(account: account) - } - - func getSentInvites(account: Account) -> [SentInvite] { - return chatService.getSentInvites(account: account) - } - - func receivedInvitesSubscription() -> Stream<[ReceivedInvite]> { - return chatService.receivedInvitePublisher - } - - func sentInvitesSubscription() -> Stream<[SentInvite]> { - return chatService.sentInvitePublisher - } - - func setupSubscriptions(account: Account) { - chatService.setupSubscriptions(account: account) - } - - func logout() async throws { - guard let importAccount = accountStorage.importAccount else { return } - try await chatService.goPrivate(account: importAccount.account) - try await chatService.unregister(account: importAccount.account, importAccount: importAccount) - accountStorage.importAccount = nil - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListModule.swift b/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListModule.swift deleted file mode 100644 index 4d1ec3480..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListModule.swift +++ /dev/null @@ -1,18 +0,0 @@ -import SwiftUI - -final class ChatListModule { - - @discardableResult - static func create(app: Application, account: Account) -> UIViewController { - let router = ChatListRouter(app: app) - let interactor = ChatListInteractor(chatService: app.chatService, accountStorage: app.accountStorage) - let presenter = ChatListPresenter(account: account, interactor: interactor, router: router) - let view = ChatListView().environmentObject(presenter) - let viewController = SceneViewController(viewModel: presenter, content: view) - - router.viewController = viewController - - return viewController - } - -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListPresenter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListPresenter.swift deleted file mode 100644 index 56a3a0f9c..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListPresenter.swift +++ /dev/null @@ -1,131 +0,0 @@ -import UIKit -import Combine -import WalletConnectChat - -final class ChatListPresenter: ObservableObject { - - private let interactor: ChatListInteractor - private let router: ChatListRouter - private let account: Account - private var disposeBag = Set() - - @Published private var threads: [WalletConnectChat.Thread] = [] - @Published private var receivedInvites: [ReceivedInvite] = [] - @Published private var sentInvites: [SentInvite] = [] - - var threadViewModels: [ThreadViewModel] { - return threads - .sorted(by: { $0.topic < $1.topic }) - .map { ThreadViewModel(thread: $0) } - } - - var receivedInviteViewModels: [InviteViewModel] { - return receivedInvites - .sorted(by: { $0.timestamp < $1.timestamp }) - .map { InviteViewModel(invite: $0) } - } - - var sentInviteViewModels: [InviteViewModel] { - return sentInvites - .sorted(by: { $0.timestamp < $1.timestamp }) - .map { InviteViewModel(invite: $0) } - } - - init(account: Account, interactor: ChatListInteractor, router: ChatListRouter) { - defer { setupInitialState() } - self.account = account - self.interactor = interactor - self.router = router - } - - var showReceivedInvites: Bool { - return !receivedInviteViewModels.isEmpty - } - - var showSentInvites: Bool { - return !sentInviteViewModels.isEmpty - } - - func didPressThread(_ thread: ThreadViewModel) { - router.presentChat(thread: thread.thread) - } - - func didPressReceivedInvites() { - router.presentReceivedInviteList(account: account) - } - - func didPressSentInvites() { - router.presentSentInviteList(account: account) - } - - @MainActor - func didLogoutPress() async throws { - try await interactor.logout() - router.presentWelcome() - } - - @MainActor - func didCopyPress() async throws { - guard let account = interactor.account else { return } - UIPasteboard.general.string = account.absoluteString - - throw AlertError(message: "Account copied to clipboard") - } - - func didPressNewChat() { - presentInvite() - } -} - -// MARK: SceneViewModel - -extension ChatListPresenter: SceneViewModel { - - var sceneTitle: String? { - return "Chat" - } - - var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { - return .always - } - - var rightBarButtonItem: UIBarButtonItem? { - return UIBarButtonItem( - barButtonSystemItem: .add, - target: self, - action: #selector(presentInvite) - ) - } -} - -// MARK: Privates - -private extension ChatListPresenter { - - func setupInitialState() { - interactor.setupSubscriptions(account: account) - - threads = interactor.getThreads(account: account) - receivedInvites = interactor.getReceivedInvites(account: account) - sentInvites = interactor.getSentInvites(account: account) - - interactor.threadsSubscription() - .sink { [unowned self] threads in - self.threads = threads - }.store(in: &disposeBag) - - interactor.receivedInvitesSubscription() - .sink { [unowned self] receivedInvites in - self.receivedInvites = receivedInvites - }.store(in: &disposeBag) - - interactor.sentInvitesSubscription() - .sink { [unowned self] sentInvites in - self.sentInvites = sentInvites - }.store(in: &disposeBag) - } - - @objc func presentInvite() { - router.presentInvite(account: account) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListRouter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListRouter.swift deleted file mode 100644 index bd2d8407f..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListRouter.swift +++ /dev/null @@ -1,36 +0,0 @@ -import UIKit -import WalletConnectChat - -final class ChatListRouter { - - weak var viewController: UIViewController! - - private let app: Application - - init(app: Application) { - self.app = app - } - - func presentInvite(account: Account) { - InviteModule.create(app: app, account: account) - .wrapToNavigationController() - .present(from: viewController) - } - - func presentReceivedInviteList(account: Account) { - InviteListModule.create(app: app, account: account, type: .received).push(from: viewController) - } - - func presentSentInviteList(account: Account) { - InviteListModule.create(app: app, account: account, type: .sent).push(from: viewController) - } - - func presentChat(thread: WalletConnectChat.Thread) { - ChatModule.create(thread: thread, app: app).push(from: viewController) - } - - func presentWelcome() { - WelcomeModule.create(app: app).present() - } -} - diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListView.swift b/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListView.swift deleted file mode 100644 index 979d1fe6d..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/ChatListView.swift +++ /dev/null @@ -1,153 +0,0 @@ -import SwiftUI - -struct ChatListView: View { - - @EnvironmentObject var presenter: ChatListPresenter - - var body: some View { - GeometryReader { geometry in - VStack { - ScrollView(showsIndicators: false) { - VStack { - HStack { - if presenter.showReceivedInvites { - invitesButton(title: "Received Invites", count: presenter.receivedInviteViewModels.count, textColor: .w_greenForground, backgroundColor: .w_greenBackground) { - presenter.didPressReceivedInvites() - } - } - - if presenter.showSentInvites { - invitesButton(title: "Sent Invites", count: presenter.sentInviteViewModels.count, textColor: .w_foreground, backgroundColor: .w_purpleBackground) { - presenter.didPressSentInvites() - } - } - - Spacer() - } - .padding(16.0) - - if presenter.threadViewModels.isEmpty { - Spacer() - emptyView(size: geometry.size) - Spacer() - } else { - chatsList() - } - } - } - - PlainButton { - try await presenter.didCopyPress() - } label: { - Text("Copy account") - .foregroundColor(.white) - } - .padding(.bottom, 16) - - PlainButton { - try await presenter.didLogoutPress() - } label: { - Text("Log out") - .foregroundColor(.red) - } - .padding(.bottom, 16) - } - } - } - - private func invitesButton( - title: String, - count: Int, - textColor: Color, - backgroundColor: Color, - action: @escaping () -> Void - ) -> some View { - Button(action: action) { - HStack(spacing: 8.0) { - Text(String(count)) - .frame(width: 24.0, height: 24.0) - .background(textColor) - .foregroundColor(backgroundColor) - .font(.system(size: 15.0, weight: .bold)) - .clipShape(Circle()) - - Text(title) - .foregroundColor(textColor) - .font(.system(size: 15.0, weight: .bold)) - } - .padding(.vertical, 8) - .padding(.horizontal, 16) - } - .frame(height: 44.0) - .background(backgroundColor) - .clipShape(Capsule()) - } - - private func chatsList() -> some View { - ForEach(presenter.threadViewModels) { thread in - Button(action: { - presenter.didPressThread(thread) - }) { - HStack(spacing: 16.0) { - Image("avatar") - .resizable() - .frame(width: 64.0, height: 64.0) - - VStack(alignment: .leading) { - Text(thread.title) - .font(.title3) - .foregroundColor(.w_foreground) - .lineLimit(1) - - Text(thread.subtitle) - .font(.subheadline) - .foregroundColor(.w_secondaryForeground) - .multilineTextAlignment(.leading) - } - } - .frame(height: 64.0) - } - } - .padding(16.0) - } - - private func emptyView(size: CGSize) -> some View { - VStack(spacing: 8.0) { - Text("It’s empty in here") - .font(.system(.title3)) - .foregroundColor(.w_foreground) - - Text("Start a conversation with your web3 frens") - .font(.body) - .foregroundColor(.w_secondaryForeground) - .padding(.bottom, 8.0) - - Button(action: { presenter.didPressNewChat() }, label: { - HStack(spacing: 8.0) { - Image("plus_icon") - .resizable() - .frame(width: 24, height: 24) - Text("New chat") - .foregroundColor(.w_foreground) - .font(.system(size: 18, weight: .semibold)) - } - .padding(.trailing, 8.0) - }) - .frame(width: 128, height: 44) - .background( - Capsule() - .foregroundColor(.w_greenForground) - ) - } - .frame(width: size.width) - .frame(minHeight: size.height) - } -} - -#if DEBUG -struct ChatListView_Previews: PreviewProvider { - static var previews: some View { - ChatListView() - } -} -#endif diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/Models/AlertError.swift b/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/Models/AlertError.swift deleted file mode 100644 index c7cc4f270..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/Models/AlertError.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation - -struct AlertError: Error, LocalizedError { - let message: String - - var errorDescription: String? { - return message - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/Models/ThreadViewModel.swift b/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/Models/ThreadViewModel.swift deleted file mode 100644 index 1c37f30d8..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/ChatList/Models/ThreadViewModel.swift +++ /dev/null @@ -1,22 +0,0 @@ -import Foundation -import WalletConnectChat - -struct ThreadViewModel: Identifiable { - let thread: WalletConnectChat.Thread - - var topic: String { - return thread.topic - } - - var id: String { - return thread.topic - } - - var title: String { - return thread.peerAccount.address - } - - var subtitle: String { - return thread.topic - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportInteractor.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportInteractor.swift deleted file mode 100644 index c412afe30..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportInteractor.swift +++ /dev/null @@ -1,18 +0,0 @@ -final class ImportInteractor { - - private let chatService: ChatService - private let accountStorage: AccountStorage - - init(chatService: ChatService, accountStorage: AccountStorage) { - self.chatService = chatService - self.accountStorage = accountStorage - } - - func save(importAccount: ImportAccount) { - accountStorage.importAccount = importAccount - } - - func register(importAccount: ImportAccount) async throws { - try await chatService.register(account: importAccount.account, importAccount: importAccount) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportModule.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportModule.swift deleted file mode 100644 index 4a567ca90..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportModule.swift +++ /dev/null @@ -1,18 +0,0 @@ -import SwiftUI - -final class ImportModule { - - @discardableResult - static func create(app: Application) -> UIViewController { - let router = ImportRouter(app: app) - let interactor = ImportInteractor(chatService: app.chatService, accountStorage: app.accountStorage) - let presenter = ImportPresenter(interactor: interactor, router: router) - let view = ImportView().environmentObject(presenter) - let viewController = SceneViewController(viewModel: presenter, content: view) - - router.viewController = viewController - - return viewController - } - -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportPresenter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportPresenter.swift deleted file mode 100644 index cecd2569f..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportPresenter.swift +++ /dev/null @@ -1,79 +0,0 @@ -import UIKit -import Combine -import WalletConnectModal - -final class ImportPresenter: ObservableObject { - - private let interactor: ImportInteractor - private let router: ImportRouter - private var disposeBag = Set() - - @Published var input: String = .empty - - init(interactor: ImportInteractor, router: ImportRouter) { - defer { setupInitialState() } - self.interactor = interactor - self.router = router - } - - @MainActor - func didPressWalletConnectModal() async throws { - router.presentWalletConnectModal() - - let session: Session = try await withCheckedThrowingContinuation { continuation in - var cancellable: AnyCancellable? - cancellable = WalletConnectModal.instance.sessionSettlePublisher.sink { session in - defer { cancellable?.cancel() } - return continuation.resume(returning: session) - } - } - - guard let account = session.accounts.first(where: { $0.blockchain.absoluteString == "eip155:1" }) else { - throw AlertError(message: "No matching accounts found in namespaces") - } - - try await importAccount(.web3Modal(account: account, topic: session.topic)) - } - - @MainActor - func didPressImport() async throws { - guard let account = ImportAccount(input: input) - else { return input = .empty } - try await importAccount(account) - } - - - func didPressRandom() async throws { - let account = ImportAccount.new() - try await importAccount(account) - } -} - -// MARK: SceneViewModel - -extension ImportPresenter: SceneViewModel { - - var sceneTitle: String? { - return "Import account" - } - - var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { - return .always - } -} - -// MARK: Privates - -private extension ImportPresenter { - - func setupInitialState() { - - } - - @MainActor - func importAccount(_ importAccount: ImportAccount) async throws { - try await interactor.register(importAccount: importAccount) - interactor.save(importAccount: importAccount) - router.presentChat(importAccount: importAccount) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportRouter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportRouter.swift deleted file mode 100644 index db0aec97f..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportRouter.swift +++ /dev/null @@ -1,22 +0,0 @@ -import UIKit -import WalletConnectModal -import WalletConnectPairing - -final class ImportRouter { - - weak var viewController: UIViewController! - - private let app: Application - - init(app: Application) { - self.app = app - } - - func presentWalletConnectModal() { - WalletConnectModal.present(from: viewController) - } - - func presentChat(importAccount: ImportAccount) { - MainModule.create(app: app, importAccount: importAccount).present() - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportView.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportView.swift deleted file mode 100644 index e7aac0269..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Import/ImportView.swift +++ /dev/null @@ -1,48 +0,0 @@ -import SwiftUI -import WalletConnectModal - -struct ImportView: View { - - @EnvironmentObject var presenter: ImportPresenter - - var body: some View { - VStack(spacing: 8.0) { - Image("profile_icon") - .resizable() - .frame(width: 128, height: 128) - .padding(.top, 24.0) - - TextFieldView(title: "Private key", placeholder: "4dc0055d1831…", input: $presenter.input) - - Spacer() - - VStack { - - BrandButton(title: "WalletConnectModal WIP") { - try await presenter.didPressWalletConnectModal() - } - - BrandButton(title: "Ok, done" ) { - try await presenter.didPressImport() - } - } - .padding(16.0) - - PlainButton { - try await presenter.didPressRandom() - } label: { - Text("Create new account") - .foregroundColor(.white) - } - .padding(.bottom, 16) - } - } -} - -#if DEBUG -struct ImportView_Previews: PreviewProvider { - static var previews: some View { - ImportView() - } -} -#endif diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InviteInteractor.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InviteInteractor.swift deleted file mode 100644 index f56f3b6eb..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InviteInteractor.swift +++ /dev/null @@ -1,22 +0,0 @@ -import WalletConnectSigner - -final class InviteInteractor { - - private let accountStorage: AccountStorage - private let chatService: ChatService - - init(accountStorage: AccountStorage, chatService: ChatService) { - self.accountStorage = accountStorage - self.chatService = chatService - } - - func invite(inviterAccount: Account, inviteeAccount: Account, message: String) async throws { - try await chatService.invite(inviterAccount: inviterAccount, inviteeAccount: inviteeAccount, message: message) - } - - func resolve(ens: String) async throws -> Account { - let resolver = ENSResolverFactory(crypto: DefaultCryptoProvider()).create() - let blochain = Blockchain("eip155:1")! - return try await resolver.resolveAddress(ens: ens, blockchain: Blockchain("eip155:1")!) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InviteModule.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InviteModule.swift deleted file mode 100644 index a114a92c3..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InviteModule.swift +++ /dev/null @@ -1,18 +0,0 @@ -import SwiftUI - -final class InviteModule { - - @discardableResult - static func create(app: Application, account: Account) -> UIViewController { - let router = InviteRouter(app: app) - let interactor = InviteInteractor(accountStorage: app.accountStorage, chatService: app.chatService) - let presenter = InvitePresenter(interactor: interactor, router: router, account: account) - let view = InviteView().environmentObject(presenter) - let viewController = SceneViewController(viewModel: presenter, content: view) - - router.viewController = viewController - - return viewController - } - -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InvitePresenter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InvitePresenter.swift deleted file mode 100644 index 7cc915aac..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InvitePresenter.swift +++ /dev/null @@ -1,92 +0,0 @@ -import UIKit -import Combine -import Web3 - -final class InvitePresenter: ObservableObject { - - private let interactor: InviteInteractor - private let router: InviteRouter - private let account: Account - private var disposeBag = Set() - - @Published var input: String = .empty { - didSet { didInputChanged() } - } - - var showButton: Bool { - return validation(from: input) - } - - init(interactor: InviteInteractor, router: InviteRouter, account: Account) { - self.interactor = interactor - self.router = router - self.account = account - } - - @MainActor - func invite() async throws { - let inviteeAccount = try await resolveAccount(from: input) - - try await interactor.invite(inviterAccount: account, inviteeAccount: inviteeAccount, message: "Welcome to WalletConnect Chat!") - - await dismiss() - } -} - -// MARK: SceneViewModel - -extension InvitePresenter: SceneViewModel { - - var sceneTitle: String? { - return "New Chat" - } - - var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { - return .always - } -} - -// MARK: Privates - -private extension InvitePresenter { - - @MainActor - func dismiss() async { - router.dismiss() - } - - func didInputChanged() { - rightBarButtonItem?.isEnabled = !input.isEmpty - } - - func validation(from input: String) -> Bool { - if let _ = Account(input) { - return true - } - if let _ = ImportAccount(input: input)?.account { - return true - } - if let _ = try? EthereumAddress(hex: input, eip55: false) { - return true - } - - let components = input.components(separatedBy: ".") - if components.count > 1, !components.contains("") { - return true - } - return false - } - - func resolveAccount(from input: String) async throws -> Account { - if let account = Account(input) { - return account - } - if let account = ImportAccount(input: input)?.account { - return account - } - if let address = try? EthereumAddress(hex: input, eip55: false) { - return Account("eip155:1:\(address.hex(eip55: true))")! - } - return try await interactor.resolve(ens: input) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InviteRouter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InviteRouter.swift deleted file mode 100644 index 5ef3c420b..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InviteRouter.swift +++ /dev/null @@ -1,16 +0,0 @@ -import UIKit - -final class InviteRouter { - - weak var viewController: UIViewController! - - private let app: Application - - init(app: Application) { - self.app = app - } - - func dismiss() { - viewController.dismiss() - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InviteView.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InviteView.swift deleted file mode 100644 index 178faed50..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Invite/InviteView.swift +++ /dev/null @@ -1,43 +0,0 @@ -import SwiftUI - -struct InviteView: View { - - @EnvironmentObject var presenter: InvitePresenter - - var body: some View { - VStack(spacing: 32) { - TextFieldView(title: "ENS Name or Public Key", placeholder: "username.eth or 0x0…", input: $presenter.input) - - if presenter.showButton { - PlainButton { - try await presenter.invite() - } label: { - HStack(spacing: 8.0) { - Image("plus_icon") - .resizable() - .frame(width: 24, height: 24) - Text("Invite") - .foregroundColor(.w_foreground) - .font(.system(size: 18, weight: .semibold)) - } - .padding(.trailing, 8.0) - } - .frame(width: 128, height: 44) - .background( - Capsule() - .foregroundColor(.w_greenForground) - ) - } - - Spacer() - } - } -} - -#if DEBUG -struct InviteView_Previews: PreviewProvider { - static var previews: some View { - InviteView() - } -} -#endif diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListInteractor.swift b/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListInteractor.swift deleted file mode 100644 index 0444c487d..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListInteractor.swift +++ /dev/null @@ -1,33 +0,0 @@ -import WalletConnectChat - -final class InviteListInteractor { - private let chatService: ChatService - - init(chatService: ChatService) { - self.chatService = chatService - } - - func getReceivedInvites(account: Account) -> [ReceivedInvite] { - return chatService.getReceivedInvites(account: account) - } - - func getSentInvites(account: Account) -> [SentInvite] { - return chatService.getSentInvites(account: account) - } - - func receivedInvitesSubscription() -> Stream<[ReceivedInvite]> { - return chatService.receivedInvitePublisher - } - - func sentInvitesSubscription() -> Stream<[SentInvite]> { - return chatService.sentInvitePublisher - } - - func accept(invite: ReceivedInvite) async throws { - try await chatService.accept(invite: invite) - } - - func reject(invite: ReceivedInvite) async throws { - try await chatService.reject(invite: invite) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListModule.swift b/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListModule.swift deleted file mode 100644 index 91d870eb2..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListModule.swift +++ /dev/null @@ -1,18 +0,0 @@ -import SwiftUI - -final class InviteListModule { - - @discardableResult - static func create(app: Application, account: Account, type: InviteType) -> UIViewController { - let router = InviteListRouter(app: app) - let interactor = InviteListInteractor(chatService: app.chatService) - let presenter = InviteListPresenter(interactor: interactor, router: router, account: account, inviteType: type) - let view = InviteListView().environmentObject(presenter) - let viewController = SceneViewController(viewModel: presenter, content: view) - - router.viewController = viewController - - return viewController - } - -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListPresenter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListPresenter.swift deleted file mode 100644 index 69116cc9b..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListPresenter.swift +++ /dev/null @@ -1,92 +0,0 @@ -import UIKit -import Combine -import WalletConnectChat - -final class InviteListPresenter: ObservableObject { - - private let interactor: InviteListInteractor - private let router: InviteListRouter - private let account: Account - private let inviteType: InviteType - private var disposeBag = Set() - - var invites: [InviteViewModel] { - switch inviteType { - case .received: - return receivedInviteViewModels - case .sent: - return sentInviteViewModels - } - } - - @Published private var receivedInvites: [ReceivedInvite] = [] - @Published private var sentInvites: [SentInvite] = [] - - private var receivedInviteViewModels: [InviteViewModel] { - return receivedInvites - .sorted(by: { $0.timestamp > $1.timestamp }) - .map { InviteViewModel(invite: $0) } - } - - private var sentInviteViewModels: [InviteViewModel] { - return sentInvites - .sorted(by: { $0.timestamp > $1.timestamp }) - .map { InviteViewModel(invite: $0) } - } - - init(interactor: InviteListInteractor, router: InviteListRouter, account: Account, inviteType: InviteType) { - defer { setupInitialState() } - self.interactor = interactor - self.router = router - self.account = account - self.inviteType = inviteType - } - - func didPressAccept(invite: InviteViewModel) async throws { - guard let invite = invite.receivedInvite else { return } - try await interactor.accept(invite: invite) - } - - func didPressReject(invite: InviteViewModel) async throws { - guard let invite = invite.receivedInvite else { return } - try await interactor.reject(invite: invite) - } -} - -// MARK: SceneViewModel - -extension InviteListPresenter: SceneViewModel { - - var sceneTitle: String? { - return inviteType.title - } - - var largeTitleDisplayMode: UINavigationItem.LargeTitleDisplayMode { - return .always - } -} - -// MARK: Privates - -private extension InviteListPresenter { - - func setupInitialState() { - receivedInvites = interactor.getReceivedInvites(account: account) - sentInvites = interactor.getSentInvites(account: account) - - interactor.receivedInvitesSubscription() - .sink { [unowned self] receivedInvites in - self.receivedInvites = receivedInvites - }.store(in: &disposeBag) - - interactor.sentInvitesSubscription() - .sink { [unowned self] sentInvites in - self.sentInvites = sentInvites - }.store(in: &disposeBag) - } - - @MainActor - func dismiss() { - router.dismiss() - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListRouter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListRouter.swift deleted file mode 100644 index f153598f7..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListRouter.swift +++ /dev/null @@ -1,16 +0,0 @@ -import UIKit - -final class InviteListRouter { - - weak var viewController: UIViewController! - - private let app: Application - - init(app: Application) { - self.app = app - } - - func dismiss() { - viewController.pop() - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListView.swift b/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListView.swift deleted file mode 100644 index e4adb21a3..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/InviteListView.swift +++ /dev/null @@ -1,80 +0,0 @@ -import SwiftUI - -struct InviteListView: View { - - @EnvironmentObject var presenter: InviteListPresenter - - var body: some View { - ScrollView { - VStack { - Spacer() - .frame(height: 16.0) - - ForEach(presenter.invites) { invite in - HStack(spacing: 16.0) { - Image("avatar") - .resizable() - .frame(width: 64.0, height: 64.0) - - VStack(alignment: .leading) { - Text(invite.title) - .font(.title3) - .foregroundColor(.w_foreground) - .lineLimit(1) - - Text(invite.subtitle) - .font(.subheadline) - .foregroundColor(.w_secondaryForeground) - .multilineTextAlignment(.leading) - } - - Spacer() - - if invite.showActions { - HStack(spacing: 8.0) { - PlainButton { - try await presenter.didPressAccept(invite: invite) - } label: { - Image("checkmark_icon") - .resizable() - .frame(width: 32, height: 32) - } - - PlainButton { - try await presenter.didPressReject(invite: invite) - } label: { - Image("cross_icon") - .resizable() - .frame(width: 32, height: 32) - } - } - .padding(4.0) - .background( - Capsule() - .foregroundColor(.w_secondaryBackground) - ) - .overlay( - Capsule() - .stroke(Color.w_tertiaryBackground, lineWidth: 0.5) - ) - } else { - Text(invite.statusTitle) - .font(.subheadline) - .foregroundColor(.w_secondaryForeground) - } - } - .frame(height: 64.0) - } - .padding(16.0) - } - } - } -} - -#if DEBUG -struct InviteListView_Previews: PreviewProvider { - static var previews: some View { - InviteListView() - } -} -#endif diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/Models/InviteType.swift b/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/Models/InviteType.swift deleted file mode 100644 index 1191f5a9e..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/Models/InviteType.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Foundation - -enum InviteType { - case received - case sent - - var title: String { - switch self { - case .received: - return "Chat Requests" - case .sent: - return "Sent Invites" - } - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/Models/InviteViewModel.swift b/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/Models/InviteViewModel.swift deleted file mode 100644 index e91092042..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/InviteList/Models/InviteViewModel.swift +++ /dev/null @@ -1,34 +0,0 @@ -import Foundation -import WalletConnectChat - -struct InviteViewModel: Identifiable { - - let id: Int64 - let title: String - let subtitle: String - let showActions: Bool - let statusTitle: String - - let receivedInvite: ReceivedInvite? - let sentInvite: SentInvite? - - init(invite: ReceivedInvite) { - self.id = invite.id - self.title = invite.inviterAccount.address - self.subtitle = invite.message - self.showActions = invite.status == .pending - self.statusTitle = invite.status.rawValue.capitalized - self.receivedInvite = invite - self.sentInvite = nil - } - - init(invite: SentInvite) { - self.id = invite.id - self.title = invite.inviteeAccount.address - self.subtitle = invite.message - self.showActions = false - self.statusTitle = invite.status.rawValue.capitalized - self.sentInvite = invite - self.receivedInvite = nil - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainModule.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainModule.swift deleted file mode 100644 index 2139862bf..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainModule.swift +++ /dev/null @@ -1,16 +0,0 @@ -import SwiftUI - -final class MainModule { - - @discardableResult - static func create(app: Application, importAccount: ImportAccount) -> UIViewController { - let router = MainRouter(app: app) - let presenter = MainPresenter(router: router, importAccount: importAccount) - let viewController = MainViewController(presenter: presenter) - - router.viewController = viewController - - return viewController - } - -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainPresenter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainPresenter.swift deleted file mode 100644 index fc52791a8..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainPresenter.swift +++ /dev/null @@ -1,24 +0,0 @@ -import UIKit -import Combine - -final class MainPresenter { - - private let importAccount: ImportAccount - private let router: MainRouter - - var tabs: [TabPage] { - return TabPage.allCases - } - - var viewControllers: [UIViewController] { - return [ - router.chatViewController(account: importAccount.account), - router.web3InboxViewController(importAccount: importAccount), - ] - } - - init(router: MainRouter, importAccount: ImportAccount) { - self.importAccount = importAccount - self.router = router - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainRouter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainRouter.swift deleted file mode 100644 index e0fc6d0e6..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainRouter.swift +++ /dev/null @@ -1,20 +0,0 @@ -import UIKit - -final class MainRouter { - - weak var viewController: UIViewController! - - private let app: Application - - func chatViewController(account: Account) -> UIViewController { - return ChatListModule.create(app: app, account: account).wrapToNavigationController() - } - - func web3InboxViewController(importAccount: ImportAccount) -> UIViewController { - return Web3InboxModule.create(app: app, importAccount: importAccount).wrapToNavigationController() - } - - init(app: Application) { - self.app = app - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainViewController.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainViewController.swift deleted file mode 100644 index 5fd88ac40..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Main/MainViewController.swift +++ /dev/null @@ -1,38 +0,0 @@ -import UIKit - -final class MainViewController: UITabBarController { - - private let presenter: MainPresenter - - init(presenter: MainPresenter) { - self.presenter = presenter - super.init(nibName: nil, bundle: nil) - } - - override func viewDidLoad() { - super.viewDidLoad() - - setupTabs() - } - - private func setupTabs() { - let viewControllers = presenter.viewControllers - - for (index, viewController) in viewControllers.enumerated() { - let model = presenter.tabs[index] - let item = UITabBarItem() - item.title = model.title - item.image = model.icon - item.isEnabled = TabPage.enabledTabs.contains(model) - viewController.tabBarItem = item - viewController.view.backgroundColor = .w_background - } - - self.viewControllers = viewControllers - self.selectedIndex = TabPage.selectedIndex - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Main/Model/TabPage.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Main/Model/TabPage.swift deleted file mode 100644 index 2e6e3b43b..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Main/Model/TabPage.swift +++ /dev/null @@ -1,32 +0,0 @@ -import UIKit - -enum TabPage: CaseIterable { - case chat - case web3Inbox - - var title: String { - switch self { - case .chat: - return "Chat" - case .web3Inbox: - return "Web3Inbox" - } - } - - var icon: UIImage { - switch self { - case .chat: - return UIImage(systemName: "message.fill")! - case .web3Inbox: - return UIImage(systemName: "safari.fill")! - } - } - - static var selectedIndex: Int { - return 0 - } - - static var enabledTabs: [TabPage] { - return [.chat, .web3Inbox] - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift deleted file mode 100644 index cb76537c5..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeInteractor.swift +++ /dev/null @@ -1,49 +0,0 @@ -import Foundation -import Combine - -import WalletConnectRelay -import WalletConnectPairing -import Auth - -final class WelcomeInteractor { - private var disposeBag = Set() - - private let chatService: ChatService - private let accountStorage: AccountStorage - - init(chatService: ChatService, accountStorage: AccountStorage) { - self.chatService = chatService - self.accountStorage = accountStorage - } - - var importAccount: ImportAccount? { - return accountStorage.importAccount - } - - func isAuthorized() -> Bool { - accountStorage.importAccount != nil - } - - func trackConnection() -> Stream { - return chatService.connectionPublisher - } - - func generateUri() async -> WalletConnectURI { - return try! await Pair.instance.create() - } - - func goPublic() async throws { - guard let importAccount = importAccount else { return } - try await chatService.goPublic(account: importAccount.account) - } -} - -protocol IATProvider { - var iat: String { get } -} - -struct DefaultIATProvider: IATProvider { - var iat: String { - return ISO8601DateFormatter().string(from: Date()) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeModule.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeModule.swift deleted file mode 100644 index 47922543d..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeModule.swift +++ /dev/null @@ -1,18 +0,0 @@ -import SwiftUI - -final class WelcomeModule { - - @discardableResult - static func create(app: Application) -> UIViewController { - let router = WelcomeRouter(app: app) - let interactor = WelcomeInteractor(chatService: app.chatService, accountStorage: app.accountStorage) - let presenter = WelcomePresenter(router: router, interactor: interactor) - let view = WelcomeView().environmentObject(presenter) - let viewController = UIHostingController(rootView: view) - - router.viewController = viewController - - return viewController - } - -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomePresenter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomePresenter.swift deleted file mode 100644 index 2cf58ec21..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomePresenter.swift +++ /dev/null @@ -1,40 +0,0 @@ -import UIKit -import Combine -import Auth - -final class WelcomePresenter: ObservableObject { - - private let router: WelcomeRouter - private let interactor: WelcomeInteractor - - private var disposeBag = Set() - - init(router: WelcomeRouter, interactor: WelcomeInteractor) { - defer { setupInitialState() } - self.router = router - self.interactor = interactor - } - - var buttonTitle: String { - return interactor.isAuthorized() ? "Start Messaging" : "Connect wallet" - } - - @MainActor - func didPressImport() async throws { - if let importAccount = interactor.importAccount { - try await interactor.goPublic() - router.presentMain(importAccount: importAccount) - } else { - router.presentImport() - } - } -} - -private extension WelcomePresenter { - - func setupInitialState() { - interactor.trackConnection().sink { status in - print("Socket connection status: \(status)") - }.store(in: &disposeBag) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeRouter.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeRouter.swift deleted file mode 100644 index da574fb23..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeRouter.swift +++ /dev/null @@ -1,27 +0,0 @@ -import UIKit - -final class WelcomeRouter { - - weak var viewController: UIViewController! - - private let app: Application - - init(app: Application) { - self.app = app - } - - func presentImport() { - ImportModule.create(app: app) - .wrapToNavigationController() - .present() - } - - func presentMain(importAccount: ImportAccount) { - MainModule.create(app: app, importAccount: importAccount) - .present() - } - - func openWallet(uri: String) { - UIApplication.shared.open(URL(string: "walletapp://wc?uri=\(uri)")!) - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeView.swift b/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeView.swift deleted file mode 100644 index 05609b612..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Chat/Welcome/WelcomeView.swift +++ /dev/null @@ -1,61 +0,0 @@ -import SwiftUI - -struct WelcomeView: View { - - @State private var offset: CGFloat = 0 - - @EnvironmentObject var presenter: WelcomePresenter - - var body: some View { - GeometryReader { _ in - ZStack { - Image("LaunchScreen") - .resizable() - .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height) - .scaledToFill() - - VStack { - Spacer() - Image("LaunchLogo") - .offset(y: offset) - Spacer() - } - - VStack(spacing: 16) { - Text("Chat") - .foregroundColor(.w_greenForground) - .font(.system(size: 50.0, weight: .bold)) - - Text("Direct messaging between users, using their web3 wallets.") - .font(.title2) - .foregroundColor(.w_foreground) - .multilineTextAlignment(.center) - - BrandButton(title: presenter.buttonTitle) { - try await presenter.didPressImport() - } - - Text("By connecting your wallet you agree with our\nTerms of Service") - .font(.footnote) - .foregroundColor(.white.opacity(0.7)) - .multilineTextAlignment(.center) - } - .padding(.horizontal, 16.0) - } - .edgesIgnoringSafeArea(.all) - .onAppear { - withAnimation(.spring()) { - offset = -(UIScreen.main.bounds.height / 4) - } - } - } - } -} - -#if DEBUG -struct WelcomeView_Previews: PreviewProvider { - static var previews: some View { - WelcomeView() - } -} -#endif diff --git a/Example/Showcase/Classes/PresentationLayer/Web3Inbox/Web3InboxModule.swift b/Example/Showcase/Classes/PresentationLayer/Web3Inbox/Web3InboxModule.swift deleted file mode 100644 index 9b96061fd..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Web3Inbox/Web3InboxModule.swift +++ /dev/null @@ -1,13 +0,0 @@ -import SwiftUI - -final class Web3InboxModule { - - @discardableResult - static func create(app: Application, importAccount: ImportAccount) -> UIViewController { - let router = Web3InboxRouter(app: app) - let viewController = Web3InboxViewController(importAccount: importAccount) - router.viewController = viewController - return viewController - } - -} diff --git a/Example/Showcase/Classes/PresentationLayer/Web3Inbox/Web3InboxRouter.swift b/Example/Showcase/Classes/PresentationLayer/Web3Inbox/Web3InboxRouter.swift deleted file mode 100644 index 3631c35be..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Web3Inbox/Web3InboxRouter.swift +++ /dev/null @@ -1,12 +0,0 @@ -import UIKit - -final class Web3InboxRouter { - - weak var viewController: UIViewController! - - private let app: Application - - init(app: Application) { - self.app = app - } -} diff --git a/Example/Showcase/Classes/PresentationLayer/Web3Inbox/Web3InboxViewController.swift b/Example/Showcase/Classes/PresentationLayer/Web3Inbox/Web3InboxViewController.swift deleted file mode 100644 index c6a2d32d6..000000000 --- a/Example/Showcase/Classes/PresentationLayer/Web3Inbox/Web3InboxViewController.swift +++ /dev/null @@ -1,40 +0,0 @@ -import UIKit -import WebKit -import Web3Inbox - -final class Web3InboxViewController: UIViewController { - - private let importAccount: ImportAccount - - init(importAccount: ImportAccount) { - self.importAccount = importAccount - super.init(nibName: nil, bundle: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - Web3Inbox.configure(account: importAccount.account, bip44: DefaultBIP44Provider(), config: [.notifyEnabled: false], environment: .sandbox, crypto: DefaultCryptoProvider(), onSign: onSing) - - edgesForExtendedLayout = [] - navigationItem.title = "Web3Inbox SDK" - navigationItem.largeTitleDisplayMode = .never - view = Web3Inbox.instance.getWebView() - } -} - -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) - } -} diff --git a/Example/Showcase/Common/Components/BrandButton.swift b/Example/Showcase/Common/Components/BrandButton.swift deleted file mode 100644 index 6fee139db..000000000 --- a/Example/Showcase/Common/Components/BrandButton.swift +++ /dev/null @@ -1,25 +0,0 @@ -import SwiftUI -import AsyncButton - -struct BrandButton: View { - let title: String - let action: () async throws -> Void - - var body: some View { - AsyncButton(options: [.automatic]) { - try await action() - } label: { - Text(title) - .foregroundColor(.w_foreground) - .font(.system(size: 20, weight: .bold)) - .frame(maxWidth: .infinity) - .frame(height: 56) - .background( - Capsule() - .foregroundColor(.w_greenForground) - ) - } - } -} - - diff --git a/Example/Showcase/Common/Components/InputView.swift b/Example/Showcase/Common/Components/InputView.swift deleted file mode 100644 index 059f9ac6a..000000000 --- a/Example/Showcase/Common/Components/InputView.swift +++ /dev/null @@ -1,28 +0,0 @@ -import SwiftUI - -struct InputView: View { - - let title: String - let text: Binding - let action: () -> Void - - var body: some View { - ZStack { - TextField(title, text: text) - .disableAutocorrection(true) - .frame(minHeight: 44.0) - .padding(EdgeInsets(top: 0, leading: 16, bottom: 0, trailing: 16)) - .background( - Capsule() - .foregroundColor(.w_secondaryBackground) - ) - .overlay( - Capsule() - .stroke(Color.w_tertiaryBackground, lineWidth: 0.5) - ) - .onSubmit { - action() - } - } - } -} diff --git a/Example/Showcase/Common/Components/PlainButton.swift b/Example/Showcase/Common/Components/PlainButton.swift deleted file mode 100644 index 1baa3cb9c..000000000 --- a/Example/Showcase/Common/Components/PlainButton.swift +++ /dev/null @@ -1,16 +0,0 @@ -import SwiftUI -import AsyncButton - -struct PlainButton