diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml
index d47aa4129..ca91b0389 100644
--- a/.github/workflows/swift.yml
+++ b/.github/workflows/swift.yml
@@ -19,7 +19,11 @@ jobs:
run: swift build -v
- name: Run tests
run: swift test -v
- - name: Test Example App
+ - name: Test Wallet
working-directory: ./Example
- run: fastlane test_app
+ run: fastlane test_wallet
+ - name: Test Dapp
+ working-directory: ./Example
+ run: fastlane test_dapp
+
diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/IntegrationTests.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/IntegrationTests.xcscheme
new file mode 100644
index 000000000..0236cb7e7
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/IntegrationTests.xcscheme
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnect.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnect.xcscheme
index ce6b1b1ca..138656d6e 100644
--- a/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnect.xcscheme
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/WalletConnect.xcscheme
@@ -62,6 +62,20 @@
ReferencedContainer = "container:">
+
+
+
+
())?
+
+ private let accountsView: AccountsView = {
+ AccountsView()
+ }()
+
+ init(session: Session) {
+ self.session = session
+ super.init(nibName: nil, bundle: nil)
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ override func loadView() {
+ view = accountsView
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ navigationItem.title = "Accounts"
+
+ navigationItem.rightBarButtonItem = UIBarButtonItem(
+ title: "Disconnect",
+ style: .plain,
+ target: self,
+ action: #selector(disconnect)
+ )
+ accountsView.tableView.dataSource = self
+ accountsView.tableView.delegate = self
+ client.logger.setLogging(level: .debug)
+ session.accounts.forEach { account in
+ let splits = account.split(separator: ":", omittingEmptySubsequences: false)
+ guard splits.count == 3 else { return }
+ let chain = String(splits[0] + ":" + splits[1])
+ accountsDetails.append(AccountDetails(chain: chain, methods: Array(session.permissions.methods), account: account))
+ }
+ }
+
+ @objc
+ private func disconnect() {
+ client.disconnect(topic: session.topic, reason: Reason(code: 0, message: "disconnect"))
+ onDisconnect?()
+ }
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ accountsDetails.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: "accountCell", for: indexPath)
+ let details = accountsDetails[indexPath.row]
+ cell.textLabel?.text = details.account
+ cell.imageView?.image = UIImage(named: details.chain)
+ cell.textLabel?.numberOfLines = 0
+ return cell
+ }
+
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ showAccountRequestScreen(accountsDetails[indexPath.row])
+ }
+
+ func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+ return 70
+ }
+
+ func showAccountRequestScreen(_ details: AccountDetails) {
+ let vc = AccountRequestViewController(session: session, accountDetails: details)
+ navigationController?.pushViewController(vc, animated: true)
+ }
+
+}
diff --git a/Example/DApp/AccountRequest/AccountRequestView.swift b/Example/DApp/AccountRequest/AccountRequestView.swift
new file mode 100644
index 000000000..3f446422f
--- /dev/null
+++ b/Example/DApp/AccountRequest/AccountRequestView.swift
@@ -0,0 +1,69 @@
+
+import UIKit
+import Foundation
+
+class AccountRequestView: UIView {
+ let iconView: UIImageView = {
+ let imageView = UIImageView()
+ imageView.contentMode = .scaleAspectFit
+ imageView.backgroundColor = .systemFill
+ imageView.layer.cornerRadius = 32
+ return imageView
+ }()
+
+ let chainLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont.systemFont(ofSize: 17.0, weight: .heavy)
+ return label
+ }()
+ let accountLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont.preferredFont(forTextStyle: .subheadline)
+ label.textColor = .secondaryLabel
+ label.numberOfLines = 0
+ label.textAlignment = .center
+ return label
+ }()
+
+ let headerStackView: UIStackView = {
+ let stackView = UIStackView()
+ stackView.axis = .vertical
+ stackView.spacing = 16
+ stackView.alignment = .center
+ return stackView
+ }()
+
+ let tableView = UITableView()
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ backgroundColor = .systemBackground
+ tableView.register(UITableViewCell.self, forCellReuseIdentifier: "method_cell")
+ addSubview(iconView)
+ addSubview(headerStackView)
+ addSubview(tableView)
+
+ headerStackView.addArrangedSubview(chainLabel)
+ headerStackView.addArrangedSubview(accountLabel)
+
+ subviews.forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
+
+ NSLayoutConstraint.activate([
+ iconView.topAnchor.constraint(equalTo: topAnchor, constant: 64),
+ iconView.centerXAnchor.constraint(equalTo: centerXAnchor),
+
+ headerStackView.topAnchor.constraint(equalTo: iconView.bottomAnchor, constant: 32),
+ headerStackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 32),
+ headerStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -32),
+
+ tableView.topAnchor.constraint(equalTo: headerStackView.bottomAnchor, constant: 0),
+ tableView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0),
+ tableView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0),
+ tableView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor),
+ ])
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+}
diff --git a/Example/DApp/AccountRequest/AccountRequestViewController.swift b/Example/DApp/AccountRequest/AccountRequestViewController.swift
new file mode 100644
index 000000000..5fdab0d97
--- /dev/null
+++ b/Example/DApp/AccountRequest/AccountRequestViewController.swift
@@ -0,0 +1,166 @@
+
+
+import Foundation
+import UIKit
+import WalletConnect
+import WalletConnectUtils
+
+class AccountRequestViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
+ private let session: Session
+ private let client: WalletConnectClient = ClientDelegate.shared.client
+ private let chainId: String
+ private let account: String
+ private let methods = ["eth_sendTransaction", "personal_sign", "eth_signTypedData"]
+ private let accountRequestView = {
+ AccountRequestView()
+ }()
+
+ init(session: Session, accountDetails: AccountDetails) {
+ self.session = session
+ self.chainId = accountDetails.chain
+ self.account = accountDetails.account
+ super.init(nibName: nil, bundle: nil)
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ override func loadView() {
+ view = accountRequestView
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ accountRequestView.tableView.delegate = self
+ accountRequestView.tableView.dataSource = self
+ accountRequestView.iconView.image = UIImage(named: chainId)
+ accountRequestView.chainLabel.text = chainId
+ accountRequestView.accountLabel.text = account
+ }
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ methods.count
+ }
+
+ func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
+ return "Methods"
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: "method_cell", for: indexPath)
+ cell.textLabel?.text = methods[indexPath.row]
+ return cell
+ }
+
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ let method = methods[indexPath.row]
+ let requestParams = getRequest(for: method)
+
+
+ let request = Request(topic: session.topic, method: method, params: requestParams, chainId: chainId)
+ client.request(params: request)
+ presentConfirmationAlert()
+ }
+
+ private func presentConfirmationAlert() {
+ let alert = UIAlertController(title: "Request Sent", message: nil, preferredStyle: .alert)
+ let action = UIAlertAction(title: "OK", style: .cancel)
+ alert.addAction(action)
+ present(alert, animated: true)
+ }
+
+ private func getRequest(for method: String) -> AnyCodable {
+ let account = "0x9b2055d370f73ec7d8a03e965129118dc8f5bf83"
+ if method == "eth_sendTransaction" {
+ let tx = Stub.tx
+ return AnyCodable(tx)
+ } else if method == "personal_sign" {
+ return AnyCodable(["0xdeadbeaf", account])
+ } else if method == "eth_signTypedData" {
+ return AnyCodable([account, Stub.eth_signTypedData])
+ }
+ fatalError("not implemented")
+ }
+}
+
+struct Transaction: Codable {
+ let from, to, data, gas: String
+ let gasPrice, value, nonce: String
+}
+
+fileprivate enum Stub {
+ static let tx = [Transaction(from: "0x9b2055d370f73ec7d8a03e965129118dc8f5bf83",
+ to: "0x9b2055d370f73ec7d8a03e965129118dc8f5bf83",
+ data: "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675",
+ gas: "0x76c0",
+ gasPrice: "0x9184e72a000",
+ value: "0x9184e72a",
+ nonce: "0x117")]
+ static let eth_signTypedData = """
+{
+"types": {
+ "EIP712Domain": [
+ {
+ "name": "name",
+ "type": "string"
+ },
+ {
+ "name": "version",
+ "type": "string"
+ },
+ {
+ "name": "chainId",
+ "type": "uint256"
+ },
+ {
+ "name": "verifyingContract",
+ "type": "address"
+ }
+ ],
+ "Person": [
+ {
+ "name": "name",
+ "type": "string"
+ },
+ {
+ "name": "wallet",
+ "type": "address"
+ }
+ ],
+ "Mail": [
+ {
+ "name": "from",
+ "type": "Person"
+ },
+ {
+ "name": "to",
+ "type": "Person"
+ },
+ {
+ "name": "contents",
+ "type": "string"
+ }
+ ]
+},
+"primaryType": "Mail",
+"domain": {
+ "name": "Ether Mail",
+ "version": "1",
+ "chainId": 1,
+ "verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
+},
+"message": {
+ "from": {
+ "name": "Cow",
+ "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
+ },
+ "to": {
+ "name": "Bob",
+ "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"
+ },
+ "contents": "Hello, Bob!"
+}
+}
+"""
+}
diff --git a/Example/DApp/AppDelegate.swift b/Example/DApp/AppDelegate.swift
new file mode 100644
index 000000000..7256ad23d
--- /dev/null
+++ b/Example/DApp/AppDelegate.swift
@@ -0,0 +1,27 @@
+
+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 {
+ // Called when a new scene session is being created.
+ // Use this method to select a configuration to create the new scene with.
+ return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
+ }
+
+ 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.
+ }
+
+
+}
+
diff --git a/Example/DApp/Assets.xcassets/AccentColor.colorset/Contents.json b/Example/DApp/Assets.xcassets/AccentColor.colorset/Contents.json
new file mode 100644
index 000000000..eb8789700
--- /dev/null
+++ b/Example/DApp/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "colors" : [
+ {
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 000000000..78d34c2c3
--- /dev/null
+++ b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,116 @@
+{
+ "images" : [
+ {
+ "filename" : "Icon-App-20x20@2x.png",
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "20x20"
+ },
+ {
+ "filename" : "Icon-App-20x20@3x.png",
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "20x20"
+ },
+ {
+ "filename" : "Icon-App-29x29@2x.png",
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "Icon-App-29x29@3x.png",
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "Icon-App-40x40@2x.png",
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "40x40"
+ },
+ {
+ "filename" : "Icon-App-40x40@3x.png",
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "40x40"
+ },
+ {
+ "filename" : "Icon-App-60x60@2x.png",
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "60x60"
+ },
+ {
+ "filename" : "Icon-App-60x60@3x.png",
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "60x60"
+ },
+ {
+ "filename" : "Icon-App-20x20@1x.png",
+ "idiom" : "ipad",
+ "scale" : "1x",
+ "size" : "20x20"
+ },
+ {
+ "filename" : "Icon-App-20x20@2x-1.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "20x20"
+ },
+ {
+ "filename" : "Icon-App-29x29@1x.png",
+ "idiom" : "ipad",
+ "scale" : "1x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "Icon-App-29x29@2x-1.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "Icon-App-40x40@1x.png",
+ "idiom" : "ipad",
+ "scale" : "1x",
+ "size" : "40x40"
+ },
+ {
+ "filename" : "Icon-App-40x40@2x-1.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "40x40"
+ },
+ {
+ "filename" : "Icon-App-76x76@1x.png",
+ "idiom" : "ipad",
+ "scale" : "1x",
+ "size" : "76x76"
+ },
+ {
+ "filename" : "Icon-App-76x76@2x.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "76x76"
+ },
+ {
+ "filename" : "Icon-App-83.5x83.5@2x.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "83.5x83.5"
+ },
+ {
+ "filename" : "ItunesArtwork@2x.png",
+ "idiom" : "ios-marketing",
+ "scale" : "1x",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
new file mode 100644
index 000000000..e8b3b928c
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png
new file mode 100644
index 000000000..7f3a702c3
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x-1.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
new file mode 100644
index 000000000..7f3a702c3
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
new file mode 100644
index 000000000..d38db763f
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
new file mode 100644
index 000000000..941819fce
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png
new file mode 100644
index 000000000..d71e54b8d
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x-1.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
new file mode 100644
index 000000000..d71e54b8d
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
new file mode 100644
index 000000000..dd60b860b
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
new file mode 100644
index 000000000..7f3a702c3
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png
new file mode 100644
index 000000000..5c0665582
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x-1.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
new file mode 100644
index 000000000..5c0665582
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
new file mode 100644
index 000000000..0fdab5f95
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
new file mode 100644
index 000000000..0fdab5f95
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
new file mode 100644
index 000000000..3b88e179c
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
new file mode 100644
index 000000000..d0c9a1a98
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
new file mode 100644
index 000000000..03bb3d021
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
new file mode 100644
index 000000000..fd505b567
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ
diff --git a/Example/DApp/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png b/Example/DApp/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png
new file mode 100644
index 000000000..f527fe624
Binary files /dev/null and b/Example/DApp/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png differ
diff --git a/Example/DApp/Assets.xcassets/Contents.json b/Example/DApp/Assets.xcassets/Contents.json
new file mode 100644
index 000000000..73c00596a
--- /dev/null
+++ b/Example/DApp/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Example/DApp/Assets.xcassets/eip155:1.imageset/Contents.json b/Example/DApp/Assets.xcassets/eip155:1.imageset/Contents.json
new file mode 100644
index 000000000..4664aca0a
--- /dev/null
+++ b/Example/DApp/Assets.xcassets/eip155:1.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "ethereum (1).png",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Example/DApp/Assets.xcassets/eip155:1.imageset/ethereum (1).png b/Example/DApp/Assets.xcassets/eip155:1.imageset/ethereum (1).png
new file mode 100644
index 000000000..35e1cb09f
Binary files /dev/null and b/Example/DApp/Assets.xcassets/eip155:1.imageset/ethereum (1).png differ
diff --git a/Example/DApp/Assets.xcassets/eip155:137.imageset/Contents.json b/Example/DApp/Assets.xcassets/eip155:137.imageset/Contents.json
new file mode 100644
index 000000000..afd53b2a5
--- /dev/null
+++ b/Example/DApp/Assets.xcassets/eip155:137.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "filename" : "coin.png",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Example/DApp/Assets.xcassets/eip155:137.imageset/coin.png b/Example/DApp/Assets.xcassets/eip155:137.imageset/coin.png
new file mode 100644
index 000000000..318e76f50
Binary files /dev/null and b/Example/DApp/Assets.xcassets/eip155:137.imageset/coin.png differ
diff --git a/Example/DApp/Base.lproj/LaunchScreen.storyboard b/Example/DApp/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 000000000..865e9329f
--- /dev/null
+++ b/Example/DApp/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example/DApp/ClientDelegate.swift b/Example/DApp/ClientDelegate.swift
new file mode 100644
index 000000000..2fecc1d15
--- /dev/null
+++ b/Example/DApp/ClientDelegate.swift
@@ -0,0 +1,42 @@
+import WalletConnect
+
+class ClientDelegate: WalletConnectClientDelegate {
+ var client: WalletConnectClient
+ var onSessionSettled: ((Session)->())?
+ var onSessionResponse: ((Response)->())?
+ var onSessionDelete: (()->())?
+
+ static var shared: ClientDelegate = ClientDelegate()
+ private init() {
+ let metadata = AppMetadata(
+ name: "Swift Dapp",
+ description: "a description",
+ url: "wallet.connect",
+ icons: ["https://gblobscdn.gitbook.com/spaces%2F-LJJeCjcLrr53DcT1Ml7%2Favatar.png?alt=media"])
+ self.client = WalletConnectClient(
+ metadata: metadata,
+ projectId: "52af113ee0c1e1a20f4995730196c13e",
+ isController: false,
+ relayHost: "relay.dev.walletconnect.com"
+ )
+ client.delegate = self
+ }
+
+ func didSettle(session: Session) {
+ onSessionSettled?(session)
+ }
+
+ func didDelete(sessionTopic: String, reason: Reason) {
+ onSessionDelete?()
+ }
+
+ func didReceive(sessionResponse: Response) {
+ onSessionResponse?(sessionResponse)
+ }
+
+ func didUpdate(sessionTopic: String, accounts: Set) {
+ }
+
+ func didUpgrade(sessionTopic: String, permissions: Session.Permissions) {
+ }
+}
diff --git a/Example/ExampleApp/Proposer/ProposerView.swift b/Example/DApp/Connect/ConnectView.swift
similarity index 58%
rename from Example/ExampleApp/Proposer/ProposerView.swift
rename to Example/DApp/Connect/ConnectView.swift
index 687b4d2de..64165ff3d 100644
--- a/Example/ExampleApp/Proposer/ProposerView.swift
+++ b/Example/DApp/Connect/ConnectView.swift
@@ -1,6 +1,9 @@
+
+import Foundation
import UIKit
-final class ProposerView: UIView {
+final class ConnectView: UIView {
+ let tableView = UITableView()
let qrCodeView: UIImageView = {
let imageView = UIImageView()
@@ -19,25 +22,34 @@ final class ProposerView: UIView {
return button
}()
- let tableView: UITableView = {
- let tableView = UITableView(frame: .zero, style: .insetGrouped)
- tableView.backgroundColor = .tertiarySystemBackground
- tableView.register(ActiveSessionCell.self, forCellReuseIdentifier: "sessionCell")
- return tableView
+ let connectWalletButton: UIButton = {
+ let button = UIButton(type: .system)
+ button.setTitle("Connect Wallet", for: .normal)
+ button.titleLabel?.font = UIFont.systemFont(ofSize: 17.0, weight: .semibold)
+ button.backgroundColor = .systemBlue
+ button.tintColor = .white
+ button.layer.cornerRadius = 8
+ return button
}()
-
+
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .systemBackground
-
addSubview(qrCodeView)
addSubview(copyButton)
+ addSubview(connectWalletButton)
addSubview(tableView)
-
+ tableView.register(UITableViewCell.self, forCellReuseIdentifier: "pairing_cell")
subviews.forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
NSLayoutConstraint.activate([
- qrCodeView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 64),
+ tableView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor),
+ tableView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor),
+ tableView.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor),
+ tableView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor),
+
+
+ qrCodeView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 50),
qrCodeView.centerXAnchor.constraint(equalTo: centerXAnchor),
qrCodeView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.6),
qrCodeView.widthAnchor.constraint(equalTo: qrCodeView.heightAnchor),
@@ -47,10 +59,10 @@ final class ProposerView: UIView {
copyButton.widthAnchor.constraint(equalTo: qrCodeView.widthAnchor),
copyButton.heightAnchor.constraint(equalToConstant: 44),
- tableView.topAnchor.constraint(equalTo: copyButton.bottomAnchor, constant: 16),
- tableView.leadingAnchor.constraint(equalTo: leadingAnchor),
- tableView.trailingAnchor.constraint(equalTo: trailingAnchor),
- tableView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor)
+ connectWalletButton.topAnchor.constraint(equalTo: copyButton.bottomAnchor, constant: 16),
+ connectWalletButton.centerXAnchor.constraint(equalTo: centerXAnchor),
+ connectWalletButton.widthAnchor.constraint(equalTo: copyButton.widthAnchor),
+ connectWalletButton.heightAnchor.constraint(equalToConstant: 44),
])
}
diff --git a/Example/DApp/Connect/ConnectViewController.swift b/Example/DApp/Connect/ConnectViewController.swift
new file mode 100644
index 000000000..09e000a7d
--- /dev/null
+++ b/Example/DApp/Connect/ConnectViewController.swift
@@ -0,0 +1,103 @@
+
+import Foundation
+import UIKit
+import WalletConnect
+
+class ConnectViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
+ let uriString: String
+ let activePairings: [Pairing] = ClientDelegate.shared.client.getSettledPairings()
+ let segmentedControl = UISegmentedControl(items: ["Pairings", "New Pairing"])
+
+ init(uri: String) {
+ self.uriString = uri
+ super.init(nibName: nil, bundle: nil)
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ private let connectView: ConnectView = {
+ ConnectView()
+ }()
+
+ override func loadView() {
+ view = connectView
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ DispatchQueue.global().async { [unowned self] in
+ if let qrImage = generateQRCode(from: uriString) {
+ DispatchQueue.main.async {
+ connectView.qrCodeView.image = qrImage
+ connectView.copyButton.isHidden = false
+ }
+ }
+ }
+ connectView.copyButton.addTarget(self, action: #selector(copyURI), for: .touchUpInside)
+ connectView.connectWalletButton.addTarget(self, action: #selector(connectWithExampleWallet), for: .touchUpInside)
+ connectView.tableView.dataSource = self
+ connectView.tableView.delegate = self
+ connectView.copyButton.isHidden = true
+ setUpSegmentedControl()
+ }
+
+ func setUpSegmentedControl() {
+ segmentedControl.selectedSegmentIndex = 0
+ self.navigationItem.titleView = segmentedControl
+ segmentedControl.addTarget(self, action: #selector(segmentAction), for: .valueChanged)
+ }
+
+ @objc func segmentAction() {
+ if segmentedControl.selectedSegmentIndex == 0 {
+ connectView.tableView.isHidden = false
+ } else {
+ connectView.tableView.isHidden = true
+ }
+ }
+
+ @objc func copyURI() {
+ UIPasteboard.general.string = uriString
+ }
+
+
+ private func generateQRCode(from string: String) -> UIImage? {
+ let data = string.data(using: .ascii)
+ if let filter = CIFilter(name: "CIQRCodeGenerator") {
+ filter.setValue(data, forKey: "inputMessage")
+ if let output = filter.outputImage {
+ return UIImage(ciImage: output)
+ }
+ }
+ return nil
+ }
+
+ @objc func connectWithExampleWallet() {
+ let url = URL(string: "https://walletconnect.com/wc?uri=\(uriString)")!
+ UIApplication.shared.open(url, options: [:]) { [weak self] _ in
+ self?.dismiss(animated: true, completion: nil)
+ }
+ }
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ activePairings.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: "pairing_cell", for: indexPath)
+ cell.textLabel?.text = activePairings[indexPath.row].peer!.name
+ return cell
+ }
+
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ let pairingTopic = activePairings[indexPath.row].topic
+ let permissions = Session.Permissions(
+ blockchains: ["eip155:1", "eip155:137"],
+ methods: ["eth_sendTransaction", "personal_sign", "eth_signTypedData"],
+ notifications: []
+ )
+ _ = try! ClientDelegate.shared.client.connect(sessionPermissions: permissions, topic: pairingTopic)
+ connectWithExampleWallet()
+ }
+}
diff --git a/Example/DApp/Info.plist b/Example/DApp/Info.plist
new file mode 100644
index 000000000..7c5f0be1e
--- /dev/null
+++ b/Example/DApp/Info.plist
@@ -0,0 +1,25 @@
+
+
+
+
+ ITSAppUsesNonExemptEncryption
+
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+ UIWindowSceneSessionRoleApplication
+
+
+ UISceneConfigurationName
+ Default Configuration
+ UISceneDelegateClassName
+ $(PRODUCT_MODULE_NAME).SceneDelegate
+
+
+
+
+
+
diff --git a/Example/DApp/ResponseViewController.swift b/Example/DApp/ResponseViewController.swift
new file mode 100644
index 000000000..e85baaafe
--- /dev/null
+++ b/Example/DApp/ResponseViewController.swift
@@ -0,0 +1,109 @@
+
+import Foundation
+import WalletConnect
+import UIKit
+
+class ResponseViewController: UIViewController {
+ let response: Response
+ private let responseView = {
+ ResponseView()
+ }()
+
+ init(response: Response) {
+ self.response = response
+ super.init(nibName: nil, bundle: nil)
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ override func loadView() {
+ view = responseView
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ let record = ClientDelegate.shared.client.getSessionRequestRecord(id: response.result.id)!
+ switch response.result {
+ case .response(let response):
+ responseView.nameLabel.text = "Received Response\n\(record.request.method)"
+ responseView.descriptionLabel.text = try! response.result.get(String.self).description
+ case .error(let error):
+ responseView.nameLabel.text = "Received Error\n\(record.request.method)"
+ responseView.descriptionLabel.text = error.error.message
+ }
+ responseView.dismissButton.addTarget(self, action: #selector(dismissSelf), for: .touchUpInside)
+ }
+
+ @objc func dismissSelf() {
+ dismiss(animated: true, completion: nil)
+ }
+}
+
+
+final class ResponseView: UIView {
+
+ let nameLabel: UILabel = {
+ let label = UILabel()
+ label.numberOfLines = 0
+ label.font = UIFont.systemFont(ofSize: 17.0, weight: .heavy)
+ return label
+ }()
+
+ let descriptionLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont.preferredFont(forTextStyle: .subheadline)
+ label.textColor = .secondaryLabel
+ label.numberOfLines = 0
+ label.textAlignment = .center
+ return label
+ }()
+
+ let dismissButton: UIButton = {
+ let button = UIButton(type: .system)
+ button.setTitle("Dismiss", for: .normal)
+ button.backgroundColor = .systemBlue
+ button.tintColor = .white
+ button.layer.cornerRadius = 8
+ button.titleLabel?.font = UIFont.systemFont(ofSize: 17.0, weight: .semibold)
+ return button
+ }()
+
+ let headerStackView: UIStackView = {
+ let stackView = UIStackView()
+ stackView.axis = .vertical
+ stackView.spacing = 16
+ stackView.alignment = .center
+ return stackView
+ }()
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ backgroundColor = .systemBackground
+
+ addSubview(headerStackView)
+ addSubview(dismissButton)
+ headerStackView.addArrangedSubview(nameLabel)
+ headerStackView.addArrangedSubview(descriptionLabel)
+
+ subviews.forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
+
+ NSLayoutConstraint.activate([
+
+ headerStackView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 32),
+ headerStackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 32),
+ headerStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -32),
+
+ dismissButton.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -16),
+ dismissButton.centerXAnchor.constraint(equalTo: safeAreaLayoutGuide.centerXAnchor, constant: 16),
+ dismissButton.heightAnchor.constraint(equalToConstant: 44),
+ dismissButton.widthAnchor.constraint(equalToConstant: 120)
+ ])
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+}
+
diff --git a/Example/DApp/SceneDelegate.swift b/Example/DApp/SceneDelegate.swift
new file mode 100644
index 000000000..ba447fb33
--- /dev/null
+++ b/Example/DApp/SceneDelegate.swift
@@ -0,0 +1,58 @@
+
+import UIKit
+import WalletConnect
+
+class SceneDelegate: UIResponder, UIWindowSceneDelegate {
+
+ var window: UIWindow?
+
+
+ func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
+ // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
+ // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
+ // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
+ guard let windowScene = (scene as? UIWindowScene) else { return }
+ window = UIWindow(windowScene: windowScene)
+ ClientDelegate.shared.onSessionDelete = { [unowned self] in
+ showSelectChainScreen()
+ }
+ ClientDelegate.shared.onSessionResponse = { [unowned self] response in
+ presentResponse(for: response)
+ }
+ if let session = ClientDelegate.shared.client.getSettledSessions().first {
+ showAccountsScreen(session)
+ } else {
+ showSelectChainScreen()
+ }
+ }
+
+ func showSelectChainScreen() {
+ DispatchQueue.main.async { [unowned self] in
+ let vc = SelectChainViewController()
+ vc.onSessionSettled = { [unowned self] session in
+ showAccountsScreen(session)
+ }
+ window?.rootViewController = UINavigationController(rootViewController: vc)
+ window?.makeKeyAndVisible()
+ }
+ }
+
+ func showAccountsScreen(_ session: Session) {
+ DispatchQueue.main.async { [unowned self] in
+ let vc = AccountsViewController(session: session)
+ vc.onDisconnect = { [unowned self] in
+ showSelectChainScreen()
+ }
+ window?.rootViewController = UINavigationController(rootViewController: vc)
+ window?.makeKeyAndVisible()
+ }
+ }
+
+ func presentResponse(for response: Response) {
+ DispatchQueue.main.async { [unowned self] in
+ let vc = UINavigationController(rootViewController: ResponseViewController(response: response))
+ window?.rootViewController?.present(vc, animated: true, completion: nil)
+ }
+ }
+}
+
diff --git a/Example/DApp/SelectChain/SelectChainView.swift b/Example/DApp/SelectChain/SelectChainView.swift
new file mode 100644
index 000000000..81891e15a
--- /dev/null
+++ b/Example/DApp/SelectChain/SelectChainView.swift
@@ -0,0 +1,48 @@
+
+import Foundation
+import UIKit
+
+
+class SelectChainView: UIView {
+ let tableView: UITableView = {
+ let tableView = UITableView(frame: .zero, style: .insetGrouped)
+ tableView.backgroundColor = .tertiarySystemBackground
+ tableView.register(UITableViewCell.self, forCellReuseIdentifier: "chain")
+ return tableView
+ }()
+ let connectButton: UIButton = {
+ let button = UIButton(type: .system)
+ button.setTitle("Connect", for: .normal)
+ button.backgroundColor = .systemBlue
+ button.tintColor = .white
+ button.layer.cornerRadius = 8
+ return button
+ }()
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ tableView.register(UITableViewCell.self, forCellReuseIdentifier: "chain_cell")
+ backgroundColor = .systemBackground
+ addSubview(tableView)
+ addSubview(connectButton)
+
+ subviews.forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
+
+ NSLayoutConstraint.activate([
+ tableView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 16),
+ tableView.leadingAnchor.constraint(equalTo: leadingAnchor),
+ tableView.trailingAnchor.constraint(equalTo: trailingAnchor),
+ tableView.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor),
+
+ connectButton.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -16),
+ connectButton.centerXAnchor.constraint(equalTo: safeAreaLayoutGuide.centerXAnchor),
+ connectButton.heightAnchor.constraint(equalToConstant: 44),
+ connectButton.widthAnchor.constraint(equalToConstant: 120),
+ ])
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+}
+
diff --git a/Example/DApp/SelectChain/SelectChainViewController.swift b/Example/DApp/SelectChain/SelectChainViewController.swift
new file mode 100644
index 000000000..88ea048ed
--- /dev/null
+++ b/Example/DApp/SelectChain/SelectChainViewController.swift
@@ -0,0 +1,71 @@
+
+
+import Foundation
+import WalletConnect
+import UIKit
+
+struct Chain {
+ let name: String
+ let id: String
+}
+
+class SelectChainViewController: UIViewController, UITableViewDataSource {
+ private let selectChainView: SelectChainView = {
+ SelectChainView()
+ }()
+ let chains = [Chain(name: "Ethereum", id: "eip155:1"), Chain(name: "Polygon", id: "eip155:137")]
+ let client = ClientDelegate.shared.client
+ var onSessionSettled: ((Session)->())?
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ navigationItem.title = "Available Chains"
+ selectChainView.tableView.dataSource = self
+ selectChainView.connectButton.addTarget(self, action: #selector(connect), for: .touchUpInside)
+ ClientDelegate.shared.onSessionSettled = { [unowned self] session in
+ onSessionSettled?(session)
+ }
+ }
+
+ override func loadView() {
+ view = selectChainView
+
+
+ }
+
+ @objc
+ private func connect() {
+ print("[PROPOSER] Connecting to a pairing...")
+ let permissions = Session.Permissions(
+ blockchains: ["eip155:1", "eip155:137"],
+ methods: ["eth_sendTransaction", "personal_sign", "eth_signTypedData"],
+ notifications: []
+ )
+ do {
+ if let uri = try client.connect(sessionPermissions: permissions) {
+ showConnectScreen(uriString: uri)
+ }
+ } catch {
+ print("[PROPOSER] Pairing connect error: \(error)")
+ }
+ }
+
+ private func showConnectScreen(uriString: String) {
+ DispatchQueue.main.async { [unowned self] in
+ let vc = UINavigationController(rootViewController: ConnectViewController(uri: uriString))
+ present(vc, animated: true, completion: nil)
+ }
+ }
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ chains.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: "chain_cell", for: indexPath)
+ let chain = chains[indexPath.row]
+ cell.textLabel?.text = chain.name
+ cell.imageView?.image = UIImage(named: chain.id)
+ cell.selectionStyle = .none
+ return cell
+ }
+}
diff --git a/Example/DappTests/DappTests.swift b/Example/DappTests/DappTests.swift
new file mode 100644
index 000000000..2792b20c0
--- /dev/null
+++ b/Example/DappTests/DappTests.swift
@@ -0,0 +1,35 @@
+//
+// DappTests.swift
+// DappTests
+//
+// Created by Admin on 27/01/2022.
+//
+
+import XCTest
+
+class DappTests: XCTestCase {
+
+ override func setUpWithError() throws {
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDownWithError() throws {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ }
+
+ func testExample() throws {
+ // This is an example of a functional test case.
+ // Use XCTAssert and related functions to verify your tests produce the correct results.
+ // Any test you write for XCTest can be annotated as throws and async.
+ // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
+ // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
+ }
+
+ func testPerformanceExample() throws {
+ // This is an example of a performance test case.
+ measure {
+ // Put the code you want to measure the time of here.
+ }
+ }
+
+}
diff --git a/Example/ExampleApp.xcodeproj/project.pbxproj b/Example/ExampleApp.xcodeproj/project.pbxproj
index dc0b3c745..5bd25f858 100644
--- a/Example/ExampleApp.xcodeproj/project.pbxproj
+++ b/Example/ExampleApp.xcodeproj/project.pbxproj
@@ -7,8 +7,6 @@
objects = {
/* Begin PBXBuildFile section */
- 7603D74D2703429A00DD27A2 /* ProposerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7603D74C2703429A00DD27A2 /* ProposerView.swift */; };
- 761C649A26FB7ABB004239D1 /* ProposerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761C649926FB7ABB004239D1 /* ProposerViewController.swift */; };
761C649C26FB7B7F004239D1 /* ResponderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761C649B26FB7B7F004239D1 /* ResponderViewController.swift */; };
761C649E26FB7FD7004239D1 /* SessionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761C649D26FB7FD7004239D1 /* SessionViewController.swift */; };
761C64A326FB83CE004239D1 /* SessionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761C64A226FB83CE004239D1 /* SessionView.swift */; };
@@ -24,32 +22,63 @@
76744CF926FE4D7400B77ED9 /* ActiveSessionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76744CF826FE4D7400B77ED9 /* ActiveSessionCell.swift */; };
84494388278D9C1B00CC26BB /* UIAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84494387278D9C1B00CC26BB /* UIAlertController.swift */; };
844943A1278EC49700CC26BB /* Web3 in Frameworks */ = {isa = PBXBuildFile; productRef = 844943A0278EC49700CC26BB /* Web3 */; };
- 845B30EF27859686002E4094 /* ExampleAppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845B30EE27859686002E4094 /* ExampleAppTests.swift */; };
8460DCFC274F98A10081F94C /* RequestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8460DCFB274F98A10081F94C /* RequestViewController.swift */; };
8460DD002750D6F50081F94C /* SessionDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8460DCFF2750D6F50081F94C /* SessionDetailsViewController.swift */; };
8460DD022750D7020081F94C /* SessionDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8460DD012750D7020081F94C /* SessionDetailsView.swift */; };
+ 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 */; };
+ 84CE6430279820F600142511 /* AccountsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761C649926FB7ABB004239D1 /* AccountsViewController.swift */; };
+ 84CE6431279820F600142511 /* AccountsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7603D74C2703429A00DD27A2 /* AccountsView.swift */; };
+ 84CE64392798228D00142511 /* Web3 in Frameworks */ = {isa = PBXBuildFile; productRef = 84CE64382798228D00142511 /* Web3 */; };
+ 84CE643B2798229100142511 /* WalletConnect in Frameworks */ = {isa = PBXBuildFile; productRef = 84CE643A2798229100142511 /* WalletConnect */; };
+ 84CE643D2798322600142511 /* ConnectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CE643C2798322600142511 /* ConnectViewController.swift */; };
+ 84CE6444279AB5AD00142511 /* SelectChainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CE6443279AB5AD00142511 /* SelectChainViewController.swift */; };
+ 84CE6446279ABBF300142511 /* ClientDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CE6445279ABBF300142511 /* ClientDelegate.swift */; };
+ 84CE6448279AE68600142511 /* AccountRequestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CE6447279AE68600142511 /* AccountRequestViewController.swift */; };
+ 84CE644B279EA1FA00142511 /* AccountRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CE644A279EA1FA00142511 /* AccountRequestView.swift */; };
+ 84CE644E279ED2FF00142511 /* SelectChainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CE644D279ED2FF00142511 /* SelectChainView.swift */; };
+ 84CE6452279ED42B00142511 /* ConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CE6451279ED42B00142511 /* ConnectView.swift */; };
+ 84CE645527A29D4D00142511 /* ResponseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CE645427A29D4C00142511 /* ResponseViewController.swift */; };
+ 84CE646127A2C85B00142511 /* DappTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CE646027A2C85B00142511 /* DappTests.swift */; };
+ 84CE647027A2CD6B00142511 /* WalletTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CE646F27A2CD6B00142511 /* WalletTests.swift */; };
84F568C2279582D200D0A289 /* Signer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F568C1279582D200D0A289 /* Signer.swift */; };
84F568C42795832A00D0A289 /* EthereumTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F568C32795832A00D0A289 /* EthereumTransaction.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
- 845B30F027859686002E4094 /* PBXContainerItemProxy */ = {
+ 84CE646227A2C85B00142511 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 764E1D3426F8D3FC00A1FB15 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 764E1D3B26F8D3FC00A1FB15;
- remoteInfo = ExampleApp;
+ remoteInfo = Wallet;
+ };
+ 84CE646727A2C86100142511 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 764E1D3426F8D3FC00A1FB15 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 84CE641B27981DED00142511;
+ remoteInfo = DApp;
+ };
+ 84CE647127A2CD6B00142511 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 764E1D3426F8D3FC00A1FB15 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 764E1D3B26F8D3FC00A1FB15;
+ remoteInfo = Wallet;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
- 7603D74C2703429A00DD27A2 /* ProposerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProposerView.swift; sourceTree = ""; };
- 761C649926FB7ABB004239D1 /* ProposerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProposerViewController.swift; sourceTree = ""; };
+ 7603D74C2703429A00DD27A2 /* AccountsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsView.swift; sourceTree = ""; };
+ 761C649926FB7ABB004239D1 /* AccountsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsViewController.swift; sourceTree = ""; };
761C649B26FB7B7F004239D1 /* ResponderViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResponderViewController.swift; sourceTree = ""; wrapsLines = 0; };
761C649D26FB7FD7004239D1 /* SessionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionViewController.swift; sourceTree = ""; };
761C64A226FB83CE004239D1 /* SessionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionView.swift; sourceTree = ""; };
761C64A526FCB0AA004239D1 /* SessionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionInfo.swift; sourceTree = ""; };
- 764E1D3C26F8D3FC00A1FB15 /* ExampleApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExampleApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 764E1D3C26F8D3FC00A1FB15 /* WalletConnect Wallet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "WalletConnect Wallet.app"; sourceTree = BUILT_PRODUCTS_DIR; };
764E1D3F26F8D3FC00A1FB15 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
764E1D4126F8D3FC00A1FB15 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
764E1D4826F8D3FE00A1FB15 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
@@ -63,11 +92,28 @@
76744CF626FE4D5400B77ED9 /* ActiveSessionItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveSessionItem.swift; sourceTree = ""; };
76744CF826FE4D7400B77ED9 /* ActiveSessionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveSessionCell.swift; sourceTree = ""; };
84494387278D9C1B00CC26BB /* UIAlertController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIAlertController.swift; sourceTree = ""; };
- 845B30EC27859686002E4094 /* ExampleAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
- 845B30EE27859686002E4094 /* ExampleAppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleAppTests.swift; sourceTree = ""; };
8460DCFB274F98A10081F94C /* RequestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestViewController.swift; sourceTree = ""; };
8460DCFF2750D6F50081F94C /* SessionDetailsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionDetailsViewController.swift; sourceTree = ""; };
8460DD012750D7020081F94C /* SessionDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionDetailsView.swift; sourceTree = ""; };
+ 84CE641C27981DED00142511 /* DApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 84CE641E27981DED00142511 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ 84CE642027981DED00142511 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
+ 84CE642727981DF000142511 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 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 = ""; };
+ 84CE643C2798322600142511 /* ConnectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectViewController.swift; sourceTree = ""; };
+ 84CE6443279AB5AD00142511 /* SelectChainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectChainViewController.swift; sourceTree = ""; };
+ 84CE6445279ABBF300142511 /* ClientDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClientDelegate.swift; sourceTree = ""; };
+ 84CE6447279AE68600142511 /* AccountRequestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountRequestViewController.swift; sourceTree = ""; };
+ 84CE644A279EA1FA00142511 /* AccountRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountRequestView.swift; sourceTree = ""; };
+ 84CE644D279ED2FF00142511 /* SelectChainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectChainView.swift; sourceTree = ""; };
+ 84CE6451279ED42B00142511 /* ConnectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectView.swift; sourceTree = ""; };
+ 84CE6453279FFE1100142511 /* Wallet.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Wallet.entitlements; sourceTree = ""; };
+ 84CE645427A29D4C00142511 /* ResponseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseViewController.swift; sourceTree = ""; };
+ 84CE645E27A2C85B00142511 /* DappTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DappTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 84CE646027A2C85B00142511 /* DappTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DappTests.swift; sourceTree = ""; };
+ 84CE646D27A2CD6B00142511 /* WalletTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WalletTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 84CE646F27A2CD6B00142511 /* WalletTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletTests.swift; 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 = ""; };
/* End PBXFileReference section */
@@ -82,7 +128,23 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 845B30E927859686002E4094 /* Frameworks */ = {
+ 84CE641927981DED00142511 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 84CE643B2798229100142511 /* WalletConnect in Frameworks */,
+ 84CE64392798228D00142511 /* Web3 in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 84CE645B27A2C85B00142511 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 84CE646A27A2CD6B00142511 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -100,8 +162,6 @@
84F568C1279582D200D0A289 /* Signer.swift */,
84494387278D9C1B00CC26BB /* UIAlertController.swift */,
76744CF426FDFB6B00B77ED9 /* ResponderView.swift */,
- 76744CF826FE4D7400B77ED9 /* ActiveSessionCell.swift */,
- 76744CF626FE4D5400B77ED9 /* ActiveSessionItem.swift */,
764E1D5926F8DF1B00A1FB15 /* ScannerViewController.swift */,
761C64A426FCB08B004239D1 /* SessionProposal */,
8460DCFD274F98A90081F94C /* Request */,
@@ -109,15 +169,6 @@
path = Responder;
sourceTree = "";
};
- 761C64A126FB838D004239D1 /* Proposer */ = {
- isa = PBXGroup;
- children = (
- 761C649926FB7ABB004239D1 /* ProposerViewController.swift */,
- 7603D74C2703429A00DD27A2 /* ProposerView.swift */,
- );
- path = Proposer;
- sourceTree = "";
- };
761C64A426FCB08B004239D1 /* SessionProposal */ = {
isa = PBXGroup;
children = (
@@ -131,8 +182,11 @@
764E1D3326F8D3FC00A1FB15 = {
isa = PBXGroup;
children = (
+ 84CE6453279FFE1100142511 /* Wallet.entitlements */,
764E1D3E26F8D3FC00A1FB15 /* ExampleApp */,
- 845B30ED27859686002E4094 /* ExampleAppTests */,
+ 84CE641D27981DED00142511 /* DApp */,
+ 84CE645F27A2C85B00142511 /* DappTests */,
+ 84CE646E27A2CD6B00142511 /* WalletTests */,
764E1D3D26F8D3FC00A1FB15 /* Products */,
764E1D5326F8DAC800A1FB15 /* Frameworks */,
764E1D5626F8DB6000A1FB15 /* WalletConnectSwiftV2 */,
@@ -142,8 +196,10 @@
764E1D3D26F8D3FC00A1FB15 /* Products */ = {
isa = PBXGroup;
children = (
- 764E1D3C26F8D3FC00A1FB15 /* ExampleApp.app */,
- 845B30EC27859686002E4094 /* ExampleAppTests.xctest */,
+ 764E1D3C26F8D3FC00A1FB15 /* WalletConnect Wallet.app */,
+ 84CE641C27981DED00142511 /* DApp.app */,
+ 84CE645E27A2C85B00142511 /* DappTests.xctest */,
+ 84CE646D27A2CD6B00142511 /* WalletTests.xctest */,
);
name = Products;
sourceTree = "";
@@ -153,9 +209,10 @@
children = (
764E1D3F26F8D3FC00A1FB15 /* AppDelegate.swift */,
764E1D4126F8D3FC00A1FB15 /* SceneDelegate.swift */,
+ 76744CF826FE4D7400B77ED9 /* ActiveSessionCell.swift */,
+ 76744CF626FE4D5400B77ED9 /* ActiveSessionItem.swift */,
8460DCFE2750D6DF0081F94C /* SessionDetails */,
761C64A026FB8387004239D1 /* Responder */,
- 761C64A126FB838D004239D1 /* Proposer */,
764E1D4826F8D3FE00A1FB15 /* Assets.xcassets */,
764E1D4A26F8D3FE00A1FB15 /* LaunchScreen.storyboard */,
764E1D4D26F8D3FE00A1FB15 /* Info.plist */,
@@ -172,14 +229,6 @@
name = Frameworks;
sourceTree = "";
};
- 845B30ED27859686002E4094 /* ExampleAppTests */ = {
- isa = PBXGroup;
- children = (
- 845B30EE27859686002E4094 /* ExampleAppTests.swift */,
- );
- path = ExampleAppTests;
- sourceTree = "";
- };
8460DCFD274F98A90081F94C /* Request */ = {
isa = PBXGroup;
children = (
@@ -197,12 +246,82 @@
path = SessionDetails;
sourceTree = "";
};
+ 84CE641D27981DED00142511 /* DApp */ = {
+ isa = PBXGroup;
+ children = (
+ 84CE641E27981DED00142511 /* AppDelegate.swift */,
+ 84CE642027981DED00142511 /* SceneDelegate.swift */,
+ 84CE645427A29D4C00142511 /* ResponseViewController.swift */,
+ 84CE6449279EA1E600142511 /* AccountRequest */,
+ 84CE6445279ABBF300142511 /* ClientDelegate.swift */,
+ 84CE644C279ED2EC00142511 /* SelectChain */,
+ 84CE6450279ED41D00142511 /* Connect */,
+ 84CE644F279ED3FB00142511 /* Accounts */,
+ 84CE642727981DF000142511 /* Assets.xcassets */,
+ 84CE642927981DF000142511 /* LaunchScreen.storyboard */,
+ 84CE642C27981DF000142511 /* Info.plist */,
+ );
+ path = DApp;
+ sourceTree = "";
+ };
+ 84CE6449279EA1E600142511 /* AccountRequest */ = {
+ isa = PBXGroup;
+ children = (
+ 84CE6447279AE68600142511 /* AccountRequestViewController.swift */,
+ 84CE644A279EA1FA00142511 /* AccountRequestView.swift */,
+ );
+ path = AccountRequest;
+ sourceTree = "";
+ };
+ 84CE644C279ED2EC00142511 /* SelectChain */ = {
+ isa = PBXGroup;
+ children = (
+ 84CE6443279AB5AD00142511 /* SelectChainViewController.swift */,
+ 84CE644D279ED2FF00142511 /* SelectChainView.swift */,
+ );
+ path = SelectChain;
+ sourceTree = "";
+ };
+ 84CE644F279ED3FB00142511 /* Accounts */ = {
+ isa = PBXGroup;
+ children = (
+ 761C649926FB7ABB004239D1 /* AccountsViewController.swift */,
+ 7603D74C2703429A00DD27A2 /* AccountsView.swift */,
+ );
+ path = " Accounts";
+ sourceTree = "";
+ };
+ 84CE6450279ED41D00142511 /* Connect */ = {
+ isa = PBXGroup;
+ children = (
+ 84CE643C2798322600142511 /* ConnectViewController.swift */,
+ 84CE6451279ED42B00142511 /* ConnectView.swift */,
+ );
+ path = Connect;
+ sourceTree = "";
+ };
+ 84CE645F27A2C85B00142511 /* DappTests */ = {
+ isa = PBXGroup;
+ children = (
+ 84CE646027A2C85B00142511 /* DappTests.swift */,
+ );
+ path = DappTests;
+ sourceTree = "";
+ };
+ 84CE646E27A2CD6B00142511 /* WalletTests */ = {
+ isa = PBXGroup;
+ children = (
+ 84CE646F27A2CD6B00142511 /* WalletTests.swift */,
+ );
+ path = WalletTests;
+ sourceTree = "";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
- 764E1D3B26F8D3FC00A1FB15 /* ExampleApp */ = {
+ 764E1D3B26F8D3FC00A1FB15 /* Wallet */ = {
isa = PBXNativeTarget;
- buildConfigurationList = 764E1D5026F8D3FE00A1FB15 /* Build configuration list for PBXNativeTarget "ExampleApp" */;
+ buildConfigurationList = 764E1D5026F8D3FE00A1FB15 /* Build configuration list for PBXNativeTarget "Wallet" */;
buildPhases = (
764E1D3826F8D3FC00A1FB15 /* Sources */,
764E1D3926F8D3FC00A1FB15 /* Frameworks */,
@@ -212,31 +331,71 @@
);
dependencies = (
);
- name = ExampleApp;
+ name = Wallet;
packageProductDependencies = (
764E1D5726F8DBAB00A1FB15 /* WalletConnect */,
844943A0278EC49700CC26BB /* Web3 */,
);
productName = ExampleApp;
- productReference = 764E1D3C26F8D3FC00A1FB15 /* ExampleApp.app */;
+ productReference = 764E1D3C26F8D3FC00A1FB15 /* WalletConnect Wallet.app */;
productType = "com.apple.product-type.application";
};
- 845B30EB27859686002E4094 /* ExampleAppTests */ = {
+ 84CE641B27981DED00142511 /* DApp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 84CE642F27981DF000142511 /* Build configuration list for PBXNativeTarget "DApp" */;
+ buildPhases = (
+ 84CE641827981DED00142511 /* Sources */,
+ 84CE641927981DED00142511 /* Frameworks */,
+ 84CE641A27981DED00142511 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = DApp;
+ packageProductDependencies = (
+ 84CE64382798228D00142511 /* Web3 */,
+ 84CE643A2798229100142511 /* WalletConnect */,
+ );
+ productName = DApp;
+ productReference = 84CE641C27981DED00142511 /* DApp.app */;
+ productType = "com.apple.product-type.application";
+ };
+ 84CE645D27A2C85B00142511 /* DappTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 84CE646427A2C85B00142511 /* Build configuration list for PBXNativeTarget "DappTests" */;
+ buildPhases = (
+ 84CE645A27A2C85B00142511 /* Sources */,
+ 84CE645B27A2C85B00142511 /* Frameworks */,
+ 84CE645C27A2C85B00142511 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 84CE646327A2C85B00142511 /* PBXTargetDependency */,
+ 84CE646827A2C86100142511 /* PBXTargetDependency */,
+ );
+ name = DappTests;
+ productName = DappTests;
+ productReference = 84CE645E27A2C85B00142511 /* DappTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ 84CE646C27A2CD6B00142511 /* WalletTests */ = {
isa = PBXNativeTarget;
- buildConfigurationList = 845B30F227859686002E4094 /* Build configuration list for PBXNativeTarget "ExampleAppTests" */;
+ buildConfigurationList = 84CE647327A2CD6C00142511 /* Build configuration list for PBXNativeTarget "WalletTests" */;
buildPhases = (
- 845B30E827859686002E4094 /* Sources */,
- 845B30E927859686002E4094 /* Frameworks */,
- 845B30EA27859686002E4094 /* Resources */,
+ 84CE646927A2CD6B00142511 /* Sources */,
+ 84CE646A27A2CD6B00142511 /* Frameworks */,
+ 84CE646B27A2CD6B00142511 /* Resources */,
);
buildRules = (
);
dependencies = (
- 845B30F127859686002E4094 /* PBXTargetDependency */,
+ 84CE647227A2CD6B00142511 /* PBXTargetDependency */,
);
- name = ExampleAppTests;
- productName = ExampleAppTests;
- productReference = 845B30EC27859686002E4094 /* ExampleAppTests.xctest */;
+ name = WalletTests;
+ productName = WalletTests;
+ productReference = 84CE646D27A2CD6B00142511 /* WalletTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
@@ -251,7 +410,14 @@
764E1D3B26F8D3FC00A1FB15 = {
CreatedOnToolsVersion = 12.5.1;
};
- 845B30EB27859686002E4094 = {
+ 84CE641B27981DED00142511 = {
+ CreatedOnToolsVersion = 13.2;
+ };
+ 84CE645D27A2C85B00142511 = {
+ CreatedOnToolsVersion = 13.2;
+ TestTargetID = 84CE641B27981DED00142511;
+ };
+ 84CE646C27A2CD6B00142511 = {
CreatedOnToolsVersion = 13.2;
TestTargetID = 764E1D3B26F8D3FC00A1FB15;
};
@@ -273,8 +439,10 @@
projectDirPath = "";
projectRoot = "";
targets = (
- 764E1D3B26F8D3FC00A1FB15 /* ExampleApp */,
- 845B30EB27859686002E4094 /* ExampleAppTests */,
+ 764E1D3B26F8D3FC00A1FB15 /* Wallet */,
+ 84CE641B27981DED00142511 /* DApp */,
+ 84CE645D27A2C85B00142511 /* DappTests */,
+ 84CE646C27A2CD6B00142511 /* WalletTests */,
);
};
/* End PBXProject section */
@@ -289,7 +457,23 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
- 845B30EA27859686002E4094 /* Resources */ = {
+ 84CE641A27981DED00142511 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 84CE642B27981DF000142511 /* LaunchScreen.storyboard in Resources */,
+ 84CE642827981DF000142511 /* Assets.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 84CE645C27A2C85B00142511 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 84CE646B27A2CD6B00142511 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -306,7 +490,6 @@
761C64A326FB83CE004239D1 /* SessionView.swift in Sources */,
8460DCFC274F98A10081F94C /* RequestViewController.swift in Sources */,
76744CF526FDFB6B00B77ED9 /* ResponderView.swift in Sources */,
- 761C649A26FB7ABB004239D1 /* ProposerViewController.swift in Sources */,
8460DD002750D6F50081F94C /* SessionDetailsViewController.swift in Sources */,
76744CF926FE4D7400B77ED9 /* ActiveSessionCell.swift in Sources */,
764E1D4026F8D3FC00A1FB15 /* AppDelegate.swift in Sources */,
@@ -317,28 +500,64 @@
764E1D4226F8D3FC00A1FB15 /* SceneDelegate.swift in Sources */,
84F568C2279582D200D0A289 /* Signer.swift in Sources */,
8460DD022750D7020081F94C /* SessionDetailsView.swift in Sources */,
- 7603D74D2703429A00DD27A2 /* ProposerView.swift in Sources */,
764E1D5A26F8DF1B00A1FB15 /* ScannerViewController.swift in Sources */,
84494388278D9C1B00CC26BB /* UIAlertController.swift in Sources */,
84F568C42795832A00D0A289 /* EthereumTransaction.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
- 845B30E827859686002E4094 /* Sources */ = {
+ 84CE641827981DED00142511 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 84CE6430279820F600142511 /* AccountsViewController.swift in Sources */,
+ 84CE645527A29D4D00142511 /* ResponseViewController.swift in Sources */,
+ 84CE6446279ABBF300142511 /* ClientDelegate.swift in Sources */,
+ 84CE641F27981DED00142511 /* AppDelegate.swift in Sources */,
+ 84CE6452279ED42B00142511 /* ConnectView.swift in Sources */,
+ 84CE6448279AE68600142511 /* AccountRequestViewController.swift in Sources */,
+ 84CE642127981DED00142511 /* SceneDelegate.swift in Sources */,
+ 84CE644E279ED2FF00142511 /* SelectChainView.swift in Sources */,
+ 84CE644B279EA1FA00142511 /* AccountRequestView.swift in Sources */,
+ 84CE6431279820F600142511 /* AccountsView.swift in Sources */,
+ 84CE643D2798322600142511 /* ConnectViewController.swift in Sources */,
+ 84CE6444279AB5AD00142511 /* SelectChainViewController.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 84CE645A27A2C85B00142511 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 845B30EF27859686002E4094 /* ExampleAppTests.swift in Sources */,
+ 84CE646127A2C85B00142511 /* DappTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 84CE646927A2CD6B00142511 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 84CE647027A2CD6B00142511 /* WalletTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
- 845B30F127859686002E4094 /* PBXTargetDependency */ = {
+ 84CE646327A2C85B00142511 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 764E1D3B26F8D3FC00A1FB15 /* Wallet */;
+ targetProxy = 84CE646227A2C85B00142511 /* PBXContainerItemProxy */;
+ };
+ 84CE646827A2C86100142511 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 84CE641B27981DED00142511 /* DApp */;
+ targetProxy = 84CE646727A2C86100142511 /* PBXContainerItemProxy */;
+ };
+ 84CE647227A2CD6B00142511 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
- target = 764E1D3B26F8D3FC00A1FB15 /* ExampleApp */;
- targetProxy = 845B30F027859686002E4094 /* PBXContainerItemProxy */;
+ target = 764E1D3B26F8D3FC00A1FB15 /* Wallet */;
+ targetProxy = 84CE647127A2CD6B00142511 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
@@ -351,6 +570,14 @@
name = LaunchScreen.storyboard;
sourceTree = "";
};
+ 84CE642927981DF000142511 /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 84CE642A27981DF000142511 /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
@@ -475,9 +702,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = Wallet.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 7;
+ CURRENT_PROJECT_VERSION = 9;
DEVELOPMENT_TEAM = W5R8AG9K22;
INFOPLIST_FILE = ExampleApp/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
@@ -487,7 +715,7 @@
);
MARKETING_VERSION = 0.0.1;
PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.example;
- PRODUCT_NAME = "$(TARGET_NAME)";
+ PRODUCT_NAME = "WalletConnect Wallet";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -499,9 +727,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = Wallet.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 7;
+ CURRENT_PROJECT_VERSION = 9;
DEVELOPMENT_TEAM = W5R8AG9K22;
INFOPLIST_FILE = ExampleApp/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
@@ -511,14 +740,78 @@
);
MARKETING_VERSION = 0.0.1;
PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.example;
- PRODUCT_NAME = "$(TARGET_NAME)";
+ PRODUCT_NAME = "WalletConnect Wallet";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
- 845B30F327859686002E4094 /* Debug */ = {
+ 84CE642D27981DF000142511 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 2;
+ DEVELOPMENT_TEAM = W5R8AG9K22;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = DApp/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = dApp;
+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
+ INFOPLIST_KEY_UIRequiredDeviceCapabilities = armv7;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = UIInterfaceOrientationPortrait;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 0.0.1;
+ PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.dapp;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 84CE642E27981DF000142511 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 2;
+ DEVELOPMENT_TEAM = W5R8AG9K22;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = DApp/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = dApp;
+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
+ INFOPLIST_KEY_UIRequiredDeviceCapabilities = armv7;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = UIInterfaceOrientationPortrait;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 0.0.1;
+ PRODUCT_BUNDLE_IDENTIFIER = com.walletconnect.dapp;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+ 84CE646527A2C85B00142511 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
@@ -529,16 +822,16 @@
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = walletconnect.ExampleAppTests;
+ PRODUCT_BUNDLE_IDENTIFIER = walletconnect.DappTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ExampleApp.app/ExampleApp";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DApp.app/DApp";
};
name = Debug;
};
- 845B30F427859686002E4094 /* Release */ = {
+ 84CE646627A2C85B00142511 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
@@ -549,12 +842,52 @@
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = walletconnect.ExampleAppTests;
+ PRODUCT_BUNDLE_IDENTIFIER = walletconnect.DappTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
- TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ExampleApp.app/ExampleApp";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DApp.app/DApp";
+ };
+ name = Release;
+ };
+ 84CE647427A2CD6C00142511 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = W5R8AG9K22;
+ GENERATE_INFOPLIST_FILE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = walletconnect.WalletTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WalletConnect Wallet.app/WalletConnect Wallet";
+ };
+ name = Debug;
+ };
+ 84CE647527A2CD6C00142511 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_TEAM = W5R8AG9K22;
+ GENERATE_INFOPLIST_FILE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = walletconnect.WalletTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = NO;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WalletConnect Wallet.app/WalletConnect Wallet";
};
name = Release;
};
@@ -570,7 +903,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 764E1D5026F8D3FE00A1FB15 /* Build configuration list for PBXNativeTarget "ExampleApp" */ = {
+ 764E1D5026F8D3FE00A1FB15 /* Build configuration list for PBXNativeTarget "Wallet" */ = {
isa = XCConfigurationList;
buildConfigurations = (
764E1D5126F8D3FE00A1FB15 /* Debug */,
@@ -579,11 +912,29 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 845B30F227859686002E4094 /* Build configuration list for PBXNativeTarget "ExampleAppTests" */ = {
+ 84CE642F27981DF000142511 /* Build configuration list for PBXNativeTarget "DApp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 84CE642D27981DF000142511 /* Debug */,
+ 84CE642E27981DF000142511 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 84CE646427A2C85B00142511 /* Build configuration list for PBXNativeTarget "DappTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 845B30F327859686002E4094 /* Debug */,
- 845B30F427859686002E4094 /* Release */,
+ 84CE646527A2C85B00142511 /* Debug */,
+ 84CE646627A2C85B00142511 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 84CE647327A2CD6C00142511 /* Build configuration list for PBXNativeTarget "WalletTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 84CE647427A2CD6C00142511 /* Debug */,
+ 84CE647527A2CD6C00142511 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
@@ -611,6 +962,15 @@
package = 8449439F278EC49700CC26BB /* XCRemoteSwiftPackageReference "Web3" */;
productName = Web3;
};
+ 84CE64382798228D00142511 /* Web3 */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 8449439F278EC49700CC26BB /* XCRemoteSwiftPackageReference "Web3" */;
+ productName = Web3;
+ };
+ 84CE643A2798229100142511 /* WalletConnect */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = WalletConnect;
+ };
/* End XCSwiftPackageProductDependency section */
};
rootObject = 764E1D3426F8D3FC00A1FB15 /* Project object */;
diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/ExampleApp.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/DApp.xcscheme
similarity index 81%
rename from Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/ExampleApp.xcscheme
rename to Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/DApp.xcscheme
index dce1bdf8a..bb02c9037 100644
--- a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/ExampleApp.xcscheme
+++ b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/DApp.xcscheme
@@ -14,9 +14,9 @@
buildForAnalyzing = "YES">
@@ -32,9 +32,9 @@
skipped = "NO">
@@ -54,9 +54,9 @@
runnableDebuggingMode = "0">
@@ -71,9 +71,9 @@
runnableDebuggingMode = "0">
diff --git a/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/Wallet.xcscheme b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/Wallet.xcscheme
new file mode 100644
index 000000000..5c9f393ee
--- /dev/null
+++ b/Example/ExampleApp.xcodeproj/xcshareddata/xcschemes/Wallet.xcscheme
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example/ExampleApp/Responder/ActiveSessionCell.swift b/Example/ExampleApp/ActiveSessionCell.swift
similarity index 100%
rename from Example/ExampleApp/Responder/ActiveSessionCell.swift
rename to Example/ExampleApp/ActiveSessionCell.swift
diff --git a/Example/ExampleApp/Responder/ActiveSessionItem.swift b/Example/ExampleApp/ActiveSessionItem.swift
similarity index 100%
rename from Example/ExampleApp/Responder/ActiveSessionItem.swift
rename to Example/ExampleApp/ActiveSessionItem.swift
diff --git a/Example/ExampleApp/AppDelegate.swift b/Example/ExampleApp/AppDelegate.swift
index 8476d254c..a02457777 100644
--- a/Example/ExampleApp/AppDelegate.swift
+++ b/Example/ExampleApp/AppDelegate.swift
@@ -15,4 +15,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
}
+
+
+
}
diff --git a/Example/ExampleApp/Info.plist b/Example/ExampleApp/Info.plist
index 1fa4cd501..fd00d23da 100644
--- a/Example/ExampleApp/Info.plist
+++ b/Example/ExampleApp/Info.plist
@@ -5,7 +5,7 @@
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleDisplayName
- Demo App
+ WalletConnect Wallet
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
@@ -18,6 +18,19 @@
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
$(MARKETING_VERSION)
+ CFBundleURLTypes
+
+
+ CFBundleTypeRole
+ Editor
+ CFBundleURLName
+ com.walletconnect.example
+ CFBundleURLSchemes
+
+ walletconnectwallet
+
+
+
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
ITSAppUsesNonExemptEncryption
diff --git a/Example/ExampleApp/Proposer/ProposerViewController.swift b/Example/ExampleApp/Proposer/ProposerViewController.swift
deleted file mode 100644
index 511c1447e..000000000
--- a/Example/ExampleApp/Proposer/ProposerViewController.swift
+++ /dev/null
@@ -1,182 +0,0 @@
-import UIKit
-import WalletConnect
-
-final class ProposerViewController: UIViewController {
-
- let client: WalletConnectClient = {
- let metadata = AppMetadata(
- name: "Example Proposer",
- description: "a description",
- url: "wallet.connect",
- icons: ["https://gblobscdn.gitbook.com/spaces%2F-LJJeCjcLrr53DcT1Ml7%2Favatar.png?alt=media"])
- return WalletConnectClient(
- metadata: metadata,
- projectId: "52af113ee0c1e1a20f4995730196c13e",
- isController: false,
- relayHost: "relay.dev.walletconnect.com",
- clientName: "proposer"
- )
- }()
-
- var activeItems: [ActiveSessionItem] = []
- private var currentURI: String?
-
- private let proposerView: ProposerView = {
- ProposerView()
- }()
-
- override func loadView() {
- view = proposerView
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
- navigationItem.title = "Dapp"
-
- navigationItem.rightBarButtonItem = UIBarButtonItem(
- title: "Connect",
- style: .plain,
- target: self,
- action: #selector(connect)
- )
-
- proposerView.copyButton.addTarget(self, action: #selector(copyURI), for: .touchUpInside)
- proposerView.copyButton.isHidden = true
-
- proposerView.tableView.dataSource = self
- proposerView.tableView.delegate = self
-
- client.delegate = self
- client.logger.setLogging(level: .debug)
- }
-
- @objc func copyURI() {
- UIPasteboard.general.string = currentURI
- }
-
- @objc
- private func connect() {
- print("[PROPOSER] Connecting to a pairing...")
- let permissions = Session.Permissions(
- blockchains: ["a chain"],
- methods: ["a method"],
- notifications: []
- )
- do {
- if let uri = try client.connect(sessionPermissions: permissions) {
- showQRCode(uriString: uri)
- }
- } catch {
- print("[PROPOSER] Pairing connect error: \(error)")
- }
- }
-
- private func showQRCode(uriString: String) {
- currentURI = uriString
- DispatchQueue.global().async { [weak self] in
- if let qrImage = self?.generateQRCode(from: uriString) {
- DispatchQueue.main.async {
- self?.proposerView.qrCodeView.image = qrImage
- self?.proposerView.copyButton.isHidden = false
- }
- }
- }
- }
-
- private func generateQRCode(from string: String) -> UIImage? {
- let data = string.data(using: .ascii)
- if let filter = CIFilter(name: "CIQRCodeGenerator") {
- filter.setValue(data, forKey: "inputMessage")
- if let output = filter.outputImage {
- return UIImage(ciImage: output)
- }
- }
- return nil
- }
-}
-
-extension ProposerViewController: UITableViewDataSource, UITableViewDelegate {
-
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- activeItems.count
- }
-
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let cell = tableView.dequeueReusableCell(withIdentifier: "sessionCell", for: indexPath) as! ActiveSessionCell
- cell.item = activeItems[indexPath.row]
- return cell
- }
-
- func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
- if editingStyle == .delete {
- activeItems.remove(at: indexPath.row)
- tableView.deleteRows(at: [indexPath], with: .automatic)
- }
- }
-
- func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? {
- "Disconnect"
- }
-
- func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- print("did select row \(indexPath)")
- }
-}
-
-extension ProposerViewController: WalletConnectClientDelegate {
-
- func didReceive(sessionProposal: Session.Proposal) {
- print("[PROPOSER] WC: Did receive session proposal")
- }
-
- func didReceive(sessionRequest: Request) {
- print("[PROPOSER] WC: Did receive session request")
- }
-
- func didReceive(notification: Session.Notification, sessionTopic: String) {
-
- }
-
- func didUpgrade(sessionTopic: String, permissions: Session.Permissions) {
-
- }
-
- func didUpdate(sessionTopic: String, accounts: Set) {
-
- }
-
- func didUpdate(pairingTopic: String, appMetadata: AppMetadata) {
-
- }
-
- func didDelete(sessionTopic: String, reason: Reason) {
-
- }
-
- func didSettle(session: Session) {
- print("[PROPOSER] WC: Did settle session")
- }
-
- func didSettle(pairing: Pairing) {
- print("[PROPOSER] WC: Did settle pairing")
- let settledPairings = client.getSettledPairings()
- let activePairings = settledPairings.map { pairing -> ActiveSessionItem in
- let app = pairing.peer
- return ActiveSessionItem(
- dappName: app?.name ?? "",
- dappURL: app?.url ?? "",
- iconURL: app?.icons?.first ?? "",
- topic: pairing.topic)
- }
- DispatchQueue.main.async {
- self.activeItems = activePairings
- self.proposerView.tableView.reloadData()
- self.proposerView.qrCodeView.image = nil
- self.proposerView.copyButton.isHidden = true
- }
- }
-
- func didReject(pendingSessionTopic: String, reason: Reason) {
- print("[PROPOSER] WC: Did reject session")
- }
-}
diff --git a/Example/ExampleApp/Responder/Request/RequestViewController.swift b/Example/ExampleApp/Responder/Request/RequestViewController.swift
index 0bac90b73..a6e392661 100644
--- a/Example/ExampleApp/Responder/Request/RequestViewController.swift
+++ b/Example/ExampleApp/Responder/Request/RequestViewController.swift
@@ -8,9 +8,8 @@ class RequestViewController: UIViewController {
var onSign: (()->())?
var onReject: (()->())?
let sessionRequest: Request
- private let requestView = {
- RequestView()
- }()
+ private let requestView = RequestView()
+
init(_ sessionRequest: Request) {
self.sessionRequest = sessionRequest
super.init(nibName: nil, bundle: nil)
@@ -59,15 +58,6 @@ class RequestViewController: UIViewController {
}
final class RequestView: UIView {
-
- let iconView: UIImageView = {
- let imageView = UIImageView()
- imageView.contentMode = .scaleAspectFit
- imageView.backgroundColor = .systemFill
- imageView.layer.cornerRadius = 32
- return imageView
- }()
-
let nameLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 17.0, weight: .heavy)
@@ -115,7 +105,6 @@ final class RequestView: UIView {
super.init(frame: frame)
backgroundColor = .systemBackground
- addSubview(iconView)
addSubview(headerStackView)
addSubview(approveButton)
addSubview(rejectButton)
@@ -125,12 +114,8 @@ final class RequestView: UIView {
subviews.forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
NSLayoutConstraint.activate([
- iconView.topAnchor.constraint(equalTo: topAnchor, constant: 64),
- iconView.centerXAnchor.constraint(equalTo: centerXAnchor),
- iconView.widthAnchor.constraint(equalToConstant: 64),
- iconView.heightAnchor.constraint(equalToConstant: 64),
- headerStackView.topAnchor.constraint(equalTo: iconView.bottomAnchor, constant: 32),
+ headerStackView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 32),
headerStackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 32),
headerStackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -32),
@@ -148,17 +133,6 @@ final class RequestView: UIView {
])
}
- func loadImage(at url: String) {
- guard let iconURL = URL(string: url) else { return }
- DispatchQueue.global().async {
- if let imageData = try? Data(contentsOf: iconURL) {
- DispatchQueue.main.async { [weak self] in
- self?.iconView.image = UIImage(data: imageData)
- }
- }
- }
- }
-
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
diff --git a/Example/ExampleApp/Responder/ResponderViewController.swift b/Example/ExampleApp/Responder/ResponderViewController.swift
index c5049becd..c5e662ca6 100644
--- a/Example/ExampleApp/Responder/ResponderViewController.swift
+++ b/Example/ExampleApp/Responder/ResponderViewController.swift
@@ -16,8 +16,7 @@ final class ResponderViewController: UIViewController {
metadata: metadata,
projectId: "52af113ee0c1e1a20f4995730196c13e",
isController: true,
- relayHost: "relay.dev.walletconnect.com", //use with dapp at https://canary.react-app.walletconnect.com/
- clientName: "responder"
+ relayHost: "relay.dev.walletconnect.com"
)
}()
lazy var account = Signer.privateKey.address.hex(eip55: true)
@@ -43,6 +42,7 @@ final class ResponderViewController: UIViewController {
let settledSessions = client.getSettledSessions()
sessionItems = getActiveSessionItem(for: settledSessions)
client.delegate = self
+ client.logger.setLogging(level: .debug)
}
@objc
@@ -119,7 +119,6 @@ extension ResponderViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let item = sessionItems[indexPath.row]
-// let deleteParams = SessionType.DeleteParams(topic: item.topic, reason: SessionType.Reason(code: 0, message: "disconnect"))
client.disconnect(topic: item.topic, reason: Reason(code: 0, message: "disconnect"))
sessionItems.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
@@ -194,10 +193,6 @@ extension ResponderViewController: WalletConnectClientDelegate {
}
- func didReceive(notification: Session.Notification, sessionTopic: String) {
-
- }
-
func didUpgrade(sessionTopic: String, permissions: Session.Permissions) {
}
@@ -208,6 +203,9 @@ extension ResponderViewController: WalletConnectClientDelegate {
func didDelete(sessionTopic: String, reason: Reason) {
reloadActiveSessions()
+ DispatchQueue.main.async { [unowned self] in
+ navigationController?.popToRootViewController(animated: true)
+ }
}
private func getActiveSessionItem(for settledSessions: [Session]) -> [ActiveSessionItem] {
diff --git a/Example/ExampleApp/Responder/Signer.swift b/Example/ExampleApp/Responder/Signer.swift
index 89482ac59..683bde6d3 100644
--- a/Example/ExampleApp/Responder/Signer.swift
+++ b/Example/ExampleApp/Responder/Signer.swift
@@ -16,12 +16,8 @@ class Signer {
let result = "0x" + r.toHexString() + s.toHexString() + String(v + 27, radix: 16)
return AnyCodable(result)
} else if method == "eth_signTypedData" {
- let params = try! request.params.get([String].self)
- print(params)
- let messageToSign = params[1]
- let dataToHash = dataToHash(messageToSign)
- let (v, r, s) = try! self.privateKey.sign(message: .init(hex: dataToHash.toHexString()))
- let result = "0x" + r.toHexString() + s.toHexString() + String(v + 27, radix: 16)
+ //TODO
+ let result = "0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c"
return AnyCodable(result)
} else if method == "eth_sendTransaction" {
let params = try! request.params.get([EthereumTransaction].self)
diff --git a/Example/ExampleApp/SceneDelegate.swift b/Example/ExampleApp/SceneDelegate.swift
index 3cdd41306..9109d0f93 100644
--- a/Example/ExampleApp/SceneDelegate.swift
+++ b/Example/ExampleApp/SceneDelegate.swift
@@ -10,17 +10,29 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
window?.rootViewController = UITabBarController.createExampleApp()
window?.makeKeyAndVisible()
}
+
+ func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
+ guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
+ let incomingURL = userActivity.webpageURL else {
+ return
+ }
+ let wcUri = incomingURL.absoluteString.deletingPrefix("https://walletconnect.com/wc?uri=")
+ let client = ((window!.rootViewController as! UINavigationController).viewControllers[0] as! ResponderViewController).client
+ try? client.pair(uri: wcUri)
+ }
}
extension UITabBarController {
- static func createExampleApp() -> UITabBarController {
+ static func createExampleApp() -> UINavigationController {
let responderController = UINavigationController(rootViewController: ResponderViewController())
- responderController.tabBarItem = UITabBarItem(title: "Wallet", image: UIImage(systemName: "dollarsign.circle"), selectedImage: nil)
- let proposerController = UINavigationController(rootViewController: ProposerViewController())
- proposerController.tabBarItem = UITabBarItem(title: "Dapp", image: UIImage(systemName: "appclip"), selectedImage: nil)
- let tabBarController = UITabBarController()
- tabBarController.viewControllers = [responderController]
- return tabBarController
+ return responderController
+ }
+}
+
+extension String {
+ func deletingPrefix(_ prefix: String) -> String {
+ guard self.hasPrefix(prefix) else { return self }
+ return String(self.dropFirst(prefix.count))
}
}
diff --git a/Example/ExampleApp/SessionDetails/SessionDetailsViewController.swift b/Example/ExampleApp/SessionDetails/SessionDetailsViewController.swift
index 688cc3c87..69fe928ad 100644
--- a/Example/ExampleApp/SessionDetails/SessionDetailsViewController.swift
+++ b/Example/ExampleApp/SessionDetails/SessionDetailsViewController.swift
@@ -10,7 +10,7 @@ final class SessionDetailsViewController: UIViewController, UITableViewDelegate,
private let client: WalletConnectClient
private let session: Session
init(_ session: Session, _ client: WalletConnectClient) {
- let pendingRequests = client.getPendingRequests().map{$0.method}
+ let pendingRequests = client.getPendingRequests(topic: session.topic).map{$0.method}
self.sessionInfo = SessionInfo(name: session.peer.name ?? "",
descriptionText: session.peer.description ?? "",
dappURL: session.peer.description ?? "",
@@ -99,7 +99,7 @@ final class SessionDetailsViewController: UIViewController, UITableViewDelegate,
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 2 {
- let pendingRequests = client.getPendingRequests()
+ let pendingRequests = client.getPendingRequests(topic: session.topic)
showSessionRequest(pendingRequests[indexPath.row])
}
}
@@ -120,7 +120,7 @@ final class SessionDetailsViewController: UIViewController, UITableViewDelegate,
}
func reloadTable() {
- let pendingRequests = client.getPendingRequests().map{$0.method}
+ let pendingRequests = client.getPendingRequests(topic: session.topic).map{$0.method}
self.sessionInfo = SessionInfo(name: session.peer.name ?? "",
descriptionText: session.peer.description ?? "",
dappURL: session.peer.description ?? "",
diff --git a/Example/ExampleAppTests/ExampleAppTests.swift b/Example/ExampleAppTests/ExampleAppTests.swift
deleted file mode 100644
index e16431ce7..000000000
--- a/Example/ExampleAppTests/ExampleAppTests.swift
+++ /dev/null
@@ -1,5 +0,0 @@
-
-import XCTest
-
-class ExampleAppTests: XCTestCase {
-}
diff --git a/Example/Wallet.entitlements b/Example/Wallet.entitlements
new file mode 100644
index 000000000..44da28df4
--- /dev/null
+++ b/Example/Wallet.entitlements
@@ -0,0 +1,10 @@
+
+
+
+
+ com.apple.developer.associated-domains
+
+ applinks:walletconnect.com
+
+
+
diff --git a/Example/WalletTests/WalletTests.swift b/Example/WalletTests/WalletTests.swift
new file mode 100644
index 000000000..a248726c3
--- /dev/null
+++ b/Example/WalletTests/WalletTests.swift
@@ -0,0 +1,35 @@
+//
+// WalletTests.swift
+// WalletTests
+//
+// Created by Admin on 27/01/2022.
+//
+
+import XCTest
+
+class WalletTests: XCTestCase {
+
+ override func setUpWithError() throws {
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDownWithError() throws {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ }
+
+ func testExample() throws {
+ // This is an example of a functional test case.
+ // Use XCTAssert and related functions to verify your tests produce the correct results.
+ // Any test you write for XCTest can be annotated as throws and async.
+ // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
+ // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
+ }
+
+ func testPerformanceExample() throws {
+ // This is an example of a performance test case.
+ measure {
+ // Put the code you want to measure the time of here.
+ }
+ }
+
+}
diff --git a/Example/fastlane/Fastfile b/Example/fastlane/Fastfile
index b63a04a84..45180026e 100644
--- a/Example/fastlane/Fastfile
+++ b/Example/fastlane/Fastfile
@@ -2,8 +2,13 @@
default_platform(:ios)
platform :ios do
- desc "Test Example App"
- lane :test_app do
- scan(xcargs: "-allowProvisioningUpdates")
+ desc "Test Example Wallet"
+ lane :test_wallet do
+ scan(xcargs: "-allowProvisioningUpdates", scheme: "Wallet")
+ end
+
+ desc "Test Example dapp"
+ lane :test_dapp do
+ scan(xcargs: "-allowProvisioningUpdates", scheme: "DApp")
end
end
diff --git a/README.md b/README.md
index 3d23662fe..0da9866f2 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,11 @@ Swift implementation of WalletConnect v.2 protocol for native iOS applications.
- Swift 5
## Documentation
-In order to build documentation in XCode go to Product -> Build Documentation
+- In order to build API documentation in XCode go to Product -> Build Documentation
+- [Getting started with wallet integration](https://docs.walletconnect.com/2.0/quick-start/wallets/swift)
+- [Beginner guide to WalletConnect v2.0 for iOS Developers](https://medium.com/walletconnect/beginner-guide-to-walletconnect-v2-0-for-swift-developers-4534b0975218)
+- [Protocol Documentation](https://docs.walletconnect.com/2.0/protocol/client-communication)
+- [Glossary](https://docs.walletconnect.com/2.0/protocol/glossary)
## Usage
### Responder
diff --git a/Sources/Relayer/WakuNetworkRelay.swift b/Sources/Relayer/WakuNetworkRelay.swift
index e126b30b9..7477a759c 100644
--- a/Sources/Relayer/WakuNetworkRelay.swift
+++ b/Sources/Relayer/WakuNetworkRelay.swift
@@ -184,7 +184,7 @@ public final class WakuNetworkRelay {
private func acknowledgeSubscription(requestId: Int64) {
let response = JSONRPCResponse(id: requestId, result: AnyCodable(true))
let responseJson = try! response.json()
- _ = try? jsonRpcSubscriptionsHistory.resolve(response: JsonRpcResponseTypes.response(response))
+ _ = try? jsonRpcSubscriptionsHistory.resolve(response: JsonRpcResult.response(response))
dispatcher.send(responseJson) { [weak self] error in
if let error = error {
self?.logger.debug("Failed to Respond for request id: \(requestId), error: \(error)")
diff --git a/Sources/WalletConnect/Engine/PairingEngine.swift b/Sources/WalletConnect/Engine/PairingEngine.swift
index bff5522e0..29736ef5a 100644
--- a/Sources/WalletConnect/Engine/PairingEngine.swift
+++ b/Sources/WalletConnect/Engine/PairingEngine.swift
@@ -196,7 +196,7 @@ final class PairingEngine {
return
}
let response = JSONRPCResponse(id: requestId, result: AnyCodable(true))
- relayer.respond(topic: topic, response: JsonRpcResponseTypes.response(response)) { [unowned self] error in
+ relayer.respond(topic: topic, response: JsonRpcResult.response(response)) { [unowned self] error in
if let error = error {
logger.error(error)
} else {
@@ -209,7 +209,7 @@ final class PairingEngine {
private func handlePairingPing(topic: String, requestId: Int64) {
let response = JSONRPCResponse(id: requestId, result: AnyCodable(true))
- relayer.respond(topic: topic, response: JsonRpcResponseTypes.response(response)) { error in
+ relayer.respond(topic: topic, response: JsonRpcResult.response(response)) { error in
//todo
}
}
@@ -229,7 +229,7 @@ final class PairingEngine {
try? crypto.setAgreementSecret(pairingAgreementSecret, topic: sessionProposal.topic)
}
let response = JSONRPCResponse(id: requestId, result: AnyCodable(true))
- relayer.respond(topic: topic, response: JsonRpcResponseTypes.response(response)) { [weak self] error in
+ relayer.respond(topic: topic, response: JsonRpcResult.response(response)) { [weak self] error in
self?.onSessionProposal?(sessionProposal)
}
}
@@ -260,7 +260,7 @@ final class PairingEngine {
// TODO: Move JSON-RPC responding to networking layer
let response = JSONRPCResponse(id: requestId, result: AnyCodable(true))
- relayer.respond(topic: proposal.topic, response: JsonRpcResponseTypes.response(response)) { [weak self] error in
+ relayer.respond(topic: proposal.topic, response: JsonRpcResult.response(response)) { [weak self] error in
if let error = error {
self?.logger.error("Could not respond with error: \(error)")
}
diff --git a/Sources/WalletConnect/Engine/SessionEngine.swift b/Sources/WalletConnect/Engine/SessionEngine.swift
index cea274cd0..529fc5810 100644
--- a/Sources/WalletConnect/Engine/SessionEngine.swift
+++ b/Sources/WalletConnect/Engine/SessionEngine.swift
@@ -3,8 +3,8 @@ import Combine
import WalletConnectUtils
final class SessionEngine {
-
var onSessionPayloadRequest: ((Request)->())?
+ var onSessionPayloadResponse: ((Response)->())?
var onSessionApproved: ((Session)->())?
var onApprovalAcknowledgement: ((Session) -> Void)?
var onSessionRejected: ((String, SessionType.Reason)->())?
@@ -44,7 +44,7 @@ final class SessionEngine {
restoreSubscriptions()
relayer.onResponse = { [weak self] in
- self?.handleReponse($0)
+ self?.handleResponse($0)
}
}
@@ -56,7 +56,7 @@ final class SessionEngine {
sequencesStore.getAll().compactMap {
guard let settled = $0.settled else { return nil }
let permissions = Session.Permissions(blockchains: settled.permissions.blockchain.chains, methods: settled.permissions.jsonrpc.methods)
- return Session(topic: $0.topic, peer: settled.peer.metadata!, permissions: permissions)
+ return Session(topic: $0.topic, peer: settled.peer.metadata!, permissions: permissions, accounts: settled.state.accounts)
}
}
@@ -164,7 +164,7 @@ final class SessionEngine {
}
}
- func request(params: Request, completion: @escaping ((Result, JSONRPCErrorResponse>)->())) {
+ func request(params: Request) {
guard sequencesStore.hasSequence(forTopic: params.topic) else {
logger.debug("Could not find session for topic \(params.topic)")
return
@@ -174,17 +174,15 @@ final class SessionEngine {
let sessionPayloadRequest = WCRequest(id: params.id, method: .sessionPayload, params: .sessionPayload(sessionPayloadParams))
relayer.request(topic: params.topic, payload: sessionPayloadRequest) { [weak self] result in
switch result {
- case .success(let response):
- completion(.success(response))
+ case .success(_):
self?.logger.debug("Did receive session payload response")
case .failure(let error):
self?.logger.debug("error: \(error)")
- completion(.failure(error))
}
}
}
- func respondSessionPayload(topic: String, response: JsonRpcResponseTypes) {
+ func respondSessionPayload(topic: String, response: JsonRpcResult) {
guard sequencesStore.hasSequence(forTopic: topic) else {
logger.debug("Could not find session for topic \(topic)")
return
@@ -198,46 +196,45 @@ final class SessionEngine {
}
}
- func update(topic: String, accounts: Set) {
- guard var session = try? sequencesStore.getSequence(forTopic: topic) else {
- logger.debug("Could not find session for topic \(topic)")
- return
+ func update(topic: String, accounts: Set) throws {
+ guard var session = sequencesStore.getSequence(forTopic: topic) else {
+ throw WalletConnectError.internal(.noSequenceForTopic)
}
- session.update(accounts)
- relayer.request(.wcSessionUpdate(SessionType.UpdateParams(state: SessionState(accounts: accounts))), onTopic: topic) { [unowned self] result in
- switch result {
- case .success(_):
- sequencesStore.setSequence(session)
- onSessionUpdate?(topic, accounts)
- case .failure(_):
- break
+ for account in accounts {
+ if !String.conformsToCAIP10(account) {
+ throw WalletConnectError.internal(.notApproved) // TODO: Use a suitable error cases
}
}
+ if !isController || session.settled?.status != .acknowledged {
+ throw WalletConnectError.unauthrorized(.unauthorizedUpdateRequest)
+ }
+ session.update(accounts)
+ sequencesStore.setSequence(session)
+ relayer.request(.wcSessionUpdate(SessionType.UpdateParams(accounts: accounts)), onTopic: topic)
}
- func upgrade(topic: String, permissions: Session.Permissions) {
- guard var session = try? sequencesStore.getSequence(forTopic: topic) else {
- logger.debug("Could not find session for topic \(topic)")
- return
+ func upgrade(topic: String, permissions: Session.Permissions) throws {
+ let permissions = SessionPermissions(permissions: permissions)
+ guard var session = sequencesStore.getSequence(forTopic: topic) else {
+ throw WalletConnectError.noSessionMatchingTopic(topic)
}
- session.upgrade(permissions)
- guard let newPermissions = session.settled?.permissions else {
- return
+ guard session.isSettled else {
+ throw WalletConnectError.sessionNotSettled(topic)
}
- relayer.request(.wcSessionUpgrade(SessionType.UpgradeParams(permissions: newPermissions)), onTopic: topic) { [unowned self] result in
- switch result {
- case .success(_):
- sequencesStore.setSequence(session)
- onSessionUpgrade?(session.topic, newPermissions)
- case .failure(_):
- return
- //TODO
- }
+ guard isController else {
+ throw WalletConnectError.unauthorizedNonControllerCall
+ }
+ guard validatePermissions(permissions) else {
+ throw WalletConnectError.invalidPermissions
}
+ session.upgrade(permissions)
+ let newPermissions = session.settled!.permissions // We know session is settled
+ sequencesStore.setSequence(session)
+ relayer.request(.wcSessionUpgrade(SessionType.UpgradeParams(permissions: newPermissions)), onTopic: topic)
}
func notify(topic: String, params: Session.Notification, completion: ((Error?)->())?) {
- guard let session = try? sequencesStore.getSequence(forTopic: topic), session.isSettled else {
+ guard let session = sequencesStore.getSequence(forTopic: topic), session.isSettled else {
logger.debug("Could not find session for topic \(topic)")
return
}
@@ -270,9 +267,9 @@ final class SessionEngine {
case .sessionReject(let rejectParams):
handleSessionReject(rejectParams, topic: topic)
case .sessionUpdate(let updateParams):
- handleSessionUpdate(topic: topic, updateParams: updateParams, requestId: requestId)
+ handleSessionUpdate(payload: subscriptionPayload, updateParams: updateParams)
case .sessionUpgrade(let upgradeParams):
- handleSessionUpgrade(topic: topic, upgradeParams: upgradeParams, requestId: requestId)
+ handleSessionUpgrade(payload: subscriptionPayload, upgradeParams: upgradeParams)
case .sessionDelete(let deleteParams):
handleSessionDelete(deleteParams, topic: topic)
case .sessionPayload(let sessionPayloadParams):
@@ -288,13 +285,13 @@ final class SessionEngine {
}
private func handleSessionNotification(topic: String, notificationParams: SessionType.NotificationParams, requestId: Int64) {
- guard let session = try? sequencesStore.getSequence(forTopic: topic), session.isSettled else {
+ guard let session = sequencesStore.getSequence(forTopic: topic), session.isSettled else {
return
}
do {
try validateNotification(session: session, params: notificationParams)
let response = JSONRPCResponse(id: requestId, result: AnyCodable(true))
- relayer.respond(topic: topic, response: JsonRpcResponseTypes.response(response)) { [unowned self] error in
+ relayer.respond(topic: topic, response: JsonRpcResult.response(response)) { [unowned self] error in
if let error = error {
logger.error(error)
} else {
@@ -320,56 +317,54 @@ final class SessionEngine {
}
}
- private func handleSessionUpdate(topic: String, updateParams: SessionType.UpdateParams, requestId: Int64) {
- guard var session = try? sequencesStore.getSequence(forTopic: topic) else {
- logger.debug("Could not find session for topic \(topic)")
+ private func handleSessionUpdate(payload: WCRequestSubscriptionPayload, updateParams: SessionType.UpdateParams) {
+ for account in updateParams.state.accounts {
+ if !String.conformsToCAIP10(account) {
+ relayer.respondError(for: payload, reason: .invalidUpdateRequest(context: .session))
+ return
+ }
+ }
+ let topic = payload.topic
+ guard var session = sequencesStore.getSequence(forTopic: topic) else {
+ relayer.respondError(for: payload, reason: .noContextWithTopic(context: .session, topic: topic))
return
}
guard session.peerIsController else {
- let error = WalletConnectError.unauthrorized(.unauthorizedUpdateRequest)
- logger.error(error)
- respond(error: error, requestId: requestId, topic: topic)
+ relayer.respondError(for: payload, reason: .unauthorizedUpdateRequest(context: .session))
return
}
- let response = JSONRPCResponse(id: requestId, result: AnyCodable(true))
- relayer.respond(topic: topic, response: JsonRpcResponseTypes.response(response)) { [unowned self] error in
- if let error = error {
- logger.error(error)
- } else {
- session.settled?.state = updateParams.state
- sequencesStore.setSequence(session)
- onSessionUpdate?(topic, updateParams.state.accounts)
- }
+ guard !isController else {
+ relayer.respondError(for: payload, reason: .unauthorizedMatchingController(isController: isController))
+ return
}
+ session.settled?.state = updateParams.state
+ sequencesStore.setSequence(session)
+ relayer.respondSuccess(for: payload)
+ onSessionUpdate?(topic, updateParams.state.accounts)
}
- private func handleSessionUpgrade(topic: String, upgradeParams: SessionType.UpgradeParams, requestId: Int64) {
- guard var session = try? sequencesStore.getSequence(forTopic: topic) else {
- logger.debug("Could not find session for topic \(topic)")
+ private func handleSessionUpgrade(payload: WCRequestSubscriptionPayload, upgradeParams: SessionType.UpgradeParams) {
+ guard validatePermissions(upgradeParams.permissions) else {
+ relayer.respondError(for: payload, reason: .invalidUpgradeRequest(context: .session))
return
}
- guard session.peerIsController else {
- let error = WalletConnectError.unauthrorized(.unauthorizedUpgradeRequest)
- logger.error(error)
- respond(error: error, requestId: requestId, topic: topic)
+ guard var session = sequencesStore.getSequence(forTopic: payload.topic) else {
+ relayer.respondError(for: payload, reason: .noContextWithTopic(context: .session, topic: payload.topic))
return
}
- let permissions = Session.Permissions(
- blockchains: upgradeParams.permissions.blockchain.chains,
- methods: upgradeParams.permissions.jsonrpc.methods)
- session.upgrade(permissions)
- guard let newPermissions = session.settled?.permissions else {
+ guard session.peerIsController else {
+ relayer.respondError(for: payload, reason: .unauthorizedUpgradeRequest(context: .session))
return
}
- let response = JSONRPCResponse(id: requestId, result: AnyCodable(true))
- relayer.respond(topic: topic, response: JsonRpcResponseTypes.response(response)) { [unowned self] error in
- if let error = error {
- logger.error(error)
- } else {
- sequencesStore.setSequence(session)
- onSessionUpgrade?(session.topic, newPermissions)
- }
+ guard !isController else {
+ relayer.respondError(for: payload, reason: .unauthorizedMatchingController(isController: isController))
+ return
}
+ session.upgrade(upgradeParams.permissions)
+ sequencesStore.setSequence(session)
+ let newPermissions = session.settled!.permissions // We know session is settled
+ relayer.respondSuccess(for: payload)
+ onSessionUpgrade?(session.topic, newPermissions)
}
private func handleSessionPing(topic: String, requestId: Int64) {
@@ -419,7 +414,7 @@ final class SessionEngine {
private func respond(error: WalletConnectError, requestId: Int64, topic: String) {
let jsonrpcError = JSONRPCErrorResponse.Error(code: error.code, message: error.description)
let response = JSONRPCErrorResponse(id: requestId, error: jsonrpcError)
- relayer.respond(topic: topic, response: JsonRpcResponseTypes.error(response)) { [weak self] responseError in
+ relayer.respond(topic: topic, response: JsonRpcResult.error(response)) { [weak self] responseError in
if let responseError = responseError {
self?.logger.error("Could not respond with error: \(responseError)")
} else {
@@ -429,7 +424,7 @@ final class SessionEngine {
}
private func validatePayload(_ sessionRequest: Request) throws {
- guard let session = try? sequencesStore.getSequence(forTopic: sessionRequest.topic) else {
+ guard let session = sequencesStore.getSequence(forTopic: sessionRequest.topic) else {
throw WalletConnectError.internal(.noSequenceForTopic)
}
if let chainId = sessionRequest.chainId {
@@ -449,7 +444,7 @@ final class SessionEngine {
logger.warn("Warning: Session Engine - Unexpected handleSessionApprove method call by non Controller client")
return
}
- guard let session = try? sequencesStore.getSequence(forTopic: topic),
+ guard let session = sequencesStore.getSequence(forTopic: topic),
let pendingSession = session.pending else {
logger.error("Could not find pending session for topic: \(topic)")
return
@@ -476,10 +471,10 @@ final class SessionEngine {
peer: approveParams.responder.metadata,
permissions: Session.Permissions(
blockchains: pendingSession.proposal.permissions.blockchain.chains,
- methods: pendingSession.proposal.permissions.jsonrpc.methods))
+ methods: pendingSession.proposal.permissions.jsonrpc.methods), accounts: settledSession.settled!.state.accounts)
let response = JSONRPCResponse(id: requestId, result: AnyCodable(true))
- relayer.respond(topic: topic, response: JsonRpcResponseTypes.response(response)) { [unowned self] error in
+ relayer.respond(topic: topic, response: JsonRpcResult.response(response)) { [unowned self] error in
if let error = error {
logger.error(error)
}
@@ -502,23 +497,30 @@ final class SessionEngine {
}.store(in: &publishers)
}
- private func handleReponse(_ response: WCResponse) {
+ private func handleResponse(_ response: WCResponse) {
switch response.requestParams {
case .pairingPayload(let payloadParams):
let proposeParams = payloadParams.request.params
handleProposeResponse(topic: response.topic, proposeParams: proposeParams, result: response.result)
- case .sessionApprove(let approveParams):
+ case .sessionApprove(_):
handleApproveResponse(topic: response.topic, result: response.result)
+ case .sessionUpdate:
+ handleUpdateResponse(topic: response.topic, result: response.result)
+ case .sessionUpgrade:
+ handleUpgradeResponse(topic: response.topic, result: response.result)
+ case .sessionPayload(_):
+ let response = Response(topic: response.topic, chainId: response.chainId, result: response.result)
+ onSessionPayloadResponse?(response)
default:
break
}
}
- private func handleProposeResponse(topic: String, proposeParams: SessionProposal, result: Result, Error>) {
+ private func handleProposeResponse(topic: String, proposeParams: SessionProposal, result: JsonRpcResult) {
switch result {
- case .success:
+ case .response:
break
- case .failure:
+ case .error:
wcSubscriber.removeSubscription(topic: proposeParams.topic)
crypto.deletePrivateKey(for: proposeParams.proposer.publicKey)
crypto.deleteAgreementSecret(for: topic)
@@ -526,16 +528,17 @@ final class SessionEngine {
}
}
- private func handleApproveResponse(topic: String, result: Result, Error>) {
+ private func handleApproveResponse(topic: String, result: JsonRpcResult) {
guard
- let pendingSession = try? sequencesStore.getSequence(forTopic: topic),
+ let pendingSession = sequencesStore.getSequence(forTopic: topic),
let settledTopic = pendingSession.pending?.outcomeTopic,
let proposal = pendingSession.pending?.proposal
else {
return
}
switch result {
- case .success:
+ case .response:
+ guard let settledSession = try? sequencesStore.getSequence(forTopic: settledTopic) else {return}
crypto.deleteAgreementSecret(for: topic)
wcSubscriber.removeSubscription(topic: topic)
sequencesStore.delete(topic: topic)
@@ -544,9 +547,9 @@ final class SessionEngine {
peer: proposal.proposer.metadata,
permissions: Session.Permissions(
blockchains: proposal.permissions.blockchain.chains,
- methods: proposal.permissions.jsonrpc.methods))
+ methods: proposal.permissions.jsonrpc.methods), accounts: settledSession.settled!.state.accounts)
onApprovalAcknowledgement?(sessionSuccess)
- case .failure:
+ case .error:
wcSubscriber.removeSubscription(topic: topic)
wcSubscriber.removeSubscription(topic: settledTopic)
sequencesStore.delete(topic: topic)
@@ -556,4 +559,49 @@ final class SessionEngine {
crypto.deletePrivateKey(for: pendingSession.publicKey)
}
}
+
+ private func handleUpdateResponse(topic: String, result: JsonRpcResult) {
+ guard let session = sequencesStore.getSequence(forTopic: topic), let accounts = session.settled?.state.accounts else {
+ return
+ }
+ switch result {
+ case .response:
+ onSessionUpdate?(topic, accounts)
+ case .error:
+ logger.error("Peer failed to update state.")
+ }
+ }
+
+ private func handleUpgradeResponse(topic: String, result: JsonRpcResult) {
+ guard let session = sequencesStore.getSequence(forTopic: topic), let permissions = session.settled?.permissions else {
+ return
+ }
+ switch result {
+ case .response:
+ onSessionUpgrade?(session.topic, permissions)
+ case .error:
+ logger.error("Peer failed to upgrade permissions.")
+ }
+ }
+
+ private func validatePermissions(_ permissions: SessionPermissions) -> Bool {
+ for chainId in permissions.blockchain.chains {
+ if !String.conformsToCAIP2(chainId) {
+ return false
+ }
+ }
+ for method in permissions.jsonrpc.methods {
+ if method.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
+ return false
+ }
+ }
+ if let notificationTypes = permissions.notifications?.types {
+ for notification in notificationTypes {
+ if notification.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
+ return false
+ }
+ }
+ }
+ return true
+ }
}
diff --git a/Sources/WalletConnect/JsonRpcHistory/JsonRpcHistory.swift b/Sources/WalletConnect/JsonRpcHistory/JsonRpcHistory.swift
index 9909dccd2..2d0724c0f 100644
--- a/Sources/WalletConnect/JsonRpcHistory/JsonRpcHistory.swift
+++ b/Sources/WalletConnect/JsonRpcHistory/JsonRpcHistory.swift
@@ -6,7 +6,7 @@ protocol JsonRpcHistoryRecording {
func get(id: Int64) -> JsonRpcRecord?
func set(topic: String, request: WCRequest, chainId: String?) throws
func delete(topic: String)
- func resolve(response: JsonRpcResponseTypes) throws -> JsonRpcRecord
+ func resolve(response: JsonRpcResult) throws -> JsonRpcRecord
func exist(id: Int64) -> Bool
}
//TODO -remove and use jsonrpc history only from utils
@@ -40,7 +40,7 @@ class JsonRpcHistory: JsonRpcHistoryRecording {
}
}
- func resolve(response: JsonRpcResponseTypes) throws -> JsonRpcRecord {
+ func resolve(response: JsonRpcResult) throws -> JsonRpcRecord {
logger.debug("Resolving JSON-RPC response - ID: \(response.id)")
guard var record = try? storage.get(key: "\(response.id)") else {
throw WalletConnectError.internal(.noJsonRpcRequestMatchingResponse)
diff --git a/Sources/WalletConnect/JsonRpcHistory/JsonRpcRecord.swift b/Sources/WalletConnect/JsonRpcHistory/JsonRpcRecord.swift
index f1461c5be..da8a1e0b1 100644
--- a/Sources/WalletConnect/JsonRpcHistory/JsonRpcRecord.swift
+++ b/Sources/WalletConnect/JsonRpcHistory/JsonRpcRecord.swift
@@ -7,7 +7,7 @@ struct JsonRpcRecord: Codable {
let id: Int64
let topic: String
let request: Request
- var response: JsonRpcResponseTypes?
+ var response: JsonRpcResult?
let chainId: String?
struct Request: Codable {
diff --git a/Sources/WalletConnect/Relay/WalletConnectRelay.swift b/Sources/WalletConnect/Relay/WalletConnectRelay.swift
index c0f39e4e0..64d25655b 100644
--- a/Sources/WalletConnect/Relay/WalletConnectRelay.swift
+++ b/Sources/WalletConnect/Relay/WalletConnectRelay.swift
@@ -5,9 +5,10 @@ import WalletConnectUtils
struct WCResponse {
let topic: String
+ let chainId: String?
let requestMethod: WCRequest.Method
let requestParams: WCRequest.Params
- let result: Result, Error>
+ let result: JsonRpcResult
}
protocol WalletConnectRelaying: AnyObject {
@@ -17,7 +18,9 @@ protocol WalletConnectRelaying: AnyObject {
var wcRequestPublisher: AnyPublisher {get}
func request(_ wcMethod: WCMethod, onTopic topic: String, completion: ((Result, JSONRPCErrorResponse>)->())?)
func request(topic: String, payload: WCRequest, completion: ((Result, JSONRPCErrorResponse>)->())?)
- func respond(topic: String, response: JsonRpcResponseTypes, completion: @escaping ((Error?)->()))
+ func respond(topic: String, response: JsonRpcResult, completion: @escaping ((Error?)->()))
+ func respondSuccess(for payload: WCRequestSubscriptionPayload)
+ func respondError(for payload: WCRequestSubscriptionPayload, reason: ReasonCode)
func subscribe(topic: String)
func unsubscribe(topic: String)
}
@@ -34,7 +37,7 @@ class WalletConnectRelay: WalletConnectRelaying {
var onResponse: ((WCResponse) -> Void)?
private var networkRelayer: NetworkRelaying
- private let jsonRpcSerialiser: JSONRPCSerialising
+ private let jsonRpcSerializer: JSONRPCSerializing
private let jsonRpcHistory: JsonRpcHistoryRecording
var transportConnectionPublisher: AnyPublisher {
@@ -48,18 +51,18 @@ class WalletConnectRelay: WalletConnectRelaying {
}
private let wcRequestPublisherSubject = PassthroughSubject()
- private var wcResponsePublisher: AnyPublisher {
+ private var wcResponsePublisher: AnyPublisher {
wcResponsePublisherSubject.eraseToAnyPublisher()
}
- private let wcResponsePublisherSubject = PassthroughSubject()
+ private let wcResponsePublisherSubject = PassthroughSubject()
let logger: ConsoleLogging
init(networkRelayer: NetworkRelaying,
- jsonRpcSerialiser: JSONRPCSerialising,
+ jsonRpcSerializer: JSONRPCSerializing,
logger: ConsoleLogging,
jsonRpcHistory: JsonRpcHistoryRecording) {
self.networkRelayer = networkRelayer
- self.jsonRpcSerialiser = jsonRpcSerialiser
+ self.jsonRpcSerializer = jsonRpcSerializer
self.logger = logger
self.jsonRpcHistory = jsonRpcHistory
setUpPublishers()
@@ -72,7 +75,7 @@ class WalletConnectRelay: WalletConnectRelaying {
func request(topic: String, payload: WCRequest, completion: ((Result, JSONRPCErrorResponse>)->())?) {
do {
try jsonRpcHistory.set(topic: topic, request: payload, chainId: getChainId(payload))
- let message = try jsonRpcSerialiser.serialise(topic: topic, encodable: payload)
+ let message = try jsonRpcSerializer.serialize(topic: topic, encodable: payload)
networkRelayer.publish(topic: topic, payload: message) { [weak self] error in
guard let self = self else {return}
if let error = error {
@@ -101,10 +104,11 @@ class WalletConnectRelay: WalletConnectRelaying {
}
}
- func respond(topic: String, response: JsonRpcResponseTypes, completion: @escaping ((Error?)->())) {
+ func respond(topic: String, response: JsonRpcResult, completion: @escaping ((Error?)->())) {
do {
_ = try jsonRpcHistory.resolve(response: response)
- let message = try jsonRpcSerialiser.serialise(topic: topic, encodable: response.value)
+
+ let message = try jsonRpcSerializer.serialize(topic: topic, encodable: response.value)
logger.debug("Responding....topic: \(topic)")
networkRelayer.publish(topic: topic, payload: message) { error in
completion(error)
@@ -116,6 +120,16 @@ class WalletConnectRelay: WalletConnectRelaying {
}
}
+ func respondSuccess(for payload: WCRequestSubscriptionPayload) {
+ let response = JSONRPCResponse(id: payload.wcRequest.id, result: AnyCodable(true))
+ respond(topic: payload.topic, response: JsonRpcResult.response(response)) { _ in } // TODO: Move error handling to relayer package
+ }
+
+ func respondError(for payload: WCRequestSubscriptionPayload, reason: ReasonCode) {
+ let response = JSONRPCErrorResponse(id: payload.wcRequest.id, error: JSONRPCErrorResponse.Error(code: reason.code, message: reason.message))
+ respond(topic: payload.topic, response: JsonRpcResult.error(response)) { _ in } // TODO: Move error handling to relayer package
+ }
+
func subscribe(topic: String) {
networkRelayer.subscribe(topic: topic) { [weak self] error in
if let error = error {
@@ -145,12 +159,12 @@ class WalletConnectRelay: WalletConnectRelaying {
}
private func manageSubscription(_ topic: String, _ message: String) {
- if let deserialisedJsonRpcRequest: WCRequest = jsonRpcSerialiser.tryDeserialise(topic: topic, message: message) {
- handleWCRequest(topic: topic, request: deserialisedJsonRpcRequest)
- } else if let deserialisedJsonRpcResponse: JSONRPCResponse = jsonRpcSerialiser.tryDeserialise(topic: topic, message: message) {
- handleJsonRpcResponse(response: deserialisedJsonRpcResponse)
- } else if let deserialisedJsonRpcError: JSONRPCErrorResponse = jsonRpcSerialiser.tryDeserialise(topic: topic, message: message) {
- handleJsonRpcErrorResponse(response: deserialisedJsonRpcError)
+ if let deserializedJsonRpcRequest: WCRequest = jsonRpcSerializer.tryDeserialize(topic: topic, message: message) {
+ handleWCRequest(topic: topic, request: deserializedJsonRpcRequest)
+ } else if let deserializedJsonRpcResponse: JSONRPCResponse = jsonRpcSerializer.tryDeserialize(topic: topic, message: message) {
+ handleJsonRpcResponse(response: deserializedJsonRpcResponse)
+ } else if let deserializedJsonRpcError: JSONRPCErrorResponse = jsonRpcSerializer.tryDeserialize(topic: topic, message: message) {
+ handleJsonRpcErrorResponse(response: deserializedJsonRpcError)
} else {
logger.warn("Warning: WalletConnect Relay - Received unknown object type from networking relay")
}
@@ -170,12 +184,13 @@ class WalletConnectRelay: WalletConnectRelaying {
private func handleJsonRpcResponse(response: JSONRPCResponse) {
do {
- let record = try jsonRpcHistory.resolve(response: JsonRpcResponseTypes.response(response))
+ let record = try jsonRpcHistory.resolve(response: JsonRpcResult.response(response))
let wcResponse = WCResponse(
topic: record.topic,
+ chainId: record.chainId,
requestMethod: record.request.method,
requestParams: record.request.params,
- result: .success(response))
+ result: JsonRpcResult.response(response))
wcResponsePublisherSubject.send(.response(response))
onPairingResponse?(wcResponse)
onResponse?(wcResponse)
@@ -186,12 +201,13 @@ class WalletConnectRelay: WalletConnectRelaying {
private func handleJsonRpcErrorResponse(response: JSONRPCErrorResponse) {
do {
- let record = try jsonRpcHistory.resolve(response: JsonRpcResponseTypes.error(response))
+ let record = try jsonRpcHistory.resolve(response: JsonRpcResult.error(response))
let wcResponse = WCResponse(
topic: record.topic,
+ chainId: record.chainId,
requestMethod: record.request.method,
requestParams: record.request.params,
- result: .failure(response))
+ result: JsonRpcResult.error(response))
wcResponsePublisherSubject.send(.error(response))
onPairingResponse?(wcResponse)
onResponse?(wcResponse)
diff --git a/Sources/WalletConnect/Response.swift b/Sources/WalletConnect/Response.swift
new file mode 100644
index 000000000..736893173
--- /dev/null
+++ b/Sources/WalletConnect/Response.swift
@@ -0,0 +1,9 @@
+
+import Foundation
+import WalletConnectUtils
+
+public struct Response: Codable {
+ public let topic: String
+ public let chainId: String?
+ public let result: JsonRpcResult
+}
diff --git a/Sources/WalletConnect/Serialiser/JSONRPCSerialiserError.swift b/Sources/WalletConnect/Serialiser/JSONRPCSerialiserError.swift
index eadaeec5d..87b10edf9 100644
--- a/Sources/WalletConnect/Serialiser/JSONRPCSerialiserError.swift
+++ b/Sources/WalletConnect/Serialiser/JSONRPCSerialiserError.swift
@@ -2,6 +2,6 @@
import Foundation
-enum JSONRPCSerialiserError: String, Error {
+enum JSONRPCSerializerError: String, Error {
case messageToShort = "Error: message is too short"
}
diff --git a/Sources/WalletConnect/Serialiser/JSONRPCSerializing.swift b/Sources/WalletConnect/Serialiser/JSONRPCSerializing.swift
index 14e804bc2..6be4a9a2f 100644
--- a/Sources/WalletConnect/Serialiser/JSONRPCSerializing.swift
+++ b/Sources/WalletConnect/Serialiser/JSONRPCSerializing.swift
@@ -1,12 +1,12 @@
import Foundation
-protocol JSONRPCSerialising {
- func serialise(topic: String, encodable: Encodable) throws -> String
- func tryDeserialise(topic: String, message: String) -> T?
+protocol JSONRPCSerializing {
+ func serialize(topic: String, encodable: Encodable) throws -> String
+ func tryDeserialize(topic: String, message: String) -> T?
var codec: Codec {get}
}
-class JSONRPCSerialiser: JSONRPCSerialising {
+class JSONRPCSerializer: JSONRPCSerializing {
private let crypto: Crypto
let codec: Codec
@@ -16,7 +16,7 @@ class JSONRPCSerialiser: JSONRPCSerialising {
self.codec = codec
}
- func serialise(topic: String, encodable: Encodable) throws -> String {
+ func serialize(topic: String, encodable: Encodable) throws -> String {
let messageJson = try encodable.json()
var message: String
if let agreementKeys = try? crypto.getAgreementSecret(for: topic) {
@@ -27,23 +27,23 @@ class JSONRPCSerialiser: JSONRPCSerialising {
return message
}
- func tryDeserialise(topic: String, message: String) -> T? {
+ func tryDeserialize(topic: String, message: String) -> T? {
do {
- let deserialisedJsonRpcRequest: T
+ let deserializedJsonRpcRequest: T
if let agreementKeys = try? crypto.getAgreementSecret(for: topic) {
- deserialisedJsonRpcRequest = try deserialise(message: message, symmetricKey: agreementKeys.sharedSecret)
+ deserializedJsonRpcRequest = try deserialize(message: message, symmetricKey: agreementKeys.sharedSecret)
} else {
let jsonData = Data(hex: message)
- deserialisedJsonRpcRequest = try JSONDecoder().decode(T.self, from: jsonData)
+ deserializedJsonRpcRequest = try JSONDecoder().decode(T.self, from: jsonData)
}
- return deserialisedJsonRpcRequest
+ return deserializedJsonRpcRequest
} catch {
// logger.debug("Type \(T.self) does not match the payload")
return nil
}
}
- func deserialise(message: String, symmetricKey: Data) throws -> T {
+ func deserialize(message: String, symmetricKey: Data) throws -> T {
let JSONRPCData = try decrypt(message: message, symmetricKey: symmetricKey)
return try JSONDecoder().decode(T.self, from: JSONRPCData)
}
@@ -58,7 +58,7 @@ class JSONRPCSerialiser: JSONRPCSerialising {
}
private func decrypt(message: String, symmetricKey: Data) throws -> Data {
- let encryptionPayload = try deserialiseIntoPayload(message: message)
+ let encryptionPayload = try deserializeIntoPayload(message: message)
let decryptedJSONRPC = try codec.decode(payload: encryptionPayload, sharedSecret: symmetricKey)
guard let JSONRPCData = decryptedJSONRPC.data(using: .utf8) else {
throw DataConversionError.stringToDataFailed
@@ -66,10 +66,10 @@ class JSONRPCSerialiser: JSONRPCSerialising {
return JSONRPCData
}
- private func deserialiseIntoPayload(message: String) throws -> EncryptionPayload {
+ private func deserializeIntoPayload(message: String) throws -> EncryptionPayload {
let data = Data(hex: message)
guard data.count > EncryptionPayload.ivLength + EncryptionPayload.publicKeyLength + EncryptionPayload.macLength else {
- throw JSONRPCSerialiserError.messageToShort
+ throw JSONRPCSerializerError.messageToShort
}
let pubKeyRangeStartIndex = EncryptionPayload.ivLength
let macStartIndex = pubKeyRangeStartIndex + EncryptionPayload.publicKeyLength
diff --git a/Sources/WalletConnect/Session.swift b/Sources/WalletConnect/Session.swift
index cd790bf29..6b371767b 100644
--- a/Sources/WalletConnect/Session.swift
+++ b/Sources/WalletConnect/Session.swift
@@ -7,6 +7,7 @@ public struct Session {
public let topic: String
public let peer: AppMetadata
public let permissions: Permissions
+ public let accounts: Set
}
extension Session {
diff --git a/Sources/WalletConnect/Storage/SessionStorage.swift b/Sources/WalletConnect/Storage/SessionStorage.swift
index c34095eb7..64e5aefb7 100644
--- a/Sources/WalletConnect/Storage/SessionStorage.swift
+++ b/Sources/WalletConnect/Storage/SessionStorage.swift
@@ -2,7 +2,7 @@ protocol SessionSequenceStorage: AnyObject {
var onSequenceExpiration: ((_ topic: String, _ pubKey: String) -> Void)? { get set }
func hasSequence(forTopic topic: String) -> Bool
func setSequence(_ sequence: SessionSequence)
- func getSequence(forTopic topic: String) throws -> SessionSequence?
+ func getSequence(forTopic topic: String) -> SessionSequence?
func getAll() -> [SessionSequence]
func delete(topic: String)
}
@@ -28,8 +28,8 @@ final class SessionStorage: SessionSequenceStorage {
storage.setSequence(sequence)
}
- func getSequence(forTopic topic: String) throws -> SessionSequence? {
- try storage.getSequence(forTopic: topic)
+ func getSequence(forTopic topic: String) -> SessionSequence? {
+ return try? storage.getSequence(forTopic: topic)
}
func getAll() -> [SessionSequence] {
diff --git a/Sources/WalletConnect/Types/ReasonCode.swift b/Sources/WalletConnect/Types/ReasonCode.swift
new file mode 100644
index 000000000..187095d47
--- /dev/null
+++ b/Sources/WalletConnect/Types/ReasonCode.swift
@@ -0,0 +1,51 @@
+enum ReasonCode {
+
+ enum Context: String {
+ case pairing = "pairing"
+ case session = "session"
+ }
+
+ // 0 (Generic)
+ case generic(message: String)
+
+ // 1000 (Internal)
+ case invalidUpdateRequest(context: Context)
+ case invalidUpgradeRequest(context: Context)
+ case noContextWithTopic(context: Context, topic: String)
+
+ // 3000 (Unauthorized)
+ case unauthorizedUpdateRequest(context: Context)
+ case unauthorizedUpgradeRequest(context: Context)
+ case unauthorizedMatchingController(isController: Bool)
+
+ var code: Int {
+ switch self {
+ case .generic: return 0
+ case .invalidUpdateRequest: return 1003
+ case .invalidUpgradeRequest: return 1004
+ case .noContextWithTopic: return 1301
+ case .unauthorizedUpdateRequest: return 3003
+ case .unauthorizedUpgradeRequest: return 3004
+ case .unauthorizedMatchingController: return 3005
+ }
+ }
+
+ var message: String {
+ switch self {
+ case .generic(let message):
+ return message
+ case .invalidUpdateRequest(let context):
+ return "Invalid \(context) update request"
+ case .invalidUpgradeRequest(let context):
+ return "Invalid \(context) upgrade request"
+ case .noContextWithTopic(let context, let topic):
+ return "No matching \(context) with topic: \(topic)"
+ case .unauthorizedUpdateRequest(let context):
+ return "Unauthorized \(context) update request"
+ case .unauthorizedUpgradeRequest(let context):
+ return "Unauthorized \(context) upgrade request"
+ case .unauthorizedMatchingController(let isController):
+ return "Unauthorized: peer is also \(isController ? "" : "non-")controller"
+ }
+ }
+}
diff --git a/Sources/WalletConnect/Types/Session/SessionPermissions.swift b/Sources/WalletConnect/Types/Session/SessionPermissions.swift
index dc65d9ef1..6f19280b1 100644
--- a/Sources/WalletConnect/Types/Session/SessionPermissions.swift
+++ b/Sources/WalletConnect/Types/Session/SessionPermissions.swift
@@ -38,8 +38,8 @@ struct SessionPermissions: Codable, Equatable {
self.controller = nil
}
- mutating func upgrade(with sessionPermissions: Session.Permissions) {
- blockchain.chains.formUnion(sessionPermissions.blockchains)
- jsonrpc.methods.formUnion(sessionPermissions.methods)
+ mutating func upgrade(with permissions: SessionPermissions) {
+ blockchain.chains.formUnion(permissions.blockchain.chains)
+ jsonrpc.methods.formUnion(permissions.jsonrpc.methods)
}
}
diff --git a/Sources/WalletConnect/Types/Session/SessionSequence.swift b/Sources/WalletConnect/Types/Session/SessionSequence.swift
index 3a8604ce5..b54cf5158 100644
--- a/Sources/WalletConnect/Types/Session/SessionSequence.swift
+++ b/Sources/WalletConnect/Types/Session/SessionSequence.swift
@@ -39,7 +39,7 @@ struct SessionSequence: ExpirableSequence {
}
var isSettled: Bool {
- settled != nil
+ settled?.status == .acknowledged
}
var isController: Bool {
@@ -73,7 +73,7 @@ struct SessionSequence: ExpirableSequence {
return settled.permissions.jsonrpc.methods.contains(method)
}
- mutating func upgrade(_ permissions: Session.Permissions) {
+ mutating func upgrade(_ permissions: SessionPermissions) {
settled?.permissions.upgrade(with: permissions)
}
diff --git a/Sources/WalletConnect/Types/Session/SessionType.swift b/Sources/WalletConnect/Types/Session/SessionType.swift
index 2fe408f27..889dfe82d 100644
--- a/Sources/WalletConnect/Types/Session/SessionType.swift
+++ b/Sources/WalletConnect/Types/Session/SessionType.swift
@@ -19,6 +19,10 @@ internal enum SessionType {
struct UpdateParams: Codable, Equatable {
let state: SessionState
+
+ init(accounts: Set) {
+ self.state = SessionState(accounts: accounts)
+ }
}
struct UpgradeParams: Codable, Equatable {
diff --git a/Sources/WalletConnect/Types/WalletConnectURI.swift b/Sources/WalletConnect/Types/WalletConnectURI.swift
index 246d67637..078d97785 100644
--- a/Sources/WalletConnect/Types/WalletConnectURI.swift
+++ b/Sources/WalletConnect/Types/WalletConnectURI.swift
@@ -1,11 +1,11 @@
import Foundation
-struct WalletConnectURI: Equatable {
+public struct WalletConnectURI: Equatable {
- let topic: String
- let version: String
- let publicKey: String
- let isController: Bool
+ public let topic: String
+ public let version: String
+ public let publicKey: String
+ public let isController: Bool
let relay: RelayProtocolOptions
init(topic: String, publicKey: String, isController: Bool, relay: RelayProtocolOptions) {
@@ -16,7 +16,7 @@ struct WalletConnectURI: Equatable {
self.relay = relay
}
- init?(string: String) {
+ public init?(string: String) {
guard string.hasPrefix("wc:") else {
return nil
}
@@ -41,7 +41,7 @@ struct WalletConnectURI: Equatable {
self.relay = relay
}
- var absoluteString: String {
+ public var absoluteString: String {
return "wc:\(topic)@\(version)?controller=\(isController)&publicKey=\(publicKey)&relay=\(relay.asPercentEncodedString())"
}
}
diff --git a/Sources/WalletConnect/WalletConnectClient.swift b/Sources/WalletConnect/WalletConnectClient.swift
index 5f5cd0157..ddb239ff8 100644
--- a/Sources/WalletConnect/WalletConnectClient.swift
+++ b/Sources/WalletConnect/WalletConnectClient.swift
@@ -8,7 +8,7 @@ import UIKit
/// An Object that expose public API to provide interactions with WalletConnect SDK
///
-/// WalletConnect Client is not a singleton but once you create an instance, you should not deinitialise it. Usually only one instance of a client is required in the application.
+/// WalletConnect Client is not a singleton but once you create an instance, you should not deinitialize it. Usually only one instance of a client is required in the application.
///
/// ```swift
/// let metadata = AppMetadata(name: String?, description: String?, url: String?, icons: [String]?)
@@ -47,7 +47,7 @@ public final class WalletConnectClient {
/// - keyValueStorage: by default WalletConnect SDK will store sequences in UserDefaults but if for some reasons you want to provide your own storage you can inject it here.
/// - clientName: if your app requires more than one client you are required to call them with different names to distinguish logs source and prefix storage keys.
///
- /// WalletConnect Client is not a singleton but once you create an instance, you should not deinitialise it. Usually only one instance of a client is required in the application.
+ /// WalletConnect Client is not a singleton but once you create an instance, you should not deinitialize it. Usually only one instance of a client is required in the application.
public convenience init(metadata: AppMetadata, projectId: String, isController: Bool, relayHost: String, keyValueStorage: KeyValueStorage = UserDefaults.standard, clientName: String? = nil) {
self.init(metadata: metadata, projectId: projectId, isController: isController, relayHost: relayHost, logger: ConsoleLogger(loggingLevel: .off), keychain: KeychainStorage(uniqueIdentifier: clientName), keyValueStorage: keyValueStorage, clientName: clientName)
}
@@ -61,9 +61,9 @@ public final class WalletConnectClient {
self.secureStorage = SecureStorage(keychain: keychain)
let relayUrl = WakuNetworkRelay.makeRelayUrl(host: relayHost, projectId: projectId)
self.wakuRelay = WakuNetworkRelay(logger: logger, url: relayUrl, keyValueStorage: keyValueStorage, uniqueIdentifier: clientName ?? "")
- let serialiser = JSONRPCSerialiser(crypto: crypto)
+ let serializer = JSONRPCSerializer(crypto: crypto)
self.history = JsonRpcHistory(logger: logger, keyValueStore: KeyValueStore(defaults: keyValueStorage, identifier: StorageDomainIdentifiers.jsonRpcHistory(clientName: clientName ?? "_")))
- self.relay = WalletConnectRelay(networkRelayer: wakuRelay, jsonRpcSerialiser: serialiser, logger: logger, jsonRpcHistory: history)
+ self.relay = WalletConnectRelay(networkRelayer: wakuRelay, jsonRpcSerializer: serializer, logger: logger, jsonRpcHistory: history)
let pairingSequencesStore = PairingStorage(storage: SequenceStore(storage: keyValueStorage, identifier: StorageDomainIdentifiers.pairings(clientName: clientName ?? "_")))
let sessionSequencesStore = SessionStorage(storage: SequenceStore(storage: keyValueStorage, identifier: StorageDomainIdentifiers.sessions(clientName: clientName ?? "_")))
self.pairingEngine = PairingEngine(relay: relay, crypto: crypto, subscriber: WCSubscriber(relay: relay, logger: logger), sequencesStore: pairingSequencesStore, isController: isController, metadata: metadata, logger: logger)
@@ -76,7 +76,7 @@ public final class WalletConnectClient {
func registerBackgroundTask() {
#if os(iOS)
- self.backgroundTaskID = UIApplication.shared.beginBackgroundTask (withName: "Finish Network Tasks") { [weak self] in
+ backgroundTaskID = UIApplication.shared.beginBackgroundTask (withName: "Finish Network Tasks") { [weak self] in
self?.endBackgroundTask()
}
#endif
@@ -157,30 +157,33 @@ public final class WalletConnectClient {
/// - topic: Topic of the session that is intended to be updated.
/// - accounts: Set of accounts that will be allowed to be used by the session after the update.
public func update(topic: String, accounts: Set) {
- sessionEngine.update(topic: topic, accounts: accounts)
+ do {
+ try sessionEngine.update(topic: topic, accounts: accounts)
+ } catch {
+ print("Error on session update call: \(error)")
+ }
}
/// For the responder to upgrade session permissions
/// - Parameters:
/// - topic: Topic of the session that is intended to be upgraded.
/// - permissions: Sets of permissions that will be combined with existing ones.
- public func upgrade(topic: String, permissions: Session.Permissions) {
- sessionEngine.upgrade(topic: topic, permissions: permissions)
+ public func upgrade(topic: String, permissions: Session.Permissions) throws {
+ try sessionEngine.upgrade(topic: topic, permissions: permissions)
}
/// For the proposer to send JSON-RPC requests to responding peer.
/// - Parameters:
/// - params: Parameters defining request and related session
- /// - completion: completion block will provide response from responding client
- public func request(params: Request, completion: @escaping (Result, JSONRPCErrorResponse>) -> ()) {
- sessionEngine.request(params: params, completion: completion)
+ public func request(params: Request) {
+ sessionEngine.request(params: params)
}
/// For the responder to respond on pending peer's session JSON-RPC Request
/// - Parameters:
/// - topic: Topic of the session for which the request was received.
/// - response: Your JSON RPC response or an error.
- public func respond(topic: String, response: JsonRpcResponseTypes) {
+ public func respond(topic: String, response: JsonRpcResult) {
sessionEngine.respondSessionPayload(topic: topic, response: response)
}
@@ -244,15 +247,31 @@ public final class WalletConnectClient {
pairingEngine.getSettledPairings()
}
- public func getPendingRequests() -> [Request] {
- history.getPending()
+ /// - Returns: Pending requests received with wc_sessionPayload
+ /// - Parameter topic: topic representing session for which you want to get pending requests. If nil, you will receive pending requests for all active sessions.
+ public func getPendingRequests(topic: String? = nil) -> [Request] {
+ let pendingRequests: [Request] = history.getPending()
.filter{$0.request.method == .sessionPayload}
.compactMap {
guard case let .sessionPayload(payloadRequest) = $0.request.params else {return nil}
return Request(id: $0.id, topic: $0.topic, method: payloadRequest.request.method, params: payloadRequest.request.params, chainId: payloadRequest.chainId)
}
+ if let topic = topic {
+ return pendingRequests.filter{$0.topic == topic}
+ } else {
+ return pendingRequests
+ }
}
+ /// - Parameter id: id of a wc_sessionPayload jsonrpc request
+ /// - Returns: json rpc record object for given id or nil if record for give id does not exits
+ public func getSessionRequestRecord(id: Int64) -> WalletConnectUtils.JsonRpcRecord? {
+ guard let record = history.get(id: id),
+ case .sessionPayload(let payload) = record.request.params else {return nil}
+ let request = WalletConnectUtils.JsonRpcRecord.Request(method: payload.request.method, params: payload.request.params)
+ return WalletConnectUtils.JsonRpcRecord(id: record.id, topic: record.topic, request: request, response: record.response, chainId: record.chainId)
+ }
+
// MARK: - Private
private func setUpEnginesCallbacks() {
@@ -266,10 +285,11 @@ public final class WalletConnectClient {
pairingEngine.onApprovalAcknowledgement = { [weak self] settledPairing in
self?.delegate?.didSettle(pairing: settledPairing)
}
+ pairingEngine.onPairingUpdate = { [unowned self] topic, appMetadata in
+ delegate?.didUpdate(pairingTopic: topic, appMetadata: appMetadata)
+ }
sessionEngine.onSessionApproved = { [unowned self] settledSession in
- let permissions = Session.Permissions.init(blockchains: settledSession.permissions.blockchains, methods: settledSession.permissions.methods)
- let session = Session(topic: settledSession.topic, peer: settledSession.peer, permissions: permissions)
- delegate?.didSettle(session: session)
+ delegate?.didSettle(session: settledSession)
}
sessionEngine.onApprovalAcknowledgement = { [weak self] session in
self?.delegate?.didSettle(session: session)
@@ -293,8 +313,8 @@ public final class WalletConnectClient {
sessionEngine.onNotificationReceived = { [unowned self] topic, notification in
delegate?.didReceive(notification: notification, sessionTopic: topic)
}
- pairingEngine.onPairingUpdate = { [unowned self] topic, appMetadata in
- delegate?.didUpdate(pairingTopic: topic, appMetadata: appMetadata)
+ sessionEngine.onSessionPayloadResponse = { [unowned self] response in
+ delegate?.didReceive(sessionResponse: response)
}
}
diff --git a/Sources/WalletConnect/WalletConnectClientDelegate.swift b/Sources/WalletConnect/WalletConnectClientDelegate.swift
index 372b3067a..a9df37c0a 100644
--- a/Sources/WalletConnect/WalletConnectClientDelegate.swift
+++ b/Sources/WalletConnect/WalletConnectClientDelegate.swift
@@ -9,13 +9,20 @@ public protocol WalletConnectClientDelegate: AnyObject {
/// Function is executed on responder client only
func didReceive(sessionProposal: Session.Proposal)
- /// Tells the delegate that session request has been received
+ /// Tells the delegate that session payload request has been received
///
/// In most cases that function is supposed to be called on wallet client.
/// - Parameters:
/// - sessionRequest: Object containing request received from peer client.
func didReceive(sessionRequest: Request)
+ /// Tells the delegate that session payload response has been received
+ ///
+ /// In most cases that function is supposed to be called on dApp client.
+ /// - Parameters:
+ /// - sessionResponse: Object containing response received from peer client.
+ func didReceive(sessionResponse: Response)
+
/// Tells the delegate that the peer client has terminated the session.
///
/// Function can be executed on any type of the client.
@@ -26,7 +33,7 @@ public protocol WalletConnectClientDelegate: AnyObject {
/// Function is executed on controller and non-controller client when both communicating peers have successfully upgraded permissions.
func didUpgrade(sessionTopic: String, permissions: Session.Permissions)
- /// Tells the delegate that extra eccounts has been included in session sequence
+ /// Tells the delegate that extra accounts has been included in session sequence
///
/// Function is executed on controller and non-controller client when both communicating peers have successfully included new accounts requested by the controller client.
func didUpdate(sessionTopic: String, accounts: Set)
@@ -41,7 +48,7 @@ public protocol WalletConnectClientDelegate: AnyObject {
/// Function is executed on proposer and responder client when both communicating peers have successfully established a pairing.
func didSettle(pairing: Pairing)
- /// Tells the delegate that sotification has been received.
+ /// Tells the delegate that notification has been received.
func didReceive(notification: Session.Notification, sessionTopic : String)
/// Tells the delegate that peer client has rejected a session proposal.
@@ -60,4 +67,7 @@ public extension WalletConnectClientDelegate {
func didReceive(notification: Session.Notification, sessionTopic: String) {}
func didReject(pendingSessionTopic: String, reason: Reason) {}
func didUpdate(pairingTopic: String, appMetadata: AppMetadata) {}
+ func didReceive(sessionRequest: Request) {}
+ func didReceive(sessionProposal: Session.Proposal) {}
+ func didReceive(sessionResponse: Response) {}
}
diff --git a/Sources/WalletConnect/WalletConnectError.swift b/Sources/WalletConnect/WalletConnectError.swift
index a05eb5a06..67ce2bd7a 100644
--- a/Sources/WalletConnect/WalletConnectError.swift
+++ b/Sources/WalletConnect/WalletConnectError.swift
@@ -2,19 +2,18 @@
import Foundation
+// TODO: Migrate protocol errors to ReasonCode enum over time. Use WalletConnectError for client errors only.
enum WalletConnectError: Error {
- // 1000 (Internal)
+ case noSessionMatchingTopic(String)
+ case sessionNotSettled(String)
+ case invalidPermissions
+ case unauthorizedNonControllerCall
+
case `internal`(_ reason: InternalReason)
- // 2000 (Timeout)
- // 3000 (Unauthorized)
case unauthrorized(_ reason: UnauthorizedReason)
- // 4000 (EIP-1193)
- // 5000 (CAIP-25)
- // 9000 (Unknown)
-
enum InternalReason: Error {
case notApproved
case malformedPairingURI
@@ -50,11 +49,21 @@ extension WalletConnectError: CustomStringConvertible {
return reason.code
case .unauthrorized(let reason):
return reason.code
+ default:
+ return 0
}
}
var localizedDescription: String {
switch self {
+ case .noSessionMatchingTopic(let topic):
+ return "No session found matching topic \(topic)."
+ case .sessionNotSettled(let topic):
+ return "Session is not settled on topic \(topic)."
+ case .invalidPermissions:
+ return "Permission set is invalid."
+ case .unauthorizedNonControllerCall:
+ return "Method must be called by a controller client."
case .internal(let reason):
return reason.description
case .unauthrorized(let reason):
diff --git a/Sources/WalletConnectUtils/AnyCodable.swift b/Sources/WalletConnectUtils/AnyCodable.swift
index 8d0436d6a..98ec034cf 100644
--- a/Sources/WalletConnectUtils/AnyCodable.swift
+++ b/Sources/WalletConnectUtils/AnyCodable.swift
@@ -75,10 +75,10 @@ extension AnyCodable: Decodable, Encodable {
} else if let stringVal = try? container.decode(String.self) {
value = stringVal
} else {
- throw DecodingError.dataCorruptedError(in: container, debugDescription: "the container contains nothing serialisable")
+ throw DecodingError.dataCorruptedError(in: container, debugDescription: "the container contains nothing serializable")
}
} else {
- throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not serialise"))
+ throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not serialize"))
}
}
diff --git a/Sources/WalletConnectUtils/JSONRPC/JsonRpcResponseTypes.swift b/Sources/WalletConnectUtils/JSONRPC/JsonRpcResult.swift
similarity index 91%
rename from Sources/WalletConnectUtils/JSONRPC/JsonRpcResponseTypes.swift
rename to Sources/WalletConnectUtils/JSONRPC/JsonRpcResult.swift
index 1ef0fb00d..f7fee74f8 100644
--- a/Sources/WalletConnectUtils/JSONRPC/JsonRpcResponseTypes.swift
+++ b/Sources/WalletConnectUtils/JSONRPC/JsonRpcResult.swift
@@ -2,7 +2,7 @@
import Foundation
-public enum JsonRpcResponseTypes: Codable {
+public enum JsonRpcResult: Codable {
case error(JSONRPCErrorResponse)
case response(JSONRPCResponse)
public var id: Int64 {
diff --git a/Sources/WalletConnectUtils/JsonRpcHistory.swift b/Sources/WalletConnectUtils/JsonRpcHistory.swift
index bca7270a0..8d2f27b58 100644
--- a/Sources/WalletConnectUtils/JsonRpcHistory.swift
+++ b/Sources/WalletConnectUtils/JsonRpcHistory.swift
@@ -35,7 +35,7 @@ public class JsonRpcHistory where T: Codable&Equatable {
}
}
- public func resolve(response: JsonRpcResponseTypes) throws -> JsonRpcRecord {
+ public func resolve(response: JsonRpcResult) throws -> JsonRpcRecord {
logger.debug("Resolving JSON-RPC response - ID: \(response.id)")
guard var record = try? storage.get(key: "\(response.id)") else {
throw RecordingError.noJsonRpcRequestMatchingResponse
diff --git a/Sources/WalletConnectUtils/JsonRpcRecord.swift b/Sources/WalletConnectUtils/JsonRpcRecord.swift
index 225cca1ac..151f51651 100644
--- a/Sources/WalletConnectUtils/JsonRpcRecord.swift
+++ b/Sources/WalletConnectUtils/JsonRpcRecord.swift
@@ -5,12 +5,25 @@ public struct JsonRpcRecord: Codable {
public let id: Int64
public let topic: String
public let request: Request
- public var response: JsonRpcResponseTypes?
+ public var response: JsonRpcResult?
public let chainId: String?
+ public init(id: Int64, topic: String, request: JsonRpcRecord.Request, response: JsonRpcResult? = nil, chainId: String?) {
+ self.id = id
+ self.topic = topic
+ self.request = request
+ self.response = response
+ self.chainId = chainId
+ }
+
public struct Request: Codable {
public let method: String
public let params: AnyCodable
+
+ public init(method: String, params: AnyCodable) {
+ self.method = method
+ self.params = params
+ }
}
}
diff --git a/Tests/IntegrationTests/ClientDelegate.swift b/Tests/IntegrationTests/ClientDelegate.swift
index fa87b54cd..f5eacaeb0 100644
--- a/Tests/IntegrationTests/ClientDelegate.swift
+++ b/Tests/IntegrationTests/ClientDelegate.swift
@@ -8,6 +8,7 @@ class ClientDelegate: WalletConnectClientDelegate {
var onPairingSettled: ((Pairing)->())?
var onSessionProposal: ((Session.Proposal)->())?
var onSessionRequest: ((Request)->())?
+ var onSessionResponse: ((Response)->())?
var onSessionRejected: ((String, Reason)->())?
var onSessionDelete: (()->())?
var onSessionUpgrade: ((String, Session.Permissions)->())?
@@ -50,4 +51,7 @@ class ClientDelegate: WalletConnectClientDelegate {
func didUpdate(pairingTopic: String, appMetadata: AppMetadata) {
onPairingUpdate?(pairingTopic, appMetadata)
}
+ func didReceive(sessionResponse: Response) {
+ onSessionResponse?(sessionResponse)
+ }
}
diff --git a/Tests/IntegrationTests/ClientTest.swift b/Tests/IntegrationTests/ClientTest.swift
index cb56eff3c..ecf9a5a83 100644
--- a/Tests/IntegrationTests/ClientTest.swift
+++ b/Tests/IntegrationTests/ClientTest.swift
@@ -153,15 +153,16 @@ final class ClientTests: XCTestCase {
}
proposer.onSessionSettled = {[unowned self] settledSession in
let requestParams = Request(id: 0, topic: settledSession.topic, method: method, params: AnyCodable(params), chainId: nil)
- self.proposer.client.request(params: requestParams) { result in
- switch result {
- case .success(let jsonRpcResponse):
- let response = try! jsonRpcResponse.result.get(String.self)
- XCTAssertEqual(response, responseParams)
- responseExpectation.fulfill()
- case .failure(_):
- XCTFail()
- }
+ self.proposer.client.request(params: requestParams)
+ }
+ proposer.onSessionResponse = { response in
+ switch response.result {
+ case .response(let jsonRpcResponse):
+ let response = try! jsonRpcResponse.result.get(String.self)
+ XCTAssertEqual(response, responseParams)
+ responseExpectation.fulfill()
+ case .error(_):
+ XCTFail()
}
}
responder.onSessionRequest = {[unowned self] sessionRequest in
@@ -189,15 +190,17 @@ final class ClientTests: XCTestCase {
}
proposer.onSessionSettled = {[unowned self] settledSession in
let requestParams = Request(id: 0, topic: settledSession.topic, method: method, params: AnyCodable(params), chainId: nil)
- self.proposer.client.request(params: requestParams) { result in
- switch result {
- case .success(_):
- XCTFail()
- case .failure(let errorResponse):
- XCTAssertEqual(error, errorResponse.error)
- failureResponseExpectation.fulfill()
- }
+ self.proposer.client.request(params: requestParams)
+ }
+ proposer.onSessionResponse = { response in
+ switch response.result {
+ case .response(_):
+ XCTFail()
+ case .error(let errorResponse):
+ XCTAssertEqual(error, errorResponse.error)
+ failureResponseExpectation.fulfill()
}
+
}
responder.onSessionRequest = {[unowned self] sessionRequest in
let jsonrpcErrorResponse = JSONRPCErrorResponse(id: sessionRequest.id, error: error)
@@ -251,7 +254,7 @@ final class ClientTests: XCTestCase {
self.responder.client.approve(proposal: proposal, accounts: [account])
}
responder.onSessionSettled = { [unowned self] sessionSettled in
- responder.client.upgrade(topic: sessionSettled.topic, permissions: upgradePermissions)
+ try? responder.client.upgrade(topic: sessionSettled.topic, permissions: upgradePermissions)
}
proposer.onSessionUpgrade = { topic, permissions in
XCTAssertTrue(permissions.blockchains.isSuperset(of: upgradePermissions.blockchains))
@@ -266,31 +269,6 @@ final class ClientTests: XCTestCase {
waitForExpectations(timeout: defaultTimeout, handler: nil)
}
- func testSessionUpgradeFailsOnNonControllerRequest() {
- let proposerSessionUpgradeExpectation = expectation(description: "Proposer upgrades session")
- proposerSessionUpgradeExpectation.isInverted = true
- let responderSessionUpgradeExpectation = expectation(description: "Responder upgrades session")
- responderSessionUpgradeExpectation.isInverted = true
- let account = "0x022c0c42a80bd19EA4cF0F94c4F9F96645759716"
- let permissions = Session.Permissions.stub()
- let upgradePermissions = Session.Permissions(blockchains: ["eip155:42"], methods: ["eth_sendTransaction"])
- let uri = try! proposer.client.connect(sessionPermissions: permissions)!
- try! responder.client.pair(uri: uri)
- responder.onSessionProposal = { [unowned self] proposal in
- self.responder.client.approve(proposal: proposal, accounts: [account])
- }
- proposer.onSessionSettled = { [unowned self] sessionSettled in
- proposer.client.upgrade(topic: sessionSettled.topic, permissions: upgradePermissions)
- }
- proposer.onSessionUpgrade = { topic, permissions in
- proposerSessionUpgradeExpectation.fulfill()
- }
- responder.onSessionUpgrade = { topic, permissions in
- responderSessionUpgradeExpectation.fulfill()
- }
- waitForExpectations(timeout: 3.0, handler: nil)
- }
-
func testSuccessfulSessionUpdate() {
let proposerSessionUpdateExpectation = expectation(description: "Proposer updates session on responder request")
let responderSessionUpdateExpectation = expectation(description: "Responder updates session on proposer response")
diff --git a/Tests/WalletConnectTests/Helpers/Error+Extension.swift b/Tests/WalletConnectTests/Helpers/Error+Extension.swift
index d21783353..25845a8cb 100644
--- a/Tests/WalletConnectTests/Helpers/Error+Extension.swift
+++ b/Tests/WalletConnectTests/Helpers/Error+Extension.swift
@@ -7,3 +7,30 @@ extension NSError {
NSError(domain: "com.walletconnect.sdk.tests.error", code: code, userInfo: nil)
}
}
+
+extension Error {
+
+ var wcError: WalletConnectError? {
+ self as? WalletConnectError
+ }
+
+ var isNoSessionMatchingTopicError: Bool {
+ guard case .noSessionMatchingTopic = wcError else { return false }
+ return true
+ }
+
+ var isSessionNotSettledError: Bool {
+ guard case .sessionNotSettled = wcError else { return false }
+ return true
+ }
+
+ var isInvalidPermissionsError: Bool {
+ guard case .invalidPermissions = wcError else { return false }
+ return true
+ }
+
+ var isUnauthorizedNonControllerCallError: Bool {
+ guard case .unauthorizedNonControllerCall = wcError else { return false }
+ return true
+ }
+}
diff --git a/Tests/WalletConnectTests/Helpers/WCRequest+Extension.swift b/Tests/WalletConnectTests/Helpers/WCRequest+Extension.swift
new file mode 100644
index 000000000..f68c09faf
--- /dev/null
+++ b/Tests/WalletConnectTests/Helpers/WCRequest+Extension.swift
@@ -0,0 +1,19 @@
+@testable import WalletConnect
+
+extension WCRequest {
+
+ var pairingApproveParams: PairingType.ApprovalParams? {
+ guard case .pairingApprove(let approveParams) = self.params else { return nil }
+ return approveParams
+ }
+
+ var sessionProposal: SessionProposal? {
+ guard case .pairingPayload(let payload) = self.params else { return nil }
+ return payload.request.params
+ }
+
+ var approveParams: SessionType.ApproveParams? {
+ guard case .sessionApprove(let approveParams) = self.params else { return nil }
+ return approveParams
+ }
+}
diff --git a/Tests/WalletConnectTests/JSONRPCSerialiserTests.swift b/Tests/WalletConnectTests/JSONRPCSerialiserTests.swift
index 2e4740752..f2d4f212b 100644
--- a/Tests/WalletConnectTests/JSONRPCSerialiserTests.swift
+++ b/Tests/WalletConnectTests/JSONRPCSerialiserTests.swift
@@ -5,33 +5,33 @@ import Foundation
import XCTest
@testable import WalletConnect
-final class JSONRPCSerialiserTests: XCTestCase {
- var serialiser: JSONRPCSerialiser!
+final class JSONRPCSerializerTests: XCTestCase {
+ var serializer: JSONRPCSerializer!
var codec: MockedCodec!
override func setUp() {
codec = MockedCodec()
- self.serialiser = JSONRPCSerialiser(crypto: Crypto(keychain: KeychainStorageMock()), codec: codec)
+ self.serializer = JSONRPCSerializer(crypto: Crypto(keychain: KeychainStorageMock()), codec: codec)
}
override func tearDown() {
- serialiser = nil
+ serializer = nil
}
- func testSerialise() {
- codec.encryptionPayload = EncryptionPayload(iv: SerialiserTestData.iv,
- publicKey: SerialiserTestData.publicKey,
- mac: SerialiserTestData.mac,
- cipherText: SerialiserTestData.cipherText)
- let serialisedMessage = try! serialiser.encrypt(json: SerialiserTestData.pairingApproveJSON, agreementKeys: SerialiserTestData.emptyAgreementSecret)
- let serialisedMessageSample = SerialiserTestData.serialisedMessage
- XCTAssertEqual(serialisedMessage, serialisedMessageSample)
+ func testSerialize() {
+ codec.encryptionPayload = EncryptionPayload(iv: SerializerTestData.iv,
+ publicKey: SerializerTestData.publicKey,
+ mac: SerializerTestData.mac,
+ cipherText: SerializerTestData.cipherText)
+ let serializedMessage = try! serializer.encrypt(json: SerializerTestData.pairingApproveJSON, agreementKeys: SerializerTestData.emptyAgreementSecret)
+ let serializedMessageSample = SerializerTestData.serializedMessage
+ XCTAssertEqual(serializedMessage, serializedMessageSample)
}
- func testDeserialise() {
- let serialisedMessageSample = SerialiserTestData.serialisedMessage
- codec.decodedJson = SerialiserTestData.pairingApproveJSON
- let deserialisedJSONRPC: WCRequest = try! serialiser.deserialise(message: serialisedMessageSample, symmetricKey: Data(hex: ""))
- XCTAssertEqual(deserialisedJSONRPC.params, SerialiserTestData.pairingApproveJSONRPCRequest.params)
+ func testDeserialize() {
+ let serializedMessageSample = SerializerTestData.serializedMessage
+ codec.decodedJson = SerializerTestData.pairingApproveJSON
+ let deserializedJSONRPC: WCRequest = try! serializer.deserialize(message: serializedMessageSample, symmetricKey: Data(hex: ""))
+ XCTAssertEqual(deserializedJSONRPC.params, SerializerTestData.pairingApproveJSONRPCRequest.params)
}
}
diff --git a/Tests/WalletConnectTests/JsonRpcHistoryTests.swift b/Tests/WalletConnectTests/JsonRpcHistoryTests.swift
index c807c1b46..34895bafb 100644
--- a/Tests/WalletConnectTests/JsonRpcHistoryTests.swift
+++ b/Tests/WalletConnectTests/JsonRpcHistoryTests.swift
@@ -36,7 +36,7 @@ final class JsonRpcHistoryTests: XCTestCase {
try! sut.set(topic: recordinput.topic, request: recordinput.request)
XCTAssertNil(sut.get(id: recordinput.request.id)?.response)
let jsonRpcResponse = JSONRPCResponse(id: recordinput.request.id, result: AnyCodable(""))
- let response = JsonRpcResponseTypes.response(jsonRpcResponse)
+ let response = JsonRpcResult.response(jsonRpcResponse)
_ = try! sut.resolve(response: response)
XCTAssertNotNil(sut.get(id: jsonRpcResponse.id)?.response)
}
@@ -45,7 +45,7 @@ final class JsonRpcHistoryTests: XCTestCase {
let recordinput = getTestJsonRpcRecordInput()
try! sut.set(topic: recordinput.topic, request: recordinput.request)
let jsonRpcResponse = JSONRPCResponse(id: recordinput.request.id, result: AnyCodable(""))
- let response = JsonRpcResponseTypes.response(jsonRpcResponse)
+ let response = JsonRpcResult.response(jsonRpcResponse)
_ = try! sut.resolve(response: response)
XCTAssertThrowsError(try sut.resolve(response: response))
}
@@ -71,7 +71,7 @@ final class JsonRpcHistoryTests: XCTestCase {
try! sut.set(topic: recordinput2.topic, request: recordinput2.request)
XCTAssertEqual(sut.getPending().count, 2)
let jsonRpcResponse = JSONRPCResponse(id: recordinput1.request.id, result: AnyCodable(""))
- let response = JsonRpcResponseTypes.response(jsonRpcResponse)
+ let response = JsonRpcResult.response(jsonRpcResponse)
_ = try! sut.resolve(response: response)
XCTAssertEqual(sut.getPending().count, 1)
}
diff --git a/Tests/WalletConnectTests/Mocks/MockedJSONRPCSerialiser.swift b/Tests/WalletConnectTests/Mocks/MockedJSONRPCSerialiser.swift
deleted file mode 100644
index 8e7a25968..000000000
--- a/Tests/WalletConnectTests/Mocks/MockedJSONRPCSerialiser.swift
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-
-import Foundation
-import WalletConnectUtils
-@testable import WalletConnect
-
-class MockedJSONRPCSerialiser: JSONRPCSerialising {
-
- var codec: Codec
- var deserialised: Any!
- var serialised: String!
-
- init(codec: Codec = MockedCodec()) {
- self.codec = codec
- }
-
- func serialise(topic: String, encodable: Encodable) throws -> String {
- try serialise(json: try encodable.json(), agreementKeys: AgreementSecret(sharedSecret: Data(), publicKey: AgreementPrivateKey().publicKey))
- }
- func tryDeserialise(topic: String, message: String) -> T? {
- try? deserialise(message: message, symmetricKey: Data())
- }
- func deserialiseJsonRpc(topic: String, message: String) throws -> Result, JSONRPCErrorResponse> {
- .success(try deserialise(message: message, symmetricKey: Data()))
- }
-
- func deserialise(message: String, symmetricKey: Data) throws -> T where T : Codable {
- if let deserialisedModel = deserialised as? T {
- return deserialisedModel
- } else {
- throw NSError.mock()
- }
- }
-
- func serialise(json: String, agreementKeys: AgreementSecret) throws -> String {
- return serialised
- }
-
-}
diff --git a/Tests/WalletConnectTests/Mocks/MockedJSONRPCSerializer.swift b/Tests/WalletConnectTests/Mocks/MockedJSONRPCSerializer.swift
new file mode 100644
index 000000000..fbc8c9da7
--- /dev/null
+++ b/Tests/WalletConnectTests/Mocks/MockedJSONRPCSerializer.swift
@@ -0,0 +1,39 @@
+//
+
+import Foundation
+import WalletConnectUtils
+@testable import WalletConnect
+
+class MockedJSONRPCSerializer: JSONRPCSerializing {
+
+ var codec: Codec
+ var deserialized: Any!
+ var serialized: String!
+
+ init(codec: Codec = MockedCodec()) {
+ self.codec = codec
+ }
+
+ func serialize(topic: String, encodable: Encodable) throws -> String {
+ try serialize(json: try encodable.json(), agreementKeys: AgreementSecret(sharedSecret: Data(), publicKey: AgreementPrivateKey().publicKey))
+ }
+ func tryDeserialize(topic: String, message: String) -> T? {
+ try? deserialize(message: message, symmetricKey: Data())
+ }
+ func deserializeJsonRpc(topic: String, message: String) throws -> Result, JSONRPCErrorResponse> {
+ .success(try deserialize(message: message, symmetricKey: Data()))
+ }
+
+ func deserialize(message: String, symmetricKey: Data) throws -> T where T : Codable {
+ if let deserializedModel = deserialized as? T {
+ return deserializedModel
+ } else {
+ throw NSError.mock()
+ }
+ }
+
+ func serialize(json: String, agreementKeys: AgreementSecret) throws -> String {
+ return serialized
+ }
+
+}
diff --git a/Tests/WalletConnectTests/Mocks/MockedRelay.swift b/Tests/WalletConnectTests/Mocks/MockedRelay.swift
index 171f51770..ff3fdf2bd 100644
--- a/Tests/WalletConnectTests/Mocks/MockedRelay.swift
+++ b/Tests/WalletConnectTests/Mocks/MockedRelay.swift
@@ -20,24 +20,36 @@ class MockedWCRelay: WalletConnectRelaying {
var wcRequestPublisher: AnyPublisher {
wcRequestPublisherSubject.eraseToAnyPublisher()
}
+ var didCallRequest = false
var didCallSubscribe = false
var didCallUnsubscribe = false
+ var didRespondSuccess = false
+ var lastErrorCode = -1
var error: Error? = nil
private(set) var requests: [(topic: String, request: WCRequest)] = []
-
+
func request(_ wcMethod: WCMethod, onTopic topic: String, completion: ((Result, JSONRPCErrorResponse>) -> ())?) {
request(topic: topic, payload: wcMethod.asRequest(), completion: completion)
}
func request(topic: String, payload: WCRequest, completion: ((Result, JSONRPCErrorResponse>) -> ())?) {
+ didCallRequest = true
requests.append((topic, payload))
}
- func respond(topic: String, response: JsonRpcResponseTypes, completion: @escaping ((Error?) -> ())) {
+ func respond(topic: String, response: JsonRpcResult, completion: @escaping ((Error?) -> ())) {
completion(error)
}
+ func respondSuccess(for payload: WCRequestSubscriptionPayload) {
+ didRespondSuccess = true
+ }
+
+ func respondError(for payload: WCRequestSubscriptionPayload, reason: ReasonCode) {
+ lastErrorCode = reason.code
+ }
+
func subscribe(topic: String) {
didCallSubscribe = true
}
@@ -48,7 +60,7 @@ class MockedWCRelay: WalletConnectRelaying {
func sendSubscriptionPayloadOn(topic: String) {
let payload = WCRequestSubscriptionPayload(topic: topic,
- wcRequest: SerialiserTestData.pairingApproveJSONRPCRequest)
+ wcRequest: SerializerTestData.pairingApproveJSONRPCRequest)
wcRequestPublisherSubject.send(payload)
}
}
diff --git a/Tests/WalletConnectTests/Mocks/SessionSequenceStorageMock.swift b/Tests/WalletConnectTests/Mocks/SessionSequenceStorageMock.swift
index 64852e30d..a799ace1d 100644
--- a/Tests/WalletConnectTests/Mocks/SessionSequenceStorageMock.swift
+++ b/Tests/WalletConnectTests/Mocks/SessionSequenceStorageMock.swift
@@ -1,4 +1,5 @@
@testable import WalletConnect
+import Foundation
final class SessionSequenceStorageMock: SessionSequenceStorage {
@@ -14,8 +15,8 @@ final class SessionSequenceStorageMock: SessionSequenceStorage {
sessions[sequence.topic] = sequence
}
- func getSequence(forTopic topic: String) throws -> SessionSequence? {
- sessions[topic]
+ func getSequence(forTopic topic: String) -> SessionSequence? {
+ return sessions[topic]
}
func getAll() -> [SessionSequence] {
diff --git a/Tests/WalletConnectTests/PairingEngineTests.swift b/Tests/WalletConnectTests/PairingEngineTests.swift
index 2796adcd0..6f0369b2f 100644
--- a/Tests/WalletConnectTests/PairingEngineTests.swift
+++ b/Tests/WalletConnectTests/PairingEngineTests.swift
@@ -3,24 +3,6 @@ import XCTest
import TestingUtils
import WalletConnectUtils
-fileprivate extension SessionPermissions {
- static func stub() -> SessionPermissions {
- SessionPermissions(
- blockchain: Blockchain(chains: []),
- jsonrpc: JSONRPC(methods: []),
- notifications: Notifications(types: [])
- )
- }
-}
-
-fileprivate extension WCRequest {
-
- var approveParams: PairingType.ApprovalParams? {
- guard case .pairingApprove(let approveParams) = self.params else { return nil }
- return approveParams
- }
-}
-
func deriveTopic(publicKey: String, privateKey: AgreementPrivateKey) -> String {
try! Crypto.generateAgreementSecret(from: privateKey, peerPublicKey: publicKey).derivedTopic()
}
@@ -88,7 +70,7 @@ final class PairingEngineTests: XCTestCase {
try engine.approve(uri)
// The concept of "publish" should only be known by the relayer
- guard let publishTopic = relayMock.requests.first?.topic, let approval = relayMock.requests.first?.request.approveParams else {
+ guard let publishTopic = relayMock.requests.first?.topic, let approval = relayMock.requests.first?.request.pairingApproveParams else {
XCTFail("Responder must publish an approval request."); return
}
@@ -124,7 +106,7 @@ final class PairingEngineTests: XCTestCase {
try engine.approve(uri)
let success = JSONRPCResponse(id: 0, result: AnyCodable(true))
- let response = WCResponse(topic: topicA, requestMethod: .pairingApprove, requestParams: .pairingApprove(PairingType.ApprovalParams(relay: RelayProtocolOptions(protocol: "", params: nil), responder: PairingParticipant(publicKey: ""), expiry: 0, state: nil)), result: .success(success))
+ let response = WCResponse(topic: topicA, chainId: nil, requestMethod: .pairingApprove, requestParams: .pairingApprove(PairingType.ApprovalParams(relay: RelayProtocolOptions(protocol: "", params: nil), responder: PairingParticipant(publicKey: ""), expiry: 0, state: nil)), result: .response(success))
relayMock.onPairingResponse?(response)
XCTAssert(storageMock.hasAcknowledgedPairing(on: topicB), "Settled pairing must advance to acknowledged state.")
diff --git a/Tests/WalletConnectTests/SessionEngineTests.swift b/Tests/WalletConnectTests/SessionEngineTests.swift
index 5dd35b8b0..9c480ad1a 100644
--- a/Tests/WalletConnectTests/SessionEngineTests.swift
+++ b/Tests/WalletConnectTests/SessionEngineTests.swift
@@ -3,37 +3,6 @@ import WalletConnectUtils
import TestingUtils
@testable import WalletConnect
-// TODO: Move common helper methods to a shared folder
-fileprivate extension Pairing {
-
- static func stub() -> Pairing {
- Pairing(topic: String.generateTopic()!, peer: nil)
- }
-}
-
-fileprivate extension SessionPermissions {
- static func stub() -> SessionPermissions {
- SessionPermissions(
- blockchain: Blockchain(chains: []),
- jsonrpc: JSONRPC(methods: []),
- notifications: Notifications(types: [])
- )
- }
-}
-
-fileprivate extension WCRequest {
-
- var sessionProposal: SessionProposal? {
- guard case .pairingPayload(let payload) = self.params else { return nil }
- return payload.request.params
- }
-
- var approveParams: SessionType.ApproveParams? {
- guard case .sessionApprove(let approveParams) = self.params else { return nil }
- return approveParams
- }
-}
-
final class SessionEngineTests: XCTestCase {
var engine: SessionEngine!
@@ -54,9 +23,20 @@ final class SessionEngineTests: XCTestCase {
storageMock = SessionSequenceStorageMock()
cryptoMock = CryptoStorageProtocolMock()
topicGenerator = TopicGenerator()
-
+ }
+
+ override func tearDown() {
+ relayMock = nil
+ subscriberMock = nil
+ storageMock = nil
+ cryptoMock = nil
+ topicGenerator = nil
+ engine = nil
+ }
+
+ func setupEngine(isController: Bool) {
metadata = AppMetadata(name: nil, description: nil, url: nil, icons: nil)
- isController = false
+ self.isController = isController
let logger = ConsoleLoggerMock()
engine = SessionEngine(
relay: relayMock,
@@ -68,17 +48,10 @@ final class SessionEngineTests: XCTestCase {
logger: logger,
topicGenerator: topicGenerator.getTopic)
}
-
- override func tearDown() {
- relayMock = nil
- subscriberMock = nil
- storageMock = nil
- cryptoMock = nil
- topicGenerator = nil
- engine = nil
- }
func testPropose() {
+ setupEngine(isController: false)
+
let pairing = Pairing.stub()
let topicB = pairing.topic
@@ -104,6 +77,7 @@ final class SessionEngineTests: XCTestCase {
}
func testProposeResponseFailure() {
+ setupEngine(isController: false)
let pairing = Pairing.stub()
let topicB = pairing.topic
@@ -121,9 +95,10 @@ final class SessionEngineTests: XCTestCase {
let error = JSONRPCErrorResponse(id: request.id, error: JSONRPCErrorResponse.Error(code: 0, message: ""))
let response = WCResponse(
topic: publishTopic,
+ chainId: nil,
requestMethod: request.method,
requestParams: request.params,
- result: .failure(error))
+ result: .error(error))
relayMock.onResponse?(response)
XCTAssert(subscriberMock.didUnsubscribe(to: topicC))
@@ -133,6 +108,7 @@ final class SessionEngineTests: XCTestCase {
}
func testApprove() {
+ setupEngine(isController: true)
let proposerPubKey = AgreementPrivateKey().publicKey.hexRepresentation
let topicB = String.generateTopic()!
let topicC = String.generateTopic()!
@@ -163,6 +139,8 @@ final class SessionEngineTests: XCTestCase {
}
func testApprovalAcknowledgementSuccess() {
+ setupEngine(isController: true)
+
let proposerPubKey = AgreementPrivateKey().publicKey.hexRepresentation
let topicB = String.generateTopic()!
let topicC = String.generateTopic()!
@@ -188,9 +166,10 @@ final class SessionEngineTests: XCTestCase {
let success = JSONRPCResponse(id: request.id, result: AnyCodable(true))
let response = WCResponse(
topic: publishTopic,
+ chainId: nil,
requestMethod: request.method,
requestParams: request.params,
- result: .success(success))
+ result: .response(success))
relayMock.onResponse?(response)
XCTAssertFalse(cryptoMock.hasAgreementSecret(for: topicC))
@@ -199,6 +178,8 @@ final class SessionEngineTests: XCTestCase {
}
func testApprovalAcknowledgementFailure() {
+ setupEngine(isController: true)
+
let proposerPubKey = AgreementPrivateKey().publicKey.hexRepresentation
let selfPubKey = cryptoMock.privateKeyStub.publicKey.hexRepresentation
let topicB = String.generateTopic()!
@@ -225,9 +206,10 @@ final class SessionEngineTests: XCTestCase {
let error = JSONRPCErrorResponse(id: request.id, error: JSONRPCErrorResponse.Error(code: 0, message: ""))
let response = WCResponse(
topic: publishTopic,
+ chainId: nil,
requestMethod: request.method,
requestParams: request.params,
- result: .failure(error))
+ result: .error(error))
relayMock.onResponse?(response)
XCTAssertFalse(cryptoMock.hasPrivateKey(for: selfPubKey))
@@ -241,6 +223,7 @@ final class SessionEngineTests: XCTestCase {
}
func testReceiveApprovalResponse() {
+ setupEngine(isController: false)
var approvedSession: Session?
@@ -278,4 +261,209 @@ final class SessionEngineTests: XCTestCase {
XCTAssertNotNil(approvedSession)
XCTAssertEqual(approvedSession?.topic, topicD)
}
+
+ // MARK: - Update call tests
+
+ func testUpdateSuccess() throws {
+ setupEngine(isController: true)
+ let session = SessionSequence.stubSettled()
+ storageMock.setSequence(session)
+ try engine.update(topic: session.topic, accounts: ["std:0:0"])
+ XCTAssertTrue(relayMock.didCallRequest)
+ }
+
+ func testUpdateErrorInvalidAccount() {
+ setupEngine(isController: true)
+ let session = SessionSequence.stubSettled()
+ storageMock.setSequence(session)
+ XCTAssertThrowsError(try engine.update(topic: session.topic, accounts: ["err"]))
+ }
+
+ func testUpdateErrorIfNonController() {
+ setupEngine(isController: false)
+ let session = SessionSequence.stubSettled()
+ storageMock.setSequence(session)
+ XCTAssertThrowsError(try engine.update(topic: session.topic, accounts: ["std:0:0"]), "Update must fail if called by a non-controller.")
+ }
+
+ func testUpdateErrorSessionNotFound() {
+ setupEngine(isController: true)
+ XCTAssertThrowsError(try engine.update(topic: "", accounts: ["std:0:0"]), "Update must fail if there is no session matching the target topic.")
+ }
+
+ func testUpdateErrorSessionNotSettled() {
+ setupEngine(isController: true)
+ let session = SessionSequence.stubPreSettled()
+ storageMock.setSequence(session)
+ XCTAssertThrowsError(try engine.update(topic: session.topic, accounts: ["std:0:0"]), "Update must fail if session is not on settled state.")
+ }
+
+ // MARK: - Update peer response tests
+
+ func testUpdatePeerSuccess() {
+ setupEngine(isController: false)
+ let session = SessionSequence.stubSettled(isPeerController: true)
+ storageMock.setSequence(session)
+ subscriberMock.onReceivePayload?(WCRequestSubscriptionPayload.stubUpdate(topic: session.topic))
+ XCTAssertTrue(relayMock.didRespondSuccess)
+ }
+
+ func testUpdatePeerErrorAccountInvalid() {
+ setupEngine(isController: false)
+ let session = SessionSequence.stubSettled(isPeerController: true)
+ storageMock.setSequence(session)
+ subscriberMock.onReceivePayload?(WCRequestSubscriptionPayload.stubUpdate(topic: session.topic, accounts: ["0"]))
+ XCTAssertFalse(relayMock.didRespondSuccess)
+ XCTAssertEqual(relayMock.lastErrorCode, 1003)
+ }
+
+ func testUpdatePeerErrorNoSession() {
+ setupEngine(isController: false)
+ subscriberMock.onReceivePayload?(WCRequestSubscriptionPayload.stubUpdate(topic: ""))
+ XCTAssertFalse(relayMock.didRespondSuccess)
+ XCTAssertEqual(relayMock.lastErrorCode, 1301)
+ }
+
+ func testUpdatePeerErrorSessionNotSettled() {
+ setupEngine(isController: false)
+ let session = SessionSequence.stubPreSettled(isPeerController: true) // Session is not fully settled
+ storageMock.setSequence(session)
+ subscriberMock.onReceivePayload?(WCRequestSubscriptionPayload.stubUpdate(topic: session.topic))
+ XCTAssertFalse(relayMock.didRespondSuccess)
+ XCTAssertEqual(relayMock.lastErrorCode, 3003)
+ }
+
+ func testUpdatePeerErrorUnauthorized() {
+ setupEngine(isController: false)
+ let session = SessionSequence.stubSettled() // Peer is not a controller
+ storageMock.setSequence(session)
+ subscriberMock.onReceivePayload?(WCRequestSubscriptionPayload.stubUpdate(topic: session.topic))
+ XCTAssertFalse(relayMock.didRespondSuccess)
+ XCTAssertEqual(relayMock.lastErrorCode, 3003)
+ }
+
+ func testUpdatePeerErrorMatchingController() {
+ setupEngine(isController: true) // Update request received by a controller
+ let session = SessionSequence.stubSettled(isPeerController: true)
+ storageMock.setSequence(session)
+ subscriberMock.onReceivePayload?(WCRequestSubscriptionPayload.stubUpdate(topic: session.topic))
+ XCTAssertFalse(relayMock.didRespondSuccess)
+ XCTAssertEqual(relayMock.lastErrorCode, 3005)
+ }
+
+ // TODO: Update acknowledgement tests
+
+ // MARK: - Upgrade call tests
+
+ func testUpgradeSuccess() throws {
+ setupEngine(isController: true)
+ let permissions = Session.Permissions.stub()
+ let session = SessionSequence.stubSettled()
+ storageMock.setSequence(session)
+ try engine.upgrade(topic: session.topic, permissions: permissions)
+ XCTAssertTrue(relayMock.didCallRequest)
+ // TODO: Check permissions on stored session
+ }
+
+ func testUpgradeErrorSessionNotFound() {
+ setupEngine(isController: true)
+ XCTAssertThrowsError(try engine.upgrade(topic: "", permissions: Session.Permissions.stub())) { error in
+ XCTAssertTrue(error.isNoSessionMatchingTopicError)
+ }
+ }
+
+ func testUpgradeErrorSessionNotSettled() {
+ setupEngine(isController: true)
+ let session = SessionSequence.stubPreSettled()
+ storageMock.setSequence(session)
+ XCTAssertThrowsError(try engine.upgrade(topic: session.topic, permissions: Session.Permissions.stub())) { error in
+ XCTAssertTrue(error.isSessionNotSettledError)
+ }
+ }
+
+ func testUpgradeErrorInvalidPermissions() {
+ setupEngine(isController: true)
+ let session = SessionSequence.stubSettled()
+ storageMock.setSequence(session)
+ XCTAssertThrowsError(try engine.upgrade(topic: session.topic, permissions: Session.Permissions.stub(chains: [""]))) { error in
+ XCTAssertTrue(error.isInvalidPermissionsError)
+ }
+ XCTAssertThrowsError(try engine.upgrade(topic: session.topic, permissions: Session.Permissions.stub(methods: [""]))) { error in
+ XCTAssertTrue(error.isInvalidPermissionsError)
+ }
+ XCTAssertThrowsError(try engine.upgrade(topic: session.topic, permissions: Session.Permissions.stub(notifications: [""]))) { error in
+ XCTAssertTrue(error.isInvalidPermissionsError)
+ }
+ }
+
+ func testUpgradeErrorCalledByNonController() {
+ setupEngine(isController: false)
+ let session = SessionSequence.stubSettled()
+ storageMock.setSequence(session)
+ XCTAssertThrowsError(try engine.upgrade(topic: session.topic, permissions: Session.Permissions.stub())) { error in
+ XCTAssertTrue(error.isUnauthorizedNonControllerCallError)
+ }
+ }
+
+ // MARK: - Upgrade peer response tests
+
+ func testUpgradePeerSuccess() {
+ setupEngine(isController: false)
+ var didCallbackUpgrade = false
+ let session = SessionSequence.stubSettled(isPeerController: true)
+ storageMock.setSequence(session)
+ engine.onSessionUpgrade = { topic, _ in
+ didCallbackUpgrade = true
+ XCTAssertEqual(topic, session.topic)
+ }
+ subscriberMock.onReceivePayload?(WCRequestSubscriptionPayload.stubUpgrade(topic: session.topic))
+ XCTAssertTrue(didCallbackUpgrade)
+ XCTAssertTrue(relayMock.didRespondSuccess)
+ }
+
+ func testUpgradePeerErrorInvalidPermissions() {
+ setupEngine(isController: false)
+ let invalidPermissions = SessionPermissions.stub(chains: [""])
+ let session = SessionSequence.stubSettled(isPeerController: true)
+ storageMock.setSequence(session)
+ subscriberMock.onReceivePayload?(WCRequestSubscriptionPayload.stubUpgrade(topic: session.topic, permissions: invalidPermissions))
+ XCTAssertFalse(relayMock.didRespondSuccess)
+ XCTAssertEqual(relayMock.lastErrorCode, 1004)
+ }
+
+ func testUpgradePeerErrorSessionNotFound() {
+ setupEngine(isController: false)
+ subscriberMock.onReceivePayload?(WCRequestSubscriptionPayload.stubUpgrade(topic: ""))
+ XCTAssertFalse(relayMock.didRespondSuccess)
+ XCTAssertEqual(relayMock.lastErrorCode, 1301)
+ }
+
+ func testUpgradePeerErrorSessionNotSettled() {
+ setupEngine(isController: false)
+ let session = SessionSequence.stubPreSettled(isPeerController: true) // Session is not fully settled
+ storageMock.setSequence(session)
+ subscriberMock.onReceivePayload?(WCRequestSubscriptionPayload.stubUpgrade(topic: session.topic))
+ XCTAssertFalse(relayMock.didRespondSuccess)
+ XCTAssertEqual(relayMock.lastErrorCode, 3004)
+ }
+
+ func testUpgradePeerErrorUnauthorized() {
+ setupEngine(isController: false)
+ let session = SessionSequence.stubSettled() // Peer is not a controller
+ storageMock.setSequence(session)
+ subscriberMock.onReceivePayload?(WCRequestSubscriptionPayload.stubUpgrade(topic: session.topic))
+ XCTAssertFalse(relayMock.didRespondSuccess)
+ XCTAssertEqual(relayMock.lastErrorCode, 3004)
+ }
+
+ func testUpgradePeerErrorMatchingController() {
+ setupEngine(isController: true) // Upgrade request received by a controller
+ let session = SessionSequence.stubSettled(isPeerController: true)
+ storageMock.setSequence(session)
+ subscriberMock.onReceivePayload?(WCRequestSubscriptionPayload.stubUpgrade(topic: session.topic))
+ XCTAssertFalse(relayMock.didRespondSuccess)
+ XCTAssertEqual(relayMock.lastErrorCode, 3005)
+ }
+
+ // TODO: Upgrade acknowledgement tests
}
diff --git a/Tests/WalletConnectTests/Mocks/AgreementSecret+Stub.swift b/Tests/WalletConnectTests/Stub/AgreementSecret+Stub.swift
similarity index 100%
rename from Tests/WalletConnectTests/Mocks/AgreementSecret+Stub.swift
rename to Tests/WalletConnectTests/Stub/AgreementSecret+Stub.swift
diff --git a/Tests/WalletConnectTests/Stub/Session+Stub.swift b/Tests/WalletConnectTests/Stub/Session+Stub.swift
new file mode 100644
index 000000000..cc67dacf8
--- /dev/null
+++ b/Tests/WalletConnectTests/Stub/Session+Stub.swift
@@ -0,0 +1,39 @@
+import Foundation
+@testable import WalletConnect
+
+extension SessionSequence {
+
+ static func stubPreSettled(isPeerController: Bool = false) -> SessionSequence {
+ let peerKey = AgreementPrivateKey().publicKey.hexRepresentation
+ let permissions = isPeerController ? SessionPermissions.stub(controllerKey: peerKey) : SessionPermissions.stub()
+ return SessionSequence(
+ topic: String.generateTopic()!,
+ relay: RelayProtocolOptions.stub(),
+ selfParticipant: Participant.stub(),
+ expiryDate: Date.distantFuture,
+ settledState: Settled(
+ peer: Participant.stub(publicKey: peerKey),
+ permissions: permissions,
+ state: SessionState(accounts: ["chainstd:1:1"]),
+ status: .preSettled
+ )
+ )
+ }
+
+ static func stubSettled(isPeerController: Bool = false) -> SessionSequence {
+ let peerKey = AgreementPrivateKey().publicKey.hexRepresentation
+ let permissions = isPeerController ? SessionPermissions.stub(controllerKey: peerKey) : SessionPermissions.stub()
+ return SessionSequence(
+ topic: String.generateTopic()!,
+ relay: RelayProtocolOptions.stub(),
+ selfParticipant: Participant.stub(),
+ expiryDate: Date.distantFuture,
+ settledState: Settled(
+ peer: Participant.stub(publicKey: peerKey),
+ permissions: permissions,
+ state: SessionState(accounts: ["chainstd:1:1"]),
+ status: .acknowledged
+ )
+ )
+ }
+}
diff --git a/Tests/WalletConnectTests/Stub/Stubs.swift b/Tests/WalletConnectTests/Stub/Stubs.swift
new file mode 100644
index 000000000..11b405f85
--- /dev/null
+++ b/Tests/WalletConnectTests/Stub/Stubs.swift
@@ -0,0 +1,72 @@
+@testable import WalletConnect
+
+extension AppMetadata {
+ static func stub() -> AppMetadata {
+ AppMetadata(
+ name: "Wallet Connect",
+ description: "A protocol to connect blockchain wallets to dapps.",
+ url: "https://walletconnect.com/",
+ icons: []
+ )
+ }
+}
+
+extension Pairing {
+ static func stub() -> Pairing {
+ Pairing(topic: String.generateTopic()!, peer: nil)
+ }
+}
+
+extension Session.Permissions {
+ static func stub(
+ chains: Set = ["solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ"],
+ methods: Set = ["getGenesisHash"],
+ notifications: [String] = ["msg"]
+ ) -> Session.Permissions {
+ Session.Permissions(
+ blockchains: chains,
+ methods: methods,
+ notifications: notifications
+ )
+ }
+}
+
+extension SessionPermissions {
+ static func stub(
+ chains: Set = ["eip155:1"],
+ jsonrpc: Set = ["eth_sign"],
+ notifications: [String] = ["a_type"],
+ controllerKey: String = AgreementPrivateKey().publicKey.hexRepresentation
+ ) -> SessionPermissions {
+ return SessionPermissions(
+ blockchain: Blockchain(chains: chains),
+ jsonrpc: JSONRPC(methods: jsonrpc),
+ notifications: Notifications(types: notifications),
+ controller: Controller(publicKey: controllerKey)
+ )
+ }
+}
+
+extension RelayProtocolOptions {
+ static func stub() -> RelayProtocolOptions {
+ RelayProtocolOptions(protocol: "", params: nil)
+ }
+}
+
+extension Participant {
+ static func stub(publicKey: String = AgreementPrivateKey().publicKey.hexRepresentation) -> Participant {
+ Participant(publicKey: publicKey, metadata: AppMetadata.stub())
+ }
+}
+
+extension WCRequestSubscriptionPayload {
+ static func stubUpdate(topic: String, accounts: Set = ["std:0:0"]) -> WCRequestSubscriptionPayload {
+ let updateMethod = WCMethod.wcSessionUpdate(SessionType.UpdateParams(accounts: accounts)).asRequest()
+ return WCRequestSubscriptionPayload(topic: topic, wcRequest: updateMethod)
+ }
+
+ static func stubUpgrade(topic: String, permissions: SessionPermissions = SessionPermissions(permissions: Session.Permissions.stub())) -> WCRequestSubscriptionPayload {
+ let upgradeMethod = WCMethod.wcSessionUpgrade(SessionType.UpgradeParams(permissions: permissions)).asRequest()
+ return WCRequestSubscriptionPayload(topic: topic, wcRequest: upgradeMethod)
+ }
+}
diff --git a/Tests/WalletConnectTests/Mocks/WalletConnectURI+Stub.swift b/Tests/WalletConnectTests/Stub/WalletConnectURI+Stub.swift
similarity index 100%
rename from Tests/WalletConnectTests/Mocks/WalletConnectURI+Stub.swift
rename to Tests/WalletConnectTests/Stub/WalletConnectURI+Stub.swift
diff --git a/Tests/WalletConnectTests/TestsData/SerialiserTestData.swift b/Tests/WalletConnectTests/TestsData/SerialiserTestData.swift
index f2f4d91e1..452c9eed1 100644
--- a/Tests/WalletConnectTests/TestsData/SerialiserTestData.swift
+++ b/Tests/WalletConnectTests/TestsData/SerialiserTestData.swift
@@ -3,14 +3,14 @@
import Foundation
@testable import WalletConnect
-enum SerialiserTestData {
+enum SerializerTestData {
static let emptyAgreementSecret = AgreementSecret(sharedSecret: Data(hex: ""), publicKey: AgreementPrivateKey().publicKey)
static let iv = Data(hex: "f0d00d4274a7e9711e4e0f21820b8877")
static let publicKey = Data(hex: "45c59ad0c053925072f4503a39fe579ca8b7b8fa6bf0c7297e6db8f6585ee77f")
static let mac = Data(hex: "fc6d3106fa827043279f9db08cd2e29a988c7272fa3cfdb739163bb9606822c7")
static let cipherText =
Data(hex: "14aa7f6034dd0213be5901b472f461769855ac1e2f6bec6a8ed1157a9da3b2df08802cbd6e0d030d86ff99011040cfc831eec3636c1d46bfc22cbe055560fea3")
- static let serialisedMessage = "f0d00d4274a7e9711e4e0f21820b887745c59ad0c053925072f4503a39fe579ca8b7b8fa6bf0c7297e6db8f6585ee77ffc6d3106fa827043279f9db08cd2e29a988c7272fa3cfdb739163bb9606822c714aa7f6034dd0213be5901b472f461769855ac1e2f6bec6a8ed1157a9da3b2df08802cbd6e0d030d86ff99011040cfc831eec3636c1d46bfc22cbe055560fea3"
+ static let serializedMessage = "f0d00d4274a7e9711e4e0f21820b887745c59ad0c053925072f4503a39fe579ca8b7b8fa6bf0c7297e6db8f6585ee77ffc6d3106fa827043279f9db08cd2e29a988c7272fa3cfdb739163bb9606822c714aa7f6034dd0213be5901b472f461769855ac1e2f6bec6a8ed1157a9da3b2df08802cbd6e0d030d86ff99011040cfc831eec3636c1d46bfc22cbe055560fea3"
static let pairingApproveJSONRPCRequest = WCRequest(
id: 0,
jsonrpc: "2.0",
diff --git a/Tests/WalletConnectTests/WCRelayTests.swift b/Tests/WalletConnectTests/WCRelayTests.swift
index 37ead33db..50e072d5d 100644
--- a/Tests/WalletConnectTests/WCRelayTests.swift
+++ b/Tests/WalletConnectTests/WCRelayTests.swift
@@ -9,22 +9,22 @@ import WalletConnectUtils
class WalletConnectRelayTests: XCTestCase {
var wcRelay: WalletConnectRelay!
var networkRelayer: MockedNetworkRelayer!
- var serialiser: MockedJSONRPCSerialiser!
+ var serializer: MockedJSONRPCSerializer!
var crypto: Crypto!
private var publishers = [AnyCancellable]()
override func setUp() {
let logger = ConsoleLoggerMock()
- serialiser = MockedJSONRPCSerialiser()
+ serializer = MockedJSONRPCSerializer()
networkRelayer = MockedNetworkRelayer()
- wcRelay = WalletConnectRelay(networkRelayer: networkRelayer, jsonRpcSerialiser: serialiser, logger: logger, jsonRpcHistory: JsonRpcHistory(logger: logger, keyValueStore: KeyValueStore(defaults: RuntimeKeyValueStorage(), identifier: "")))
+ wcRelay = WalletConnectRelay(networkRelayer: networkRelayer, jsonRpcSerializer: serializer, logger: logger, jsonRpcHistory: JsonRpcHistory(logger: logger, keyValueStore: KeyValueStore(defaults: RuntimeKeyValueStorage(), identifier: "")))
}
override func tearDown() {
wcRelay = nil
networkRelayer = nil
- serialiser = nil
+ serializer = nil
}
func testNotifiesOnEncryptedWCJsonRpcRequest() {
@@ -33,7 +33,7 @@ class WalletConnectRelayTests: XCTestCase {
wcRelay.wcRequestPublisher.sink { (request) in
requestExpectation.fulfill()
}.store(in: &publishers)
- serialiser.deserialised = SerialiserTestData.pairingApproveJSONRPCRequest
+ serializer.deserialized = SerializerTestData.pairingApproveJSONRPCRequest
networkRelayer.onMessage?(topic, testPayload)
waitForExpectations(timeout: 1.001, handler: nil)
}
@@ -43,8 +43,8 @@ class WalletConnectRelayTests: XCTestCase {
let topic = "93293932"
let request = getWCSessionPayloadRequest()
let sessionPayloadResponse = getWCSessionPayloadResponse()
- serialiser.deserialised = sessionPayloadResponse
- serialiser.serialised = try! sessionPayloadResponse.json().toHexEncodedString()
+ serializer.deserialized = sessionPayloadResponse
+ serializer.serialized = try! sessionPayloadResponse.json().toHexEncodedString()
wcRelay.request(topic: topic, payload: request) { result in
XCTAssertEqual(result, .success(sessionPayloadResponse))
responseExpectation.fulfill()
@@ -60,8 +60,8 @@ class WalletConnectRelayTests: XCTestCase {
let topic = "fefc3dc39cacbc562ed58f92b296e2d65a6b07ef08992b93db5b3cb86280635a"
let request = getWCSessionPayloadRequest()
let sessionPayloadResponse = getWCSessionPayloadResponse()
- serialiser.deserialised = sessionPayloadResponse
- serialiser.serialised = "encrypted_message"
+ serializer.deserialized = sessionPayloadResponse
+ serializer.serialized = "encrypted_message"
wcRelay.request(topic: topic, payload: request) { result in
XCTAssertEqual(result, .success(sessionPayloadResponse))
responseExpectation.fulfill()