diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Database.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Database.xcscheme
new file mode 100644
index 000000000..af7725d2f
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/Database.xcscheme
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example/IntegrationTests/Push/NotifyTests.swift b/Example/IntegrationTests/Push/NotifyTests.swift
index 9c9fdc96d..1fbb8aaae 100644
--- a/Example/IntegrationTests/Push/NotifyTests.swift
+++ b/Example/IntegrationTests/Push/NotifyTests.swift
@@ -74,9 +74,11 @@ final class NotifyTests: XCTestCase {
keychainStorage: keychain,
environment: .sandbox)
let keyserverURL = URL(string: "https://keys.walletconnect.com")!
+ let sqlite = try! MemorySqlite()
// Note:- prod project_id do not exists on staging, we can use gmDappProjectId
let client = NotifyClientFactory.create(projectId: InputConfig.gmDappProjectId,
- keyserverURL: keyserverURL,
+ keyserverURL: keyserverURL,
+ sqlite: sqlite,
logger: notifyLogger,
keyValueStorage: keyValueStorage,
keychainStorage: keychain,
diff --git a/Example/WalletApp/ApplicationLayer/LoggingService.swift b/Example/WalletApp/ApplicationLayer/LoggingService.swift
index e7a74cb9b..b03f7002b 100644
--- a/Example/WalletApp/ApplicationLayer/LoggingService.swift
+++ b/Example/WalletApp/ApplicationLayer/LoggingService.swift
@@ -49,7 +49,7 @@ final class LoggingService {
SentrySDK.capture(error: LoggingError.networking(log.aggregated))
case .warn(let log):
// Example of setting level to warning
- var event = Event(level: .warning)
+ let event = Event(level: .warning)
event.message = SentryMessage(formatted: log.aggregated)
SentrySDK.capture(event: event)
default:
diff --git a/Example/WalletApp/Other/Assets.xcassets/subscription_empty_icon.imageset/Contents.json b/Example/WalletApp/Other/Assets.xcassets/subscription_empty_icon.imageset/Contents.json
new file mode 100644
index 000000000..2410c5c51
--- /dev/null
+++ b/Example/WalletApp/Other/Assets.xcassets/subscription_empty_icon.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "filename" : "subscription_empty_icon.png",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Example/WalletApp/Other/Assets.xcassets/subscription_empty_icon.imageset/subscription_empty_icon.png b/Example/WalletApp/Other/Assets.xcassets/subscription_empty_icon.imageset/subscription_empty_icon.png
new file mode 100644
index 000000000..70f324724
Binary files /dev/null and b/Example/WalletApp/Other/Assets.xcassets/subscription_empty_icon.imageset/subscription_empty_icon.png differ
diff --git a/Example/WalletApp/Other/Assets.xcassets/subscriptions_empty_background.imageset/Contents.json b/Example/WalletApp/Other/Assets.xcassets/subscriptions_empty_background.imageset/Contents.json
new file mode 100644
index 000000000..14f69feeb
--- /dev/null
+++ b/Example/WalletApp/Other/Assets.xcassets/subscriptions_empty_background.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "filename" : "subscriptions_empty_background.png",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Example/WalletApp/Other/Assets.xcassets/subscriptions_empty_background.imageset/subscriptions_empty_background.png b/Example/WalletApp/Other/Assets.xcassets/subscriptions_empty_background.imageset/subscriptions_empty_background.png
new file mode 100644
index 000000000..cfdcc06ae
Binary files /dev/null and b/Example/WalletApp/Other/Assets.xcassets/subscriptions_empty_background.imageset/subscriptions_empty_background.png differ
diff --git a/Example/WalletApp/Other/Assets.xcassets/subscriptions_empty_icon.imageset/Contents.json b/Example/WalletApp/Other/Assets.xcassets/subscriptions_empty_icon.imageset/Contents.json
new file mode 100644
index 000000000..f775c3dcc
--- /dev/null
+++ b/Example/WalletApp/Other/Assets.xcassets/subscriptions_empty_icon.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "filename" : "subscriptions_empty_icon.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/Example/WalletApp/Other/Assets.xcassets/subscriptions_empty_icon.imageset/subscriptions_empty_icon.svg b/Example/WalletApp/Other/Assets.xcassets/subscriptions_empty_icon.imageset/subscriptions_empty_icon.svg
new file mode 100644
index 000000000..9f1eca535
--- /dev/null
+++ b/Example/WalletApp/Other/Assets.xcassets/subscriptions_empty_icon.imageset/subscriptions_empty_icon.svg
@@ -0,0 +1,30 @@
+
diff --git a/Example/WalletApp/PresentationLayer/Wallet/Notifications/NotificationsView.swift b/Example/WalletApp/PresentationLayer/Wallet/Notifications/NotificationsView.swift
index 73151545c..343eac466 100644
--- a/Example/WalletApp/PresentationLayer/Wallet/Notifications/NotificationsView.swift
+++ b/Example/WalletApp/PresentationLayer/Wallet/Notifications/NotificationsView.swift
@@ -15,35 +15,51 @@ struct NotificationsView: View {
List {
Section {
if selectedIndex == 0 {
- notifications()
+ if presenter.subscriptionViewModels.isEmpty {
+ emptySubscriptionsView()
+ } else {
+ notifications()
+ }
} else {
discover()
}
} header: {
- HStack {
- SegmentedPicker(["Notifications", "Discover"],
- selectedIndex: Binding(
- get: { selectedIndex },
- set: { selectedIndex = $0 ?? 0 }),
- content: { item, isSelected in
- Text(item)
- .font(.system(size: 16, weight: .medium))
- .foregroundColor(isSelected ? Color.primary : Color.secondary )
- .padding(.trailing, 32)
- .padding(.vertical, 8)
- }, selection: {
- VStack(spacing: 0) {
- Spacer()
- Rectangle()
- .fill(.Blue100)
- .frame(height: 2)
+ VStack(spacing: 0) {
+ HStack {
+ SegmentedPicker(["Subscriptions", "Discover"],
+ selectedIndex: Binding(
+ get: { selectedIndex },
+ set: { selectedIndex = $0 ?? 0 }),
+ content: { item, isSelected in
+ Text(item)
+ .font(.system(size: 16, weight: .medium))
+ .foregroundColor(isSelected ? Color.primary : Color.secondary )
.padding(.trailing, 32)
- }
- })
+ .padding(.vertical, 8)
+ }, selection: {
+ VStack(spacing: 0) {
+ Spacer()
+ Rectangle()
+ .fill(.Blue100)
+ .frame(height: 2)
+ .padding(.trailing, 32)
+ }
+ })
+ .padding(.horizontal, 20)
+ .animation(.easeInOut(duration: 0.3))
+
+ Spacer()
+ }
+
+ Rectangle()
+ .foregroundColor(.black.opacity(0.03))
+ .frame(maxWidth: .infinity)
+ .frame(height: 1)
}
- .animation(.easeInOut(duration: 0.3))
.listRowBackground(Color.clear)
}
+ .listRowInsets(EdgeInsets())
+ .listRowSeparator(.hidden)
}
.listStyle(PlainListStyle())
}
@@ -57,28 +73,37 @@ struct NotificationsView: View {
discoverListRow(listing: listing)
.listRowSeparator(.hidden)
.listRowBackground(Color.clear)
+ .listRowInsets(EdgeInsets(top: 16, leading: 20, bottom: 0, trailing: 20))
}
}
private func emptySubscriptionsView() -> some View {
- VStack(spacing: 10) {
- Spacer()
-
- Image(systemName: "bell.badge.fill")
+ ZStack {
+ Image("subscriptions_empty_background")
.resizable()
- .frame(width: 32, height: 32)
- .aspectRatio(contentMode: .fit)
- .foregroundColor(.grey50)
+ .frame(maxWidth: .infinity)
+ .ignoresSafeArea()
- Text("Notifications from connected apps will appear here. To enable notifications, visit the app in your browser and look for a \(Image(systemName: "bell.fill")) notifications toggle \(Image(systemName: "switch.2"))")
- .foregroundColor(.grey50)
- .font(.system(size: 15, weight: .regular, design: .rounded))
- .multilineTextAlignment(.center)
- .lineSpacing(4)
+ VStack(spacing: 0) {
+ Image("subscriptions_empty_icon")
- Spacer()
+ Text("Add your first app")
+ .foregroundColor(.Foreground100)
+ .font(.large700)
+ .padding(.bottom, 8.0)
+
+ Text("Head over to “Discover” and\nsubscribe to one of our apps to start\nreceiving notifications")
+ .multilineTextAlignment(.center)
+ .foregroundColor(.Foreground200)
+ .font(.paragraph500)
+ .padding(.bottom, 16.0)
+
+ Button("Discover apps") {
+ selectedIndex = 1
+ }
+ .buttonStyle(W3MButtonStyle(size: .m, variant: .main))
+ }
}
- .padding(20)
}
private func notifications() -> some View {
diff --git a/Example/WalletApp/PresentationLayer/Wallet/PushMessages/SubscriptionView.swift b/Example/WalletApp/PresentationLayer/Wallet/PushMessages/SubscriptionView.swift
index 2a37713ef..1b579552d 100644
--- a/Example/WalletApp/PresentationLayer/Wallet/PushMessages/SubscriptionView.swift
+++ b/Example/WalletApp/PresentationLayer/Wallet/PushMessages/SubscriptionView.swift
@@ -1,4 +1,5 @@
import SwiftUI
+import Web3ModalUI
struct SubscriptionView: View {
@@ -140,20 +141,21 @@ struct SubscriptionView: View {
}
func emptyStateView() -> some View {
- VStack(spacing: 10) {
- Image(systemName: "bell.badge.fill")
- .resizable()
- .frame(width: 32, height: 32)
- .aspectRatio(contentMode: .fit)
- .foregroundColor(.grey50)
-
- Text("Notifications from connected apps will appear here. To enable notifications, visit the app in your browser and look for a \(Image(systemName: "bell.fill")) notifications toggle \(Image(systemName: "switch.2"))")
- .foregroundColor(.grey50)
- .font(.system(size: 15, weight: .regular, design: .rounded))
- .multilineTextAlignment(.center)
- .lineSpacing(4)
+ VStack(spacing: 0) {
+ Image("subscription_empty_icon")
+ .padding(.bottom, 24)
+
+ Text("You’re ready to go")
+ .font(.large700)
+ .foregroundColor(.Foreground100)
+ .padding(.bottom, 8)
+
+ Text("All new notifications will appear here.")
+ .font(.paragraph500)
+ .foregroundColor(.Foreground150)
}
- .padding(20)
+ .frame(maxWidth: .infinity)
+ .frame(height: 410)
}
}
diff --git a/Package.swift b/Package.swift
index b4c69b94b..0f7ce4e77 100644
--- a/Package.swift
+++ b/Package.swift
@@ -74,7 +74,7 @@ let package = Package(
path: "Sources/Web3Wallet"),
.target(
name: "WalletConnectNotify",
- dependencies: ["WalletConnectPairing", "WalletConnectPush", "WalletConnectIdentity", "WalletConnectSigner"],
+ dependencies: ["WalletConnectPairing", "WalletConnectPush", "WalletConnectIdentity", "WalletConnectSigner", "Database"],
path: "Sources/WalletConnectNotify"),
.target(
name: "WalletConnectPush",
@@ -130,6 +130,9 @@ let package = Package(
.target(
name: "WalletConnectVerify",
dependencies: ["WalletConnectUtils", "WalletConnectNetworking"]),
+ .target(
+ name: "Database",
+ dependencies: []),
.target(
name: "WalletConnectModal",
dependencies: ["QRCode", "WalletConnectSign"],
diff --git a/Sources/Database/DiskSqlite.swift b/Sources/Database/DiskSqlite.swift
new file mode 100644
index 000000000..19ffba05e
--- /dev/null
+++ b/Sources/Database/DiskSqlite.swift
@@ -0,0 +1,46 @@
+import Foundation
+import SQLite3
+
+public final class DiskSqlite: Sqlite {
+
+ private let path: String
+
+ private var db: OpaquePointer?
+
+ public init(path: String) {
+ self.path = path
+ }
+
+ public func openDatabase() throws {
+ guard sqlite3_open_v2(path, &db, SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK else {
+ throw SQLiteError.openDatabase(path: path)
+ }
+ }
+
+ public func query(sql: String) throws -> [Row] {
+ var queryStatement: OpaquePointer?
+ guard sqlite3_prepare_v2(db, sql, -1, &queryStatement, nil) == SQLITE_OK else {
+ throw SQLiteError.queryPrepare(statement: sql)
+ }
+ var rows: [Row] = []
+ while sqlite3_step(queryStatement) == SQLITE_ROW {
+ let decoder = SqliteRowDecoder(statement: queryStatement)
+ guard let row = try? Row(decoder: decoder) else { continue }
+ rows.append(row)
+ }
+ sqlite3_finalize(queryStatement)
+ return rows
+ }
+
+ public func execute(sql: String) throws {
+ var error: UnsafeMutablePointer?
+ guard sqlite3_exec(db, sql, nil, nil, &error) == SQLITE_OK else {
+ let message = error.map { String(cString: $0) }
+ throw SQLiteError.exec(error: message)
+ }
+ }
+
+ public func closeConnection() {
+ sqlite3_close(db)
+ }
+}
diff --git a/Sources/Database/MemorySqlite.swift b/Sources/Database/MemorySqlite.swift
new file mode 100644
index 000000000..640098d04
--- /dev/null
+++ b/Sources/Database/MemorySqlite.swift
@@ -0,0 +1,44 @@
+import Foundation
+import SQLite3
+
+public final class MemorySqlite: Sqlite {
+
+ private var db: OpaquePointer?
+
+ public init() throws {
+ guard sqlite3_open_v2(":memory:", &db, SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE|SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK else {
+ throw SQLiteError.openDatabaseMemory
+ }
+ }
+
+ public func openDatabase() throws {
+ // No op
+ }
+
+ public func query(sql: String) throws -> [Row] {
+ var queryStatement: OpaquePointer?
+ guard sqlite3_prepare_v2(db, sql, -1, &queryStatement, nil) == SQLITE_OK else {
+ throw SQLiteError.queryPrepare(statement: sql)
+ }
+ var rows: [Row] = []
+ while sqlite3_step(queryStatement) == SQLITE_ROW {
+ let decoder = SqliteRowDecoder(statement: queryStatement)
+ guard let row = try? Row(decoder: decoder) else { continue }
+ rows.append(row)
+ }
+ sqlite3_finalize(queryStatement)
+ return rows
+ }
+
+ public func execute(sql: String) throws {
+ var error: UnsafeMutablePointer?
+ guard sqlite3_exec(db, sql, nil, nil, &error) == SQLITE_OK else {
+ let message = error.map { String(cString: $0) }
+ throw SQLiteError.exec(error: message)
+ }
+ }
+
+ public func closeConnection() {
+ // No op
+ }
+}
diff --git a/Sources/Database/SQLiteQuery.swift b/Sources/Database/SQLiteQuery.swift
new file mode 100644
index 000000000..a21927639
--- /dev/null
+++ b/Sources/Database/SQLiteQuery.swift
@@ -0,0 +1,50 @@
+import Foundation
+
+public struct SqliteQuery {
+
+ public static func replace(table: String, rows: [SqliteRow]) throws -> String {
+ var values: [String] = []
+
+ for row in rows {
+ values.append(row.encode().values
+ .map { "'\($0.value)'" }
+ .joined(separator: ", "))
+ }
+
+ guard let first = rows.first else {
+ throw Errors.rowsNotFound
+ }
+
+ let formattedArguments = first.encode().values
+ .map { $0.argument }
+ .joined(separator: ", ")
+
+ let formattedValues = values
+ .map { "(\($0))" }
+ .joined(separator: ",\n")
+
+ return """
+ REPLACE INTO \(table) (\(formattedArguments)) VALUES
+ \(formattedValues);
+ """
+ }
+
+ public static func select(table: String) -> String {
+ return "SELECT * FROM \(table);"
+ }
+
+ public static func select(table: String, where argument: String, equals value: String) -> String {
+ return "SELECT * FROM \(table) WHERE \(argument) = '\(value)';"
+ }
+
+ public static func delete(table: String, where argument: String, equals value: String) -> String {
+ return "DELETE FROM \(table) WHERE \(argument) = '\(value)';"
+ }
+}
+
+extension SqliteQuery {
+
+ enum Errors: Error {
+ case rowsNotFound
+ }
+}
diff --git a/Sources/Database/Sqlite.swift b/Sources/Database/Sqlite.swift
new file mode 100644
index 000000000..1770872af
--- /dev/null
+++ b/Sources/Database/Sqlite.swift
@@ -0,0 +1,20 @@
+import Foundation
+import SQLite3
+
+public protocol Sqlite {
+
+ /// Opening A New Database Connection
+ func openDatabase() throws
+
+ /// Evaluate an SQL Statement
+ /// - Parameter sql: SQL query
+ /// - Returns: Table rows array
+ func query(sql: String) throws -> [Row]
+
+ /// One-Step query execution
+ /// - Parameter sql: SQL query
+ func execute(sql: String) throws
+
+ /// Closing A Database Connection
+ func closeConnection()
+}
diff --git a/Sources/Database/SqliteError.swift b/Sources/Database/SqliteError.swift
new file mode 100644
index 000000000..9915bca06
--- /dev/null
+++ b/Sources/Database/SqliteError.swift
@@ -0,0 +1,11 @@
+import Foundation
+
+public enum SQLiteError: Error {
+ case openDatabase(path: String)
+ case openDatabaseMemory
+ case queryPrepare(statement: String)
+ case exec(error: String?)
+ case decodeString(index: Int32)
+ case stringIsNotBase64
+ case stringIsNotTimestamp
+}
diff --git a/Sources/Database/SqliteRow.swift b/Sources/Database/SqliteRow.swift
new file mode 100644
index 000000000..f1a683083
--- /dev/null
+++ b/Sources/Database/SqliteRow.swift
@@ -0,0 +1,12 @@
+import Foundation
+
+public protocol SqliteRow {
+
+ /// SqliteRow initialization
+ /// - Parameter decoder: SqliteRowDecoder instance
+ init(decoder: SqliteRowDecoder) throws
+
+ /// SqliteRow encoding
+ /// - Returns: SqliteRowEncoder instance
+ func encode() -> SqliteRowEncoder
+}
diff --git a/Sources/Database/SqliteRowDecoder.swift b/Sources/Database/SqliteRowDecoder.swift
new file mode 100644
index 000000000..bd9bde816
--- /dev/null
+++ b/Sources/Database/SqliteRowDecoder.swift
@@ -0,0 +1,51 @@
+import Foundation
+import SQLite3
+
+public class SqliteRowDecoder {
+
+ private let statement: OpaquePointer?
+
+ init(statement: OpaquePointer?) {
+ self.statement = statement
+ }
+
+ /// Decode string from column at index
+ /// - Parameter index: Column index
+ /// - Returns: Decoded string
+ public func decodeString(at index: Int32) throws -> String {
+ guard let raw = sqlite3_column_text(statement, index) else {
+ throw SQLiteError.decodeString(index: index)
+ }
+ return String(cString: raw)
+ }
+
+ /// Decode bool from column at index
+ /// - Parameter index: Column index
+ /// - Returns: Decoded bool
+ public func decodeBool(at index: Int32) throws -> Bool {
+ let string = try decodeString(at: index)
+ return (string as NSString).boolValue
+ }
+
+ /// Decode codable object from column at index
+ /// - Parameter index: Column index
+ /// - Returns: Decoded codable object
+ public func decodeCodable(at index: Int32) throws -> T {
+ let string = try decodeString(at: index)
+ guard let data = Data(base64Encoded: string) else {
+ throw SQLiteError.stringIsNotBase64
+ }
+ return try JSONDecoder().decode(T.self, from: data)
+ }
+
+ /// Decode date from column at index
+ /// - Parameter index: Column index
+ /// - Returns: Decoded date
+ public func decodeDate(at index: Int32) throws -> Date {
+ let string = try decodeString(at: index)
+ guard let interval = TimeInterval(string) else {
+ throw SQLiteError.stringIsNotTimestamp
+ }
+ return Date(timeIntervalSince1970: interval)
+ }
+}
diff --git a/Sources/Database/SqliteRowEncoder.swift b/Sources/Database/SqliteRowEncoder.swift
new file mode 100644
index 000000000..9c7516b41
--- /dev/null
+++ b/Sources/Database/SqliteRowEncoder.swift
@@ -0,0 +1,33 @@
+import Foundation
+
+public struct SqliteRowEncoder {
+ struct Value {
+ let argument: String
+ let value: String
+ }
+
+ var values: [Value] = []
+
+ public init() { }
+
+ public mutating func encodeString(_ value: String, for argument: String) {
+ let value = Value(argument: argument, value: value)
+ values.append(value)
+ }
+
+ public mutating func encodeDate(_ value: Date, for argument: String) {
+ let value = Value(argument: argument, value: String(value.timeIntervalSince1970))
+ values.append(value)
+ }
+
+ public mutating func encodeCodable(_ value: T, for argument: String) {
+ let data = try! JSONEncoder().encode(value)
+ let value = Value(argument: argument, value: data.base64EncodedString())
+ values.append(value)
+ }
+
+ public mutating func encodeBool(_ value: Bool, for argument: String) {
+ let value = Value(argument: argument, value: String(value))
+ values.append(value)
+ }
+}
diff --git a/Sources/WalletConnectModal/Extensions/Bundle.swift b/Sources/WalletConnectModal/Extensions/Bundle.swift
new file mode 100644
index 000000000..a68d32564
--- /dev/null
+++ b/Sources/WalletConnectModal/Extensions/Bundle.swift
@@ -0,0 +1,7 @@
+import Foundation
+
+#if CocoaPods
+extension Bundle {
+ static var module: Bundle { Bundle.init(for: WalletConnectModal.self) }
+}
+#endif
diff --git a/Sources/WalletConnectModal/Extensions/Image+Backport.swift b/Sources/WalletConnectModal/Extensions/Image+Backport.swift
new file mode 100644
index 000000000..bab1f5e17
--- /dev/null
+++ b/Sources/WalletConnectModal/Extensions/Image+Backport.swift
@@ -0,0 +1,12 @@
+import SwiftUI
+
+extension Image {
+
+ init(sfSymbolName: String) {
+ if #available(macOS 11, iOS 13, *) {
+ self.init(systemName: sfSymbolName)
+ } else {
+ self.init("", bundle: nil)
+ }
+ }
+}
diff --git a/Sources/WalletConnectModal/Extensions/View+Backport.swift b/Sources/WalletConnectModal/Extensions/View+Backport.swift
index c8025f061..b93de0e16 100644
--- a/Sources/WalletConnectModal/Extensions/View+Backport.swift
+++ b/Sources/WalletConnectModal/Extensions/View+Backport.swift
@@ -2,6 +2,9 @@ import Combine
import SwiftUI
extension View {
+
+ #if os(iOS)
+
/// A backwards compatible wrapper for iOS 14 `onChange`
@ViewBuilder
func onChangeBackported(of value: T, perform: @escaping (T) -> Void) -> some View {
@@ -13,4 +16,15 @@ extension View {
}
}
}
+
+ #elseif os(macOS)
+
+ @ViewBuilder
+ func onChangeBackported(of value: T, perform: @escaping (T) -> Void) -> some View {
+ self.onReceive(Just(value)) { value in
+ perform(value)
+ }
+ }
+
+ #endif
}
diff --git a/Sources/WalletConnectModal/Modal/ModalContainerView.swift b/Sources/WalletConnectModal/Modal/ModalContainerView.swift
index 4bdbefc8a..ab24e444b 100644
--- a/Sources/WalletConnectModal/Modal/ModalContainerView.swift
+++ b/Sources/WalletConnectModal/Modal/ModalContainerView.swift
@@ -37,11 +37,15 @@ struct ModalContainerView: View {
)
.edgesIgnoringSafeArea(.all)
.transform {
- if #available(iOS 14.0, *) {
- $0.ignoresSafeArea(.keyboard, edges: .bottom)
- } else {
+ #if os(iOS)
+ if #available(iOS 14.0, *) {
+ $0.ignoresSafeArea(.keyboard, edges: .bottom)
+ } else {
+ $0
+ }
+ #else
$0
- }
+ #endif
}
.onChangeBackported(of: showModal, perform: { newValue in
if newValue == false {
diff --git a/Sources/WalletConnectModal/Modal/ModalSheet.swift b/Sources/WalletConnectModal/Modal/ModalSheet.swift
index c51e69d2b..b09226db0 100644
--- a/Sources/WalletConnectModal/Modal/ModalSheet.swift
+++ b/Sources/WalletConnectModal/Modal/ModalSheet.swift
@@ -81,7 +81,7 @@ public struct ModalSheet: View {
VStack {
if viewModel.destination.hasSearch {
HStack {
- Image(systemName: "magnifyingglass")
+ Image(sfSymbolName: "magnifyingglass")
TextField("Search", text: $viewModel.searchTerm, onEditingChanged: { editing in
self.searchEditing = editing
})
@@ -186,7 +186,7 @@ extension ModalSheet {
viewModel.onBackButton()
}
} label: {
- Image(systemName: "chevron.backward")
+ Image(sfSymbolName: "chevron.backward")
.padding(20)
}
}
diff --git a/Sources/WalletConnectModal/Modal/Screens/GetAWalletView.swift b/Sources/WalletConnectModal/Modal/Screens/GetAWalletView.swift
index d9f8e1f30..b5f2c7438 100644
--- a/Sources/WalletConnectModal/Modal/Screens/GetAWalletView.swift
+++ b/Sources/WalletConnectModal/Modal/Screens/GetAWalletView.swift
@@ -22,7 +22,7 @@ struct GetAWalletView: View {
Spacer()
- Image(systemName: "chevron.right")
+ Image(sfSymbolName: "chevron.right")
.font(.system(.footnote).weight(.semibold))
}
}
diff --git a/Sources/WalletConnectModal/Modal/Screens/WalletDetail/WalletDetail.swift b/Sources/WalletConnectModal/Modal/Screens/WalletDetail/WalletDetail.swift
index 3bae82d17..2fb5f1bff 100644
--- a/Sources/WalletConnectModal/Modal/Screens/WalletDetail/WalletDetail.swift
+++ b/Sources/WalletConnectModal/Modal/Screens/WalletDetail/WalletDetail.swift
@@ -18,9 +18,9 @@ struct WalletDetail: View {
HStack {
switch item {
case .native:
- Image(systemName: "iphone")
+ Image(sfSymbolName: "iphone")
case .browser:
- Image(systemName: "safari")
+ Image(sfSymbolName: "safari")
}
Text(item.rawValue.capitalized)
}
@@ -181,7 +181,7 @@ struct WalletDetail: View {
.foregroundColor(.foreground2)
.font(.system(size: 14).weight(.semibold))
- Image(systemName: "chevron.right")
+ Image(sfSymbolName: "chevron.right")
.foregroundColor(.foreground2)
}
}
diff --git a/Sources/WalletConnectModal/Networking/Explorer/ExplorerAPI.swift b/Sources/WalletConnectModal/Networking/Explorer/ExplorerAPI.swift
index 806ae02c7..f52a3db67 100644
--- a/Sources/WalletConnectModal/Networking/Explorer/ExplorerAPI.swift
+++ b/Sources/WalletConnectModal/Networking/Explorer/ExplorerAPI.swift
@@ -1,5 +1,4 @@
import Foundation
-import HTTPClient
enum ExplorerAPI: HTTPService {
case getListings(
diff --git a/Sources/WalletConnectModal/UI/Common/Toast.swift b/Sources/WalletConnectModal/UI/Common/Toast.swift
index f8e276a25..e637cee46 100644
--- a/Sources/WalletConnectModal/UI/Common/Toast.swift
+++ b/Sources/WalletConnectModal/UI/Common/Toast.swift
@@ -40,7 +40,7 @@ struct ToastView: View {
var body: some View {
HStack(alignment: .center, spacing: 12) {
- Image(systemName: style.iconFileName)
+ Image(sfSymbolName: style.iconFileName)
.foregroundColor(style.themeColor)
Text(message)
.font(Font.caption)
@@ -51,7 +51,7 @@ struct ToastView: View {
Button {
onCancelTapped()
} label: {
- Image(systemName: "xmark")
+ Image(sfSymbolName: "xmark")
.foregroundColor(style.themeColor)
}
}
diff --git a/Sources/WalletConnectModal/UI/Common/Web3ModalPicker.swift b/Sources/WalletConnectModal/UI/Common/Web3ModalPicker.swift
index 0822b7fc9..31ba098ad 100644
--- a/Sources/WalletConnectModal/UI/Common/Web3ModalPicker.swift
+++ b/Sources/WalletConnectModal/UI/Common/Web3ModalPicker.swift
@@ -94,7 +94,7 @@ struct PreviewWeb3ModalPicker: View {
) { item in
HStack {
- Image(systemName: "iphone")
+ Image(sfSymbolName: "iphone")
Text(item.rawValue.capitalized)
}
.font(.system(size: 14).weight(.semibold))
diff --git a/Sources/WalletConnectNotify/Client/Wallet/NotifyAccountProvider.swift b/Sources/WalletConnectNotify/Client/Wallet/NotifyAccountProvider.swift
index 8a702fabd..48df9c09c 100644
--- a/Sources/WalletConnectNotify/Client/Wallet/NotifyAccountProvider.swift
+++ b/Sources/WalletConnectNotify/Client/Wallet/NotifyAccountProvider.swift
@@ -5,7 +5,7 @@ final class NotifyAccountProvider {
case currentAccountNotFound
}
- private var currentAccount: Account?
+ private(set) var currentAccount: Account?
func setAccount(_ account: Account) {
self.currentAccount = account
diff --git a/Sources/WalletConnectNotify/Client/Wallet/NotifyClient.swift b/Sources/WalletConnectNotify/Client/Wallet/NotifyClient.swift
index b4e04c5be..bba5af964 100644
--- a/Sources/WalletConnectNotify/Client/Wallet/NotifyClient.swift
+++ b/Sources/WalletConnectNotify/Client/Wallet/NotifyClient.swift
@@ -84,7 +84,7 @@ public class NotifyClient {
public func unregister(account: Account) async throws {
try await identityService.unregister(account: account)
notifyWatcherAgreementKeysProvider.removeAgreement(account: account)
- notifyStorage.clearDatabase(account: account)
+ try notifyStorage.clearDatabase(account: account)
notifyAccountProvider.logout()
subscriptionWatcher.stop()
}
@@ -114,7 +114,7 @@ public class NotifyClient {
}
public func deleteNotifyMessage(id: String) {
- notifyStorage.deleteMessage(id: id)
+ try? notifyStorage.deleteMessage(id: id)
}
public func register(deviceToken: Data) async throws {
diff --git a/Sources/WalletConnectNotify/Client/Wallet/NotifyClientFactory.swift b/Sources/WalletConnectNotify/Client/Wallet/NotifyClientFactory.swift
index 9d0e41f4a..807927a7f 100644
--- a/Sources/WalletConnectNotify/Client/Wallet/NotifyClientFactory.swift
+++ b/Sources/WalletConnectNotify/Client/Wallet/NotifyClientFactory.swift
@@ -8,10 +8,13 @@ public struct NotifyClientFactory {
let keyserverURL = URL(string: "https://keys.walletconnect.com")!
let keychainStorage = KeychainStorage(serviceIdentifier: "com.walletconnect.sdk")
let groupKeychainService = GroupKeychainStorage(serviceIdentifier: groupIdentifier)
+ let databasePath = databasePath(appGroup: groupIdentifier, database: "notify.db")
+ let sqlite = DiskSqlite(path: databasePath)
return NotifyClientFactory.create(
projectId: projectId,
keyserverURL: keyserverURL,
+ sqlite: sqlite,
logger: logger,
keyValueStorage: keyValueStorage,
keychainStorage: keychainStorage,
@@ -28,6 +31,7 @@ public struct NotifyClientFactory {
static func create(
projectId: String,
keyserverURL: URL,
+ sqlite: Sqlite,
logger: ConsoleLogging,
keyValueStorage: KeyValueStorage,
keychainStorage: KeychainStorageProtocol,
@@ -40,10 +44,9 @@ public struct NotifyClientFactory {
explorerHost: String
) -> NotifyClient {
let kms = KeyManagementService(keychain: keychainStorage)
- let subscriptionStore = KeyedDatabase(storage: keyValueStorage, identifier: NotifyStorageIdntifiers.notifySubscription)
- let messagesStore = KeyedDatabase(storage: keyValueStorage, identifier: NotifyStorageIdntifiers.notifyMessagesRecords)
let notifyAccountProvider = NotifyAccountProvider()
- let notifyStorage = NotifyStorage(subscriptionStore: subscriptionStore, messagesStore: messagesStore, accountProvider: notifyAccountProvider)
+ let database = NotifyDatabase(sqlite: sqlite, logger: logger)
+ let notifyStorage = NotifyStorage(database: database, accountProvider: notifyAccountProvider)
let identityClient = IdentityClientFactory.create(keyserver: keyserverURL, keychain: keychainStorage, logger: logger)
let notifyMessageSubscriber = NotifyMessageSubscriber(keyserver: keyserverURL, networkingInteractor: networkInteractor, identityClient: identityClient, notifyStorage: notifyStorage, crypto: crypto, logger: logger)
let webDidResolver = NotifyWebDidResolver()
@@ -92,4 +95,15 @@ public struct NotifyClientFactory {
subscriptionWatcher: subscriptionWatcher
)
}
+
+ static func databasePath(appGroup: String, database: String) -> String {
+ guard let path = FileManager.default
+ .containerURL(forSecurityApplicationGroupIdentifier: appGroup)?
+ .appendingPathComponent(database) else {
+
+ fatalError("Database path not exists")
+ }
+
+ return path.absoluteString
+ }
}
diff --git a/Sources/WalletConnectNotify/Client/Wallet/NotifyDatabase.swift b/Sources/WalletConnectNotify/Client/Wallet/NotifyDatabase.swift
new file mode 100644
index 000000000..9e6110e2b
--- /dev/null
+++ b/Sources/WalletConnectNotify/Client/Wallet/NotifyDatabase.swift
@@ -0,0 +1,156 @@
+import Foundation
+import Database
+import Combine
+
+final class NotifyDatabase {
+
+ enum Table {
+ static let subscriptions = "NotifySubscription"
+ static let messages = "NotifyMessage"
+ }
+
+ private let sqlite: Sqlite
+ private let logger: ConsoleLogging
+
+ var onSubscriptionsUpdate: (() throws -> Void)?
+ var onMessagesUpdate: (() throws -> Void)?
+
+ init(sqlite: Sqlite, logger: ConsoleLogging) {
+ self.sqlite = sqlite
+ self.logger = logger
+
+ prepareDatabase()
+ }
+
+ // MARK: - NotifySubscriptions
+
+ func save(subscription: NotifySubscription) throws {
+ try save(subscriptions: [subscription])
+ }
+
+ func save(subscriptions: [NotifySubscription]) throws {
+ let sql = try SqliteQuery.replace(table: Table.subscriptions, rows: subscriptions)
+ try execute(sql: sql)
+ try onSubscriptionsUpdate?()
+ }
+
+ func getSubscription(topic: String) -> NotifySubscription? {
+ let sql = SqliteQuery.select(table: Table.subscriptions, where: "topic", equals: topic)
+ let subscriptions: [NotifySubscription]? = try? query(sql: sql)
+ return subscriptions?.first
+ }
+
+ func getAllSubscriptions() -> [NotifySubscription] {
+ let sql = SqliteQuery.select(table: Table.subscriptions)
+ let subscriptions: [NotifySubscription]? = try? query(sql: sql)
+ return subscriptions ?? []
+ }
+
+ func getSubscriptions(account: Account) -> [NotifySubscription] {
+ let sql = SqliteQuery.select(table: Table.subscriptions, where: "account", equals: account.absoluteString)
+ let subscriptions: [NotifySubscription]? = try? query(sql: sql)
+ return subscriptions ?? []
+ }
+
+ func deleteSubscription(topic: String) throws {
+ let sql = SqliteQuery.delete(table: Table.subscriptions, where: "topic", equals: topic)
+ try execute(sql: sql)
+ try onSubscriptionsUpdate?()
+ }
+
+ func deleteSubscription(account: Account) throws {
+ let sql = SqliteQuery.delete(table: Table.subscriptions, where: "account", equals: account.absoluteString)
+ try execute(sql: sql)
+ try onSubscriptionsUpdate?()
+ }
+
+ // MARK: - NotifyMessageRecord
+
+ func getAllMessages() -> [NotifyMessageRecord] {
+ let sql = SqliteQuery.select(table: Table.messages)
+ let messages: [NotifyMessageRecord]? = try? query(sql: sql)
+ return messages ?? []
+ }
+
+ func getMessages(topic: String) -> [NotifyMessageRecord] {
+ let sql = SqliteQuery.select(table: Table.messages, where: "topic", equals: topic)
+ let messages: [NotifyMessageRecord]? = try? query(sql: sql)
+ return messages ?? []
+ }
+
+ func deleteMessages(topic: String) throws {
+ let sql = SqliteQuery.delete(table: Table.messages, where: "topic", equals: topic)
+ try execute(sql: sql)
+ try onMessagesUpdate?()
+ }
+
+ func deleteMessage(id: String) throws {
+ let sql = SqliteQuery.delete(table: Table.messages, where: "id", equals: id)
+ try execute(sql: sql)
+ try onMessagesUpdate?()
+ }
+
+ func save(message: NotifyMessageRecord) throws {
+ try save(messages: [message])
+ }
+
+ func save(messages: [NotifyMessageRecord]) throws {
+ let sql = try SqliteQuery.replace(table: Table.messages, rows: messages)
+ try execute(sql: sql)
+ try onMessagesUpdate?()
+ }
+}
+
+private extension NotifyDatabase {
+
+ func prepareDatabase() {
+ do {
+ defer { sqlite.closeConnection() }
+ try sqlite.openDatabase()
+
+ try sqlite.execute(sql: """
+ CREATE TABLE IF NOT EXISTS \(Table.subscriptions) (
+ topic TEXT PRIMARY KEY,
+ account TEXT NOT NULL,
+ relay TEXT NOT NULL,
+ metadata TEXT NOT NULL,
+ scope TEXT NOT NULL,
+ expiry TEXT NOT NULL,
+ symKey TEXT NOT NULL,
+ appAuthenticationKey TEXT NOT NULL
+ );
+ """)
+
+ try sqlite.execute(sql: """
+ CREATE TABLE IF NOT EXISTS \(Table.messages) (
+ id TEXT PRIMARY KEY,
+ topic TEXT NOT NULL,
+ title TEXT NOT NULL,
+ body TEXT NOT NULL,
+ icon TEXT NOT NULL,
+ url TEXT NOT NULL,
+ type TEXT NOT NULL,
+ publishedAt TEXT NOT NULL
+ );
+ """)
+
+ logger.debug("SQlite database created")
+ } catch {
+ logger.error("SQlite database creation error: \(error.localizedDescription)")
+ }
+ }
+
+ func execute(sql: String) throws {
+ try sqlite.openDatabase()
+ defer { sqlite.closeConnection() }
+
+ try sqlite.execute(sql: sql)
+ }
+
+ func query(sql: String) throws -> [T] {
+ try sqlite.openDatabase()
+ defer { sqlite.closeConnection() }
+
+ return try sqlite.query(sql: sql)
+ }
+}
diff --git a/Sources/WalletConnectNotify/Client/Wallet/NotifyMessageRecord.swift b/Sources/WalletConnectNotify/Client/Wallet/NotifyMessageRecord.swift
index a9431587a..d12331d34 100644
--- a/Sources/WalletConnectNotify/Client/Wallet/NotifyMessageRecord.swift
+++ b/Sources/WalletConnectNotify/Client/Wallet/NotifyMessageRecord.swift
@@ -1,6 +1,6 @@
import Foundation
-public struct NotifyMessageRecord: Codable, Equatable, DatabaseObject {
+public struct NotifyMessageRecord: Codable, Equatable, SqliteRow {
public let id: String
public let topic: String
public let message: NotifyMessage
@@ -9,4 +9,39 @@ public struct NotifyMessageRecord: Codable, Equatable, DatabaseObject {
public var databaseId: String {
return id
}
+
+ public init(id: String, topic: String, message: NotifyMessage, publishedAt: Date) {
+ self.id = id
+ self.topic = topic
+ self.message = message
+ self.publishedAt = publishedAt
+ }
+
+ public init(decoder: SqliteRowDecoder) throws {
+ self.id = try decoder.decodeString(at: 0)
+ self.topic = try decoder.decodeString(at: 1)
+
+ self.message = NotifyMessage(
+ title: try decoder.decodeString(at: 2),
+ body: try decoder.decodeString(at: 3),
+ icon: try decoder.decodeString(at: 4),
+ url: try decoder.decodeString(at: 5),
+ type: try decoder.decodeString(at: 6)
+ )
+
+ self.publishedAt = try decoder.decodeDate(at: 7)
+ }
+
+ public func encode() -> SqliteRowEncoder {
+ var encoder = SqliteRowEncoder()
+ encoder.encodeString(id, for: "id")
+ encoder.encodeString(topic, for: "topic")
+ encoder.encodeString(message.title, for: "title")
+ encoder.encodeString(message.body, for: "body")
+ encoder.encodeString(message.icon, for: "icon")
+ encoder.encodeString(message.url, for: "url")
+ encoder.encodeString(message.type, for: "type")
+ encoder.encodeDate(publishedAt, for: "publishedAt")
+ return encoder
+ }
}
diff --git a/Sources/WalletConnectNotify/Client/Wallet/NotifyStorage.swift b/Sources/WalletConnectNotify/Client/Wallet/NotifyStorage.swift
index ab873dcf1..832e92dc3 100644
--- a/Sources/WalletConnectNotify/Client/Wallet/NotifyStorage.swift
+++ b/Sources/WalletConnectNotify/Client/Wallet/NotifyStorage.swift
@@ -5,17 +5,16 @@ protocol NotifyStoring {
func getAllSubscriptions() -> [NotifySubscription]
func getSubscriptions(account: Account) -> [NotifySubscription]
func getSubscription(topic: String) -> NotifySubscription?
- func setSubscription(_ subscription: NotifySubscription) async throws
- func deleteSubscription(topic: String) async throws
- func clearDatabase(account: Account)
+ func setSubscription(_ subscription: NotifySubscription) throws
+ func deleteSubscription(topic: String) throws
+ func clearDatabase(account: Account) throws
}
final class NotifyStorage: NotifyStoring {
private var publishers = Set()
- private let subscriptionStore: KeyedDatabase
- private let messagesStore: KeyedDatabase
+ private let database: NotifyDatabase
private let newSubscriptionSubject = PassthroughSubject()
private let updateSubscriptionSubject = PassthroughSubject()
@@ -41,9 +40,8 @@ final class NotifyStorage: NotifyStoring {
return subscriptionsSubject.eraseToAnyPublisher()
}
- init(subscriptionStore: KeyedDatabase, messagesStore: KeyedDatabase, accountProvider: NotifyAccountProvider) {
- self.subscriptionStore = subscriptionStore
- self.messagesStore = messagesStore
+ init(database: NotifyDatabase, accountProvider: NotifyAccountProvider) {
+ self.database = database
self.accountProvider = accountProvider
setupSubscriptions()
@@ -52,45 +50,42 @@ final class NotifyStorage: NotifyStoring {
// MARK: Subscriptions
func getAllSubscriptions() -> [NotifySubscription] {
- return subscriptionStore.getAll()
+ return database.getAllSubscriptions()
}
func getSubscriptions(account: Account) -> [NotifySubscription] {
- return subscriptionStore.getAll(for: account.absoluteString)
+ return database.getSubscriptions(account: account)
}
func getSubscription(topic: String) -> NotifySubscription? {
- return subscriptionStore.getAll().first(where: { $0.topic == topic })
+ return database.getSubscription(topic: topic)
}
- func setSubscription(_ subscription: NotifySubscription) {
- subscriptionStore.set(element: subscription, for: subscription.account.absoluteString)
+ func setSubscription(_ subscription: NotifySubscription) throws {
+ try database.save(subscription: subscription)
newSubscriptionSubject.send(subscription)
}
- func replaceAllSubscriptions(_ subscriptions: [NotifySubscription], account: Account) {
- subscriptionStore.replace(elements: subscriptions, for: account.absoluteString)
+ func replaceAllSubscriptions(_ subscriptions: [NotifySubscription]) throws {
+ try database.save(subscriptions: subscriptions)
}
func deleteSubscription(topic: String) throws {
- guard let subscription = getSubscription(topic: topic) else {
- throw Errors.subscriptionNotFound
- }
- subscriptionStore.delete(id: topic, for: subscription.account.absoluteString)
+ try database.deleteSubscription(topic: topic)
deleteSubscriptionSubject.send(topic)
}
- func clearDatabase(account: Account) {
+ func clearDatabase(account: Account) throws {
for subscription in getSubscriptions(account: account) {
- deleteMessages(topic: subscription.topic)
+ try database.deleteMessages(topic: subscription.topic)
}
- subscriptionStore.deleteAll(for: account.absoluteString)
+ try database.deleteSubscription(account: account)
}
- func updateSubscription(_ subscription: NotifySubscription, scope: [String: ScopeValue], expiry: UInt64) {
+ func updateSubscription(_ subscription: NotifySubscription, scope: [String: ScopeValue], expiry: UInt64) throws {
let expiry = Date(timeIntervalSince1970: TimeInterval(expiry))
- let updated = NotifySubscription(topic: subscription.topic, account: subscription.account, relay: subscription.relay, metadata: subscription.metadata, scope: scope, expiry: expiry, symKey: subscription.symKey, appAuthenticationKey: subscription.appAuthenticationKey)
- subscriptionStore.set(element: updated, for: updated.account.absoluteString)
+ let updated = NotifySubscription(subscription: subscription, scope: scope, expiry: expiry)
+ try database.save(subscription: updated)
updateSubscriptionSubject.send(updated)
}
@@ -103,21 +98,19 @@ final class NotifyStorage: NotifyStoring {
}
func getMessages(topic: String) -> [NotifyMessageRecord] {
- return messagesStore.getAll(for: topic)
- .sorted{$0.publishedAt > $1.publishedAt}
+ return database.getMessages(topic: topic)
}
- func deleteMessages(topic: String) {
- messagesStore.deleteAll(for: topic)
+ func deleteMessages(topic: String) throws {
+ try database.deleteMessages(topic: topic)
}
- func deleteMessage(id: String) {
- guard let result = messagesStore.find(id: id) else { return }
- messagesStore.delete(id: id, for: result.key)
+ func deleteMessage(id: String) throws {
+ try database.deleteMessage(id: id)
}
- func setMessage(_ record: NotifyMessageRecord) {
- messagesStore.set(element: record, for: record.topic)
+ func setMessage(_ message: NotifyMessageRecord) throws {
+ try database.save(message: message)
}
}
@@ -128,12 +121,12 @@ private extension NotifyStorage {
}
func setupSubscriptions() {
- messagesStore.onUpdate = { [unowned self] in
- messagesSubject.send(messagesStore.getAll())
+ database.onMessagesUpdate = { [unowned self] in
+ messagesSubject.send(database.getAllMessages())
}
- subscriptionStore.onUpdate = { [unowned self] in
- guard let account = try? accountProvider.getCurrentAccount() else { return }
+ database.onSubscriptionsUpdate = { [unowned self] in
+ let account = try accountProvider.getCurrentAccount()
subscriptionsSubject.send(getSubscriptions(account: account))
}
}
diff --git a/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifyDelete/DeleteNotifySubscriptionRequester.swift b/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifyDelete/DeleteNotifySubscriptionRequester.swift
index a94e86420..b9c86009c 100644
--- a/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifyDelete/DeleteNotifySubscriptionRequester.swift
+++ b/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifyDelete/DeleteNotifySubscriptionRequester.swift
@@ -47,7 +47,7 @@ class DeleteNotifySubscriptionRequester {
try await networkingInteractor.request(request, topic: topic, protocolMethod: protocolMethod)
try notifyStorage.deleteSubscription(topic: topic)
- notifyStorage.deleteMessages(topic: topic)
+ try notifyStorage.deleteMessages(topic: topic)
networkingInteractor.unsubscribe(topic: topic)
diff --git a/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifyMessage/NotifyMessageSubscriber.swift b/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifyMessage/NotifyMessageSubscriber.swift
index 2ebd5125f..9b9a2cd8f 100644
--- a/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifyMessage/NotifyMessageSubscriber.swift
+++ b/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifyMessage/NotifyMessageSubscriber.swift
@@ -38,7 +38,7 @@ class NotifyMessageSubscriber {
let dappPubKey = try DIDKey(did: claims.iss)
let record = NotifyMessageRecord(id: payload.id.string, topic: payload.topic, message: messagePayload.message, publishedAt: payload.publishedAt)
- notifyStorage.setMessage(record)
+ try notifyStorage.setMessage(record)
notifyMessagePublisherSubject.send(record)
let receiptPayload = NotifyMessageReceiptPayload(
diff --git a/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifySubscriptionsChanged/NotifySubscriptionsChangedRequestSubscriber.swift b/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifySubscriptionsChanged/NotifySubscriptionsChangedRequestSubscriber.swift
index 18c8bbc31..a7c9cdd95 100644
--- a/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifySubscriptionsChanged/NotifySubscriptionsChangedRequestSubscriber.swift
+++ b/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifySubscriptionsChanged/NotifySubscriptionsChangedRequestSubscriber.swift
@@ -63,7 +63,7 @@ class NotifySubscriptionsChangedRequestSubscriber {
logger.debug("Received: \(newSubscriptions.count), changed: \(subscriptions.count)")
if subscriptions.count > 0 {
- notifyStorage.replaceAllSubscriptions(newSubscriptions, account: account)
+ try notifyStorage.replaceAllSubscriptions(newSubscriptions)
for subscription in newSubscriptions {
let symKey = try SymmetricKey(hex: subscription.symKey)
diff --git a/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifyWatchSubscriptions/NotifyWatchSubscriptionsResponseSubscriber.swift b/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifyWatchSubscriptions/NotifyWatchSubscriptionsResponseSubscriber.swift
index 55323843e..dccdcbdd7 100644
--- a/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifyWatchSubscriptions/NotifyWatchSubscriptionsResponseSubscriber.swift
+++ b/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_notifyWatchSubscriptions/NotifyWatchSubscriptionsResponseSubscriber.swift
@@ -51,7 +51,7 @@ class NotifyWatchSubscriptionsResponseSubscriber {
if subscriptions.count > 0 {
// TODO: unsubscribe for oldSubscriptions topics that are not included in new subscriptions
- notifyStorage.replaceAllSubscriptions(newSubscriptions, account: account)
+ try notifyStorage.replaceAllSubscriptions(newSubscriptions)
for subscription in newSubscriptions {
let symKey = try SymmetricKey(hex: subscription.symKey)
diff --git a/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_pushSubscribe/NotifySubscribeRequester.swift b/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_pushSubscribe/NotifySubscribeRequester.swift
index 32a875b43..1907d640e 100644
--- a/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_pushSubscribe/NotifySubscribeRequester.swift
+++ b/Sources/WalletConnectNotify/Client/Wallet/ProtocolEngine/wc_pushSubscribe/NotifySubscribeRequester.swift
@@ -36,8 +36,6 @@ class NotifySubscribeRequester {
logger.debug("Subscribing for Notify, dappUrl: \(appDomain)")
- let config = await notifyConfigProvider.resolveNotifyConfig(appDomain: appDomain)
-
let didDoc = try await webDidResolver.resolveDidDoc(appDomain: appDomain)
let peerPublicKey = try webDidResolver.resolveAgreementKey(didDoc: didDoc)
let subscribeTopic = peerPublicKey.rawRepresentation.sha256().toHexString()
diff --git a/Sources/WalletConnectNotify/NotifyImports.swift b/Sources/WalletConnectNotify/NotifyImports.swift
index 74fcfa250..43b543236 100644
--- a/Sources/WalletConnectNotify/NotifyImports.swift
+++ b/Sources/WalletConnectNotify/NotifyImports.swift
@@ -3,4 +3,5 @@
@_exported import WalletConnectPush
@_exported import WalletConnectIdentity
@_exported import WalletConnectSigner
+@_exported import Database
#endif
diff --git a/Sources/WalletConnectNotify/NotifyStorageIdntifiers.swift b/Sources/WalletConnectNotify/NotifyStorageIdntifiers.swift
deleted file mode 100644
index b68272b25..000000000
--- a/Sources/WalletConnectNotify/NotifyStorageIdntifiers.swift
+++ /dev/null
@@ -1,8 +0,0 @@
-import Foundation
-
-enum NotifyStorageIdntifiers {
- static let notifySubscription = "com.walletconnect.notify.notifySubscription"
-
- static let notifyMessagesRecords = "com.walletconnect.sdk.notifyMessagesRecords"
- static let coldStartStore = "com.walletconnect.sdk.coldStartStore"
-}
diff --git a/Sources/WalletConnectNotify/Types/DataStructures/NotifyMessage.swift b/Sources/WalletConnectNotify/Types/DataStructures/NotifyMessage.swift
index 783721bbd..2cd90ad8c 100644
--- a/Sources/WalletConnectNotify/Types/DataStructures/NotifyMessage.swift
+++ b/Sources/WalletConnectNotify/Types/DataStructures/NotifyMessage.swift
@@ -5,9 +5,9 @@ public struct NotifyMessage: Codable, Equatable {
public let body: String
public let icon: String
public let url: String
- public let type: String?
+ public let type: String
- public init(title: String, body: String, icon: String, url: String, type: String? = nil) {
+ public init(title: String, body: String, icon: String, url: String, type: String) {
self.title = title
self.body = body
self.icon = icon
diff --git a/Sources/WalletConnectNotify/Types/DataStructures/NotifySubscription.swift b/Sources/WalletConnectNotify/Types/DataStructures/NotifySubscription.swift
index cb4982555..9a5ac3609 100644
--- a/Sources/WalletConnectNotify/Types/DataStructures/NotifySubscription.swift
+++ b/Sources/WalletConnectNotify/Types/DataStructures/NotifySubscription.swift
@@ -1,6 +1,7 @@
import Foundation
+import Database
-public struct NotifySubscription: DatabaseObject {
+public struct NotifySubscription: DatabaseObject, SqliteRow {
public let topic: String
public let account: Account
public let relay: RelayProtocolOptions
@@ -13,6 +14,52 @@ public struct NotifySubscription: DatabaseObject {
public var databaseId: String {
return topic
}
+
+ public init(decoder: SqliteRowDecoder) throws {
+ self.topic = try decoder.decodeString(at: 0)
+ self.account = try Account(decoder.decodeString(at: 1))!
+ self.relay = try decoder.decodeCodable(at: 2)
+ self.metadata = try decoder.decodeCodable(at: 3)
+ self.scope = try decoder.decodeCodable(at: 4)
+ self.expiry = try decoder.decodeDate(at: 5)
+ self.symKey = try decoder.decodeString(at: 6)
+ self.appAuthenticationKey = try decoder.decodeString(at: 7)
+ }
+
+ public func encode() -> SqliteRowEncoder {
+ var encoder = SqliteRowEncoder()
+ encoder.encodeString(topic, for: "topic")
+ encoder.encodeString(account.absoluteString, for: "account")
+ encoder.encodeCodable(relay, for: "relay")
+ encoder.encodeCodable(metadata, for: "metadata")
+ encoder.encodeCodable(scope, for: "scope")
+ encoder.encodeDate(expiry, for: "expiry")
+ encoder.encodeString(symKey, for: "symKey")
+ encoder.encodeString(appAuthenticationKey, for: "appAuthenticationKey")
+ return encoder
+ }
+
+ init(topic: String, account: Account, relay: RelayProtocolOptions, metadata: AppMetadata, scope: [String : ScopeValue], expiry: Date, symKey: String, appAuthenticationKey: String) {
+ self.topic = topic
+ self.account = account
+ self.relay = relay
+ self.metadata = metadata
+ self.scope = scope
+ self.expiry = expiry
+ self.symKey = symKey
+ self.appAuthenticationKey = appAuthenticationKey
+ }
+
+ init(subscription: NotifySubscription, scope: [String : ScopeValue], expiry: Date) {
+ self.topic = subscription.topic
+ self.account = subscription.account
+ self.relay = subscription.relay
+ self.metadata = subscription.metadata
+ self.symKey = subscription.symKey
+ self.appAuthenticationKey = subscription.appAuthenticationKey
+ self.scope = scope
+ self.expiry = expiry
+ }
}
public struct ScopeValue: Codable, Equatable {
diff --git a/Sources/WalletConnectRelay/PackageConfig.json b/Sources/WalletConnectRelay/PackageConfig.json
index ae47f4ee5..f828972fc 100644
--- a/Sources/WalletConnectRelay/PackageConfig.json
+++ b/Sources/WalletConnectRelay/PackageConfig.json
@@ -1 +1 @@
-{"version": "1.9.5"}
+{"version": "1.9.6"}
diff --git a/Sources/WalletConnectRouter/Router/Router.swift b/Sources/WalletConnectRouter/Router/Router.swift
index b97566675..75a227b31 100644
--- a/Sources/WalletConnectRouter/Router/Router.swift
+++ b/Sources/WalletConnectRouter/Router/Router.swift
@@ -1,7 +1,5 @@
import UIKit
-@_exported import WalletConnectRouter
-
public struct WalletConnectRouter {
public static func goBack(uri: String) {
if #available(iOS 17, *) {
diff --git a/Sources/WalletConnectRouter/Router/RouterImports.swift b/Sources/WalletConnectRouter/Router/RouterImports.swift
new file mode 100644
index 000000000..e2e65b0f9
--- /dev/null
+++ b/Sources/WalletConnectRouter/Router/RouterImports.swift
@@ -0,0 +1,3 @@
+#if !CocoaPods
+@_exported import WalletConnectRouter
+#endif
diff --git a/Tests/NotifyTests/Mocks/MockNotifyStoring.swift b/Tests/NotifyTests/Mocks/MockNotifyStoring.swift
index bd773936c..e5df4531f 100644
--- a/Tests/NotifyTests/Mocks/MockNotifyStoring.swift
+++ b/Tests/NotifyTests/Mocks/MockNotifyStoring.swift
@@ -21,7 +21,7 @@ class MockNotifyStoring: NotifyStoring {
return subscriptions
}
- func setSubscription(_ subscription: NotifySubscription) async throws {
+ func setSubscription(_ subscription: NotifySubscription) {
if let index = subscriptions.firstIndex(where: { $0.topic == subscription.topic }) {
subscriptions[index] = subscription
} else {
@@ -33,7 +33,7 @@ class MockNotifyStoring: NotifyStoring {
subscriptions = subscriptions.filter { $0.account != account }
}
- func deleteSubscription(topic: String) async throws {
+ func deleteSubscription(topic: String) throws {
subscriptions.removeAll(where: { $0.topic == topic })
}
}
diff --git a/WalletConnectSwiftV2.podspec b/WalletConnectSwiftV2.podspec
index cc6ab4f3d..29cf98ffe 100644
--- a/WalletConnectSwiftV2.podspec
+++ b/WalletConnectSwiftV2.podspec
@@ -189,4 +189,10 @@ Pod::Spec.new do |spec|
spec.subspec 'HTTPClient' do |ss|
ss.source_files = 'Sources/HTTPClient/**/*.{h,m,swift}'
end
+
+ spec.subspec 'WalletConnectModal' do |ss|
+ ss.source_files = 'Sources/WalletConnectModal/**/*.{h,m,swift}'
+ ss.dependency 'WalletConnectSwiftV2/WalletConnectSign'
+ ss.dependency 'DSF_QRCode', '~> 16.1.1'
+ end
end