diff --git a/Package.swift b/Package.swift
index f5678619dec83e0af6ca965e92d6303b0bc6f373..b74da3460ef87448c09191338411819e7b5e5a0b 100644
--- a/Package.swift
+++ b/Package.swift
@@ -23,7 +23,6 @@ let package = Package(
         .library(name: "ScanFeature", targets: ["ScanFeature"]),
         .library(name: "Permissions", targets: ["Permissions"]),
         .library(name: "MenuFeature", targets: ["MenuFeature"]),
-        .library(name: "Integration", targets: ["Integration"]),
         .library(name: "ChatFeature", targets: ["ChatFeature"]),
         .library(name: "PushFeature", targets: ["PushFeature"]),
         .library(name: "SFTPFeature", targets: ["SFTPFeature"]),
@@ -115,6 +114,10 @@ let package = Package(
             url: "https://github.com/google/google-api-objectivec-client-for-rest",
             .upToNextMajor(from: "1.6.0")
         ),
+        .package(
+            url: "https://git.xx.network/elixxir/elixxir-dapps-sdk-swift",
+            branch: "development"
+        ),
         .package(
             url: "https://git.xx.network/elixxir/client-ios-db.git",
             .upToNextMajor(from: "1.1.0")
@@ -207,10 +210,6 @@ let package = Package(
                 .target(name: "Shared"),
             ]
         ),
-        .binaryTarget(
-            name: "Bindings",
-            path: "XCFrameworks/Bindings.xcframework"
-        ),
         .target(
             name: "Permissions",
             dependencies: [
@@ -224,8 +223,8 @@ let package = Package(
             dependencies: [
                 .target(name: "Models"),
                 .target(name: "Defaults"),
-                .target(name: "Integration"),
                 .target(name: "DependencyInjection"),
+                .product(name: "XXDatabase", package: "client-ios-db"),
             ]
         ),
         .target(
@@ -373,26 +372,6 @@ let package = Package(
                 .process("Resources"),
             ]
         ),
-        .target(
-            name: "Integration",
-            dependencies: [
-                .target(name: "Shared"),
-                .target(name: "Bindings"),
-                .target(name: "XXLogger"),
-                .target(name: "Keychain"),
-                .target(name: "ToastFeature"),
-                .target(name: "BackupFeature"),
-                .target(name: "CrashReporting"),
-                .target(name: "NetworkMonitor"),
-                .target(name: "DependencyInjection"),
-                .product(name: "Retry", package: "Retry"),
-                .product(name: "XXDatabase", package: "client-ios-db"),
-                .product(name: "XXLegacyDatabaseMigrator", package: "client-ios-db"),
-            ],
-            resources: [
-                .process("Resources"),
-            ]
-        ),
         .target(
             name: "Presentation",
             dependencies: [
@@ -422,12 +401,16 @@ let package = Package(
                 .target(name: "HUD"),
                 .target(name: "Shared"),
                 .target(name: "SFTPFeature"),
-                .target(name: "Integration"),
                 .target(name: "Presentation"),
                 .target(name: "iCloudFeature"),
+                .target(name: "BackupFeature"),
                 .target(name: "DropboxFeature"),
                 .target(name: "GoogleDriveFeature"),
                 .target(name: "DependencyInjection"),
+                .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"),
+            ],
+            resources: [
+                .process("Resources"),
             ]
         ),
         .target(
@@ -459,7 +442,6 @@ let package = Package(
                 .target(name: "Defaults"),
                 .target(name: "Keychain"),
                 .target(name: "Voxophone"),
-                .target(name: "Integration"),
                 .target(name: "Permissions"),
                 .target(name: "Presentation"),
                 .target(name: "DrawerFeature"),
@@ -486,10 +468,11 @@ let package = Package(
                 .target(name: "HUD"),
                 .target(name: "Shared"),
                 .target(name: "Countries"),
-                .target(name: "Integration"),
                 .target(name: "Presentation"),
                 .target(name: "ContactFeature"),
+                .target(name: "NetworkMonitor"),
                 .target(name: "DependencyInjection"),
+                .product(name: "XXDatabase", package: "client-ios-db"),
             ]
         ),
         .testTarget(
@@ -509,12 +492,17 @@ let package = Package(
                 .target(name: "Shared"),
                 .target(name: "Defaults"),
                 .target(name: "PushFeature"),
-                .target(name: "Integration"),
                 .target(name: "Permissions"),
                 .target(name: "DropboxFeature"),
                 .target(name: "VersionChecking"),
                 .target(name: "ReportingFeature"),
                 .target(name: "DependencyInjection"),
+                .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"),
+                .product(name: "CombineSchedulers", package: "combine-schedulers"),
+                .product(name: "XXLegacyDatabaseMigrator", package: "client-ios-db"),
+            ],
+            resources: [
+                .process("Resources"),
             ]
         ),
         .target(
@@ -531,7 +519,6 @@ let package = Package(
             dependencies: [
                 .target(name: "Theme"),
                 .target(name: "Shared"),
-                .target(name: "Integration"),
                 .target(name: "ToastFeature"),
                 .target(name: "ContactFeature"),
                 .target(name: "DependencyInjection"),
@@ -559,7 +546,6 @@ let package = Package(
                 .target(name: "InputField"),
                 .target(name: "MenuFeature"),
                 .target(name: "Permissions"),
-                .target(name: "Integration"),
                 .target(name: "Presentation"),
                 .target(name: "DrawerFeature"),
                 .target(name: "DependencyInjection"),
@@ -611,13 +597,15 @@ let package = Package(
                 .target(name: "InputField"),
                 .target(name: "Permissions"),
                 .target(name: "PushFeature"),
-                .target(name: "Integration"),
                 .target(name: "Presentation"),
                 .target(name: "DrawerFeature"),
                 .target(name: "VersionChecking"),
                 .target(name: "DependencyInjection"),
                 .product(name: "CombineSchedulers", package: "combine-schedulers"),
                 .product(name: "ScrollViewController", package: "ScrollViewController"),
+            ],
+            resources: [
+                .process("Resources"),
             ]
         ),
         .testTarget(
@@ -635,8 +623,8 @@ let package = Package(
                 .target(name: "Theme"),
                 .target(name: "Shared"),
                 .target(name: "Defaults"),
-                .target(name: "Integration"),
                 .target(name: "Presentation"),
+                .target(name: "DrawerFeature"),
                 .target(name: "DependencyInjection"),
             ]
         ),
@@ -663,9 +651,9 @@ let package = Package(
                 .target(name: "Shared"),
                 .target(name: "Countries"),
                 .target(name: "Permissions"),
-                .target(name: "Integration"),
                 .target(name: "Presentation"),
                 .target(name: "ContactFeature"),
+                .target(name: "NetworkMonitor"),
                 .target(name: "DependencyInjection"),
                 .product(name: "SnapKit", package: "SnapKit"),
             ]
@@ -684,7 +672,6 @@ let package = Package(
             dependencies: [
                 .target(name: "Theme"),
                 .target(name: "Shared"),
-                .target(name: "Integration"),
                 .target(name: "Presentation"),
                 .target(name: "ContactFeature"),
                 .target(name: "DependencyInjection"),
@@ -708,11 +695,11 @@ let package = Package(
                 .target(name: "Shared"),
                 .target(name: "Defaults"),
                 .target(name: "Keychain"),
+                .target(name: "XXLogger"),
                 .target(name: "InputField"),
                 .target(name: "PushFeature"),
                 .target(name: "Permissions"),
                 .target(name: "MenuFeature"),
-                .target(name: "Integration"),
                 .target(name: "Presentation"),
                 .target(name: "DrawerFeature"),
                 .target(name: "DependencyInjection"),
diff --git a/Sources/App/AppDelegate.swift b/Sources/App/AppDelegate.swift
index 4143a5f270c7179e9f11892702bf7f7db79a6800..282e857220c9d718beb543c39ff4d988d6df94a9 100644
--- a/Sources/App/AppDelegate.swift
+++ b/Sources/App/AppDelegate.swift
@@ -5,7 +5,6 @@ import Theme
 import XXModels
 import XXLogger
 import Defaults
-import Integration
 import PushFeature
 import ToastFeature
 import SwiftyDropbox
@@ -14,6 +13,8 @@ import DropboxFeature
 import CrashReporting
 import DependencyInjection
 
+import XXClient
+
 public class AppDelegate: UIResponder, UIApplicationDelegate {
     @Dependency private var pushRouter: PushRouter
     @Dependency private var pushHandler: PushHandling
@@ -69,7 +70,8 @@ public class AppDelegate: UIResponder, UIApplicationDelegate {
     }
 
     public func applicationDidEnterBackground(_ application: UIApplication) {
-        if let session = try? DependencyInjection.Container.shared.resolve() as SessionType {
+        if let cMix: CMix = try? DependencyInjection.Container.shared.resolve(),
+           let database: Database = try? DependencyInjection.Container.shared.resolve() {
             let backgroundTask = application.beginBackgroundTask(withName: "xx.stop.network") {}
 
             // An option here would be: create async completion closure
@@ -78,9 +80,9 @@ public class AppDelegate: UIResponder, UIApplicationDelegate {
                 guard UIApplication.shared.backgroundTimeRemaining > 8 else {
                     if !self.calledStopNetwork {
                         self.calledStopNetwork = true
-                        session.stop()
+                        try! cMix.stopNetworkFollower()
                     } else {
-                        if session.hasRunningTasks == false {
+                        if cMix.hasRunningProcesses() == false {
                             application.endBackgroundTask(backgroundTask)
                             timer.invalidate()
                         }
@@ -95,7 +97,7 @@ public class AppDelegate: UIResponder, UIApplicationDelegate {
 
                         let query = Message.Query(status: [.sending])
                         let assignment = Message.Assignments(status: .sendingFailed)
-                        _ = try? session.dbManager.bulkUpdateMessages(query, assignment)
+                        _ = try? database.bulkUpdateMessages(query, assignment)
                     }
 
                     return
@@ -114,8 +116,8 @@ public class AppDelegate: UIResponder, UIApplicationDelegate {
     }
     
     public func applicationWillTerminate(_ application: UIApplication) {
-        if let session = try? DependencyInjection.Container.shared.resolve() as SessionType {
-            session.stop()
+        if let cMix: CMix = try? DependencyInjection.Container.shared.resolve() {
+            try? cMix.stopNetworkFollower()
         }
     }
 
@@ -125,9 +127,9 @@ public class AppDelegate: UIResponder, UIApplicationDelegate {
             backgroundTimer = nil
         }
 
-        if let session = try? DependencyInjection.Container.shared.resolve() as SessionType {
+        if let cMix: CMix = try? DependencyInjection.Container.shared.resolve() {
             guard self.calledStopNetwork == true else { return }
-            session.start()
+            try? cMix.startNetworkFollower(timeoutMS: 10_000)
             self.calledStopNetwork = false
         }
     }
diff --git a/Sources/App/DependencyRegistrator.swift b/Sources/App/DependencyRegistrator.swift
index 182ac2f5dbe6af2ee532e45b08e9b73d49a1e0a8..026bfd56440502e4597d9cb00d2e8a4bb4000b75 100644
--- a/Sources/App/DependencyRegistrator.swift
+++ b/Sources/App/DependencyRegistrator.swift
@@ -15,7 +15,6 @@ import Keychain
 import Defaults
 import Countries
 import Voxophone
-import Integration
 import Permissions
 import PushFeature
 import SFTPFeature
@@ -48,6 +47,9 @@ import RequestsFeature
 import OnboardingFeature
 import ContactListFeature
 
+import KeychainAccess
+import XXClient
+
 struct DependencyRegistrator {
     static private let container = DependencyInjection.Container.shared
 
@@ -59,7 +61,6 @@ struct DependencyRegistrator {
         container.register(VersionChecker.mock)
         container.register(ReportingStatus.mock())
         container.register(SendReport.mock())
-        container.register(XXNetwork<BindingsMock>() as XXNetworking)
         container.register(MockNetworkMonitor() as NetworkMonitoring)
         container.register(KeyObjectStore.userDefaults)
         container.register(MockPushHandler() as PushHandling)
@@ -79,6 +80,12 @@ struct DependencyRegistrator {
     // MARK: LIVE
 
     static func registerForLive() {
+        let cMixManager = CMixManager.live(passwordStorage: .keychain)
+        container.register(cMixManager)
+
+        container.register(GetIdFromContact.live)
+        container.register(GetFactsFromContact.live)
+
         container.register(KeyObjectStore.userDefaults)
         container.register(XXLogger.live())
         container.register(CrashReporter.live)
@@ -86,7 +93,6 @@ struct DependencyRegistrator {
         container.register(ReportingStatus.live())
         container.register(SendReport.live)
 
-        container.register(XXNetwork<BindingsClient>() as XXNetworking)
         container.register(NetworkMonitor() as NetworkMonitoring)
         container.register(PushHandler() as PushHandling)
         container.register(KeychainHandler() as KeychainHandling)
@@ -134,7 +140,7 @@ struct DependencyRegistrator {
                 searchFactory: SearchContainerController.init,
                 requestsFactory: RequestsContainerController.init,
                 chatListFactory: ChatListController.init,
-                onboardingFactory: OnboardingStartController.init(_:),
+                onboardingFactory: OnboardingStartController.init,
                 singleChatFactory: SingleChatController.init(_:),
                 groupChatFactory: GroupChatController.init(_:)
             ) as LaunchCoordinating)
@@ -185,7 +191,7 @@ struct DependencyRegistrator {
             RestoreCoordinator(
                 successFactory: RestoreSuccessController.init,
                 chatListFactory: ChatListController.init,
-                restoreFactory: RestoreController.init(_:_:),
+                restoreFactory: RestoreController.init(_:),
                 passphraseFactory: RestorePassphraseController.init(_:)
             ) as RestoreCoordinating)
 
@@ -224,9 +230,9 @@ struct DependencyRegistrator {
                 searchFactory: SearchContainerController.init,
                 welcomeFactory: OnboardingWelcomeController.init,
                 chatListFactory: ChatListController.init,
-                termsFactory: TermsConditionsController.init(_:),
-                usernameFactory: OnboardingUsernameController.init(_:),
-                restoreListFactory: RestoreListController.init(_:),
+                termsFactory: TermsConditionsController.init,
+                usernameFactory: OnboardingUsernameController.init,
+                restoreListFactory: RestoreListController.init,
                 successFactory: OnboardingSuccessController.init(_:),
                 countriesFactory: CountryListController.init(_:),
                 phoneConfirmationFactory: OnboardingPhoneConfirmationController.init(_:_:),
@@ -270,3 +276,15 @@ struct DependencyRegistrator {
             ) as ChatListCoordinating)
     }
 }
+
+extension PasswordStorage {
+    static let keychain: PasswordStorage = {
+        let keychain = KeychainAccess.Keychain(
+            service: "XXM"
+        )
+        return PasswordStorage(
+            save: { password in keychain[data: "password"] = password},
+            load: { try keychain[data: "password"] ?? { throw MissingPasswordError() }() }
+        )
+    }()
+}
diff --git a/Sources/App/PushRouter.swift b/Sources/App/PushRouter.swift
index a2d2d809d54818566c1aec693ed4ad07937c6999..4e1e432362954af9030921e9813676d7b3471af9 100644
--- a/Sources/App/PushRouter.swift
+++ b/Sources/App/PushRouter.swift
@@ -1,12 +1,12 @@
 import UIKit
 import PushFeature
-import Integration
 import ChatFeature
 import SearchFeature
 import LaunchFeature
 import ChatListFeature
 import RequestsFeature
 import DependencyInjection
+import XXModels
 
 extension PushRouter {
     static func live(navigationController: UINavigationController) -> PushRouter {
@@ -20,24 +20,23 @@ extension PushRouter {
                         navigationController.setViewControllers([RequestsContainerController()], animated: true)
                     }
                 case .search(username: let username):
-                    if let _ = try? DependencyInjection.Container.shared.resolve() as SessionType,
-                       !(navigationController.viewControllers.last is SearchContainerController) {
+                    if !(navigationController.viewControllers.last is SearchContainerController) {
                         navigationController.setViewControllers([
                             ChatListController(),
                             SearchContainerController(username)
                         ], animated: true)
                     }
                 case .contactChat(id: let id):
-                    if let session = try? DependencyInjection.Container.shared.resolve() as SessionType,
-                       let contact = try? session.dbManager.fetchContacts(.init(id: [id])).first {
+                    if let database: Database = try? DependencyInjection.Container.shared.resolve(),
+                       let contact = try? database.fetchContacts(.init(id: [id])).first {
                         navigationController.setViewControllers([
                             ChatListController(),
                             SingleChatController(contact)
                         ], animated: true)
                     }
                 case .groupChat(id: let id):
-                    if let session = try? DependencyInjection.Container.shared.resolve() as SessionType,
-                       let info = try? session.dbManager.fetchGroupInfos(.init(groupId: id)).first {
+                    if let database: Database = try? DependencyInjection.Container.shared.resolve(),
+                       let info = try? database.fetchGroupInfos(.init(groupId: id)).first {
                         navigationController.setViewControllers([
                             ChatListController(),
                             GroupChatController(info)
diff --git a/Sources/ChatFeature/ViewModels/GroupChatViewModel.swift b/Sources/ChatFeature/ViewModels/GroupChatViewModel.swift
index 1dbce8a895ebfeabceb5900d3e5d258bcfb31199..15754255d38b1ceba68ffd9ee2b20a815b493516 100644
--- a/Sources/ChatFeature/ViewModels/GroupChatViewModel.swift
+++ b/Sources/ChatFeature/ViewModels/GroupChatViewModel.swift
@@ -6,25 +6,34 @@ import Combine
 import XXModels
 import Defaults
 import Foundation
-import Integration
 import ToastFeature
 import DifferenceKit
 import ReportingFeature
 import DependencyInjection
 
+import struct XXModels.Message
+import XXClient
+
 enum GroupChatNavigationRoutes: Equatable {
     case waitingRound
     case webview(String)
 }
 
 final class GroupChatViewModel {
-    @Dependency private var session: SessionType
-    @Dependency private var sendReport: SendReport
-    @Dependency private var reportingStatus: ReportingStatus
-    @Dependency private var toastController: ToastController
+    @Dependency var cMix: CMix
+    @Dependency var database: Database
+    @Dependency var sendReport: SendReport
+    @Dependency var groupManager: GroupChat
+    @Dependency var userDiscovery: UserDiscovery
+    @Dependency var reportingStatus: ReportingStatus
+    @Dependency var toastController: ToastController
 
     @KeyObject(.username, defaultValue: nil) var username: String?
 
+    var myId: Data {
+        try! GetIdFromContact.live(userDiscovery.getContact())
+    }
+
     var hudPublisher: AnyPublisher<HUDStatus, Never> {
         hudSubject.eraseToAnyPublisher()
     }
@@ -50,7 +59,7 @@ final class GroupChatViewModel {
     private let routesSubject = PassthroughSubject<GroupChatNavigationRoutes, Never>()
 
     var messages: AnyPublisher<[ArraySection<ChatSection, Message>], Never> {
-        session.dbManager.fetchMessagesPublisher(.init(chat: .group(info.group.id)))
+        database.fetchMessagesPublisher(.init(chat: .group(info.group.id)))
             .assertNoFailure()
             .map { messages -> [ArraySection<ChatSection, Message>] in
                 let groupedByDate = Dictionary(grouping: messages) { domainModel -> Date in
@@ -76,11 +85,11 @@ final class GroupChatViewModel {
     func readAll() {
         let assignment = Message.Assignments(isUnread: false)
         let query = Message.Query(chat: .group(info.group.id))
-        _ = try? session.dbManager.bulkUpdateMessages(query, assignment)
+        _ = try? database.bulkUpdateMessages(query, assignment)
     }
 
     func didRequestDelete(_ messages: [Message]) {
-        _ = try? session.dbManager.deleteMessages(.init(id: Set(messages.map(\.id))))
+        _ = try? database.deleteMessages(.init(id: Set(messages.map(\.id))))
     }
 
     func didRequestReport(_ message: Message) {
@@ -90,16 +99,109 @@ final class GroupChatViewModel {
     }
 
     func send(_ text: String) {
-        session.send(.init(
+        var message = Message(
+            senderId: myId,
+            recipientId: nil,
+            groupId: info.group.id,
+            date: Date(),
+            status: .sending,
+            isUnread: false,
             text: text.trimmingCharacters(in: .whitespacesAndNewlines),
-            reply: stagedReply
-        ), toGroup: info.group)
+            replyMessageId: stagedReply?.messageId
+        )
+
+        do {
+            try database.saveMessage(message)
+
+            let report = try groupManager.send(
+                groupId: info.group.id,
+                message: Payload(
+                    text: text.trimmingCharacters(in: .whitespacesAndNewlines),
+                    reply: stagedReply
+                ).asData()
+            )
+
+            try cMix.waitForRoundResult(
+                roundList: try report.encode(),
+                timeoutMS: 5_000,
+                callback: .init(handle: {
+                    switch $0 {
+                    case .delivered:
+                        message.status = .sent
+                        _ = try? self.database.saveMessage(message)
+
+                    case .notDelivered(timedOut: let timedOut):
+                        if timedOut {
+                            message.status = .sendingTimedOut
+                        } else {
+                            message.status = .sendingFailed
+                        }
+
+                        _ = try? self.database.saveMessage(message)
+                    }
+                })
+            )
+
+            message.networkId = report.messageId
+            message.date = Date.fromTimestamp(Int(report.timestamp))
+            try database.saveMessage(message)
+        } catch {
+            message.status = .sendingFailed
+            _ = try? database.saveMessage(message)
+        }
+
         stagedReply = nil
     }
 
     func retry(_ message: Message) {
-        guard let id = message.id else { return }
-        session.retryMessage(id)
+        var message = message
+
+        do {
+            message.status = .sending
+            message = try database.saveMessage(message)
+
+            var reply: Reply?
+
+            if let replyId = message.replyMessageId {
+                reply = Reply(messageId: replyId, senderId: myId)
+            }
+
+            let report = try groupManager.send(
+                groupId: message.groupId!,
+                message: Payload(
+                    text: message.text,
+                    reply: reply
+                ).asData()
+            )
+
+            try cMix.waitForRoundResult(
+                roundList: try report.encode(),
+                timeoutMS: 5_000,
+                callback: .init(handle: {
+                    switch $0 {
+                    case .delivered:
+                        message.status = .sent
+                        _ = try? self.database.saveMessage(message)
+
+                    case .notDelivered(timedOut: let timedOut):
+                        if timedOut {
+                            message.status = .sendingTimedOut
+                        } else {
+                            message.status = .sendingFailed
+                        }
+
+                        _ = try? self.database.saveMessage(message)
+                    }
+                })
+            )
+
+            message.networkId = report.messageId
+            message.date = Date.fromTimestamp(Int(report.timestamp))
+            message = try database.saveMessage(message)
+        } catch {
+            message.status = .sendingFailed
+            _ = try? database.saveMessage(message)
+        }
     }
 
     func showRoundFrom(_ roundURL: String?) {
@@ -115,7 +217,7 @@ final class GroupChatViewModel {
     }
 
     func getReplyContent(for messageId: Data) -> (String, String) {
-        guard let message = try? session.dbManager.fetchMessages(.init(networkId: messageId)).first else {
+        guard let message = try? database.fetchMessages(.init(networkId: messageId)).first else {
             return ("[DELETED]", "[DELETED]")
         }
 
@@ -123,9 +225,9 @@ final class GroupChatViewModel {
     }
 
     func getName(from senderId: Data) -> String {
-        guard senderId != session.myId else { return "You" }
+        guard senderId != myId else { return "You" }
 
-        guard let contact = try? session.dbManager.fetchContacts(.init(id: [senderId])).first else {
+        guard let contact = try? database.fetchContacts(.init(id: [senderId])).first else {
             return "[DELETED]"
         }
 
diff --git a/Sources/ChatFeature/ViewModels/SingleChatViewModel.swift b/Sources/ChatFeature/ViewModels/SingleChatViewModel.swift
index 8ba933ad52ff63b6beca403e84bd688ccb043ac9..3593e3da61ec3c4be761455e58cdb4bd37bcf902 100644
--- a/Sources/ChatFeature/ViewModels/SingleChatViewModel.swift
+++ b/Sources/ChatFeature/ViewModels/SingleChatViewModel.swift
@@ -5,15 +5,17 @@ import Shared
 import Combine
 import XXLogger
 import XXModels
+import XXClient
 import Foundation
-import Integration
-import Defaults
 import Permissions
 import ToastFeature
 import DifferenceKit
 import ReportingFeature
 import DependencyInjection
 
+import struct XXModels.Message
+import struct XXModels.FileTransfer
+
 enum SingleChatNavigationRoutes: Equatable {
     case none
     case camera
@@ -26,11 +28,15 @@ enum SingleChatNavigationRoutes: Equatable {
 }
 
 final class SingleChatViewModel: NSObject {
-    @Dependency private var logger: XXLogger
-    @Dependency private var session: SessionType
-    @Dependency private var permissions: PermissionHandling
-    @Dependency private var toastController: ToastController
-    @Dependency private var sendReport: SendReport
+    @Dependency var e2e: E2E
+    @Dependency var cMix: CMix
+    @Dependency var logger: XXLogger
+    @Dependency var database: Database
+    @Dependency var sendReport: SendReport
+    @Dependency var userDiscovery: UserDiscovery
+    @Dependency var permissions: PermissionHandling
+    @Dependency var toastController: ToastController
+    @Dependency var transferManager: XXClient.FileTransfer
 
     @KeyObject(.username, defaultValue: nil) var username: String?
 
@@ -46,7 +52,15 @@ final class SingleChatViewModel: NSObject {
     var hud: AnyPublisher<HUDStatus, Never> { hudRelay.eraseToAnyPublisher() }
     private let hudRelay = CurrentValueSubject<HUDStatus, Never>(.none)
 
-    var isOnline: AnyPublisher<Bool, Never> { session.isOnline }
+    var isOnline: AnyPublisher<Bool, Never> {
+        // TO REFACTOR:
+        Just(.init(true)).eraseToAnyPublisher()
+    }
+
+    var myId: Data {
+        try! GetIdFromContact.live(userDiscovery.getContact())
+    }
+
     var contactPublisher: AnyPublisher<Contact, Never> { contactSubject.eraseToAnyPublisher() }
     var replyPublisher: AnyPublisher<(String, String), Never> { replySubject.eraseToAnyPublisher() }
     var navigation: AnyPublisher<SingleChatNavigationRoutes, Never> { navigationRoutes.eraseToAnyPublisher() }
@@ -68,7 +82,7 @@ final class SingleChatViewModel: NSObject {
         if contact.isRecent == true {
             var contact = contact
             contact.isRecent = false
-            _ = try? session.dbManager.saveContact(contact)
+            _ = try? database.saveContact(contact)
         }
     }
 
@@ -82,13 +96,13 @@ final class SingleChatViewModel: NSObject {
 
         updateRecentState(contact)
 
-        session.dbManager.fetchContactsPublisher(Contact.Query(id: [contact.id]))
+        database.fetchContactsPublisher(Contact.Query(id: [contact.id]))
             .assertNoFailure()
             .compactMap { $0.first }
             .sink { [unowned self] in contactSubject.send($0) }
             .store(in: &cancellables)
 
-        session.dbManager.fetchMessagesPublisher(.init(chat: .direct(session.myId, contact.id)))
+        database.fetchMessagesPublisher(.init(chat: .direct(myId, contact.id)))
             .assertNoFailure()
             .map {
                 let groupedByDate = Dictionary(grouping: $0) { domainModel -> Date in
@@ -107,7 +121,7 @@ final class SingleChatViewModel: NSObject {
     // MARK: Public
 
     func getFileTransferWith(id: Data) -> FileTransfer {
-        guard let transfer = try? session.dbManager.fetchFileTransfers(.init(id: [id])).first else {
+        guard let transfer = try? database.fetchFileTransfers(.init(id: [id])).first else {
             fatalError()
         }
 
@@ -115,36 +129,133 @@ final class SingleChatViewModel: NSObject {
     }
 
     func didSendAudio(url: URL) {
-        session.sendFile(url: url, to: contact)
+        do {
+            let transferId = try transferManager.send(
+                params: .init(
+                    payload: .init(
+                        name: "",
+                        type: "",
+                        preview: Data(),
+                        contents: Data()
+                    ),
+                    recipientId: contact.id,
+                    paramsJSON: Data(),
+                    retry: 1,
+                    period: ""
+                ),
+                callback: .init(handle: {
+                    switch $0 {
+                    case .success(let progressCallback):
+                        print(progressCallback.progress.total)
+                    case .failure(let error):
+                        print(error.localizedDescription)
+                    }
+                })
+            )
+
+            // transferId
+        } catch {
+
+        }
     }
 
     func didSend(image: UIImage) {
         guard let imageData = image.orientedUp().jpegData(compressionQuality: 1.0) else { return }
         hudRelay.send(.on)
 
-        session.send(imageData: imageData, to: contact) { [weak self] in
-            switch $0 {
-            case .success:
-                self?.hudRelay.send(.none)
-            case .failure(let error):
-                self?.hudRelay.send(.error(.init(with: error)))
-            }
+        do {
+            let transferId = try transferManager.send(
+                params: .init(
+                    payload: .init(
+                        name: "",
+                        type: "",
+                        preview: Data(),
+                        contents: Data()
+                    ),
+                    recipientId: Data(),
+                    paramsJSON: Data(),
+                    retry: 1,
+                    period: ""
+                ),
+                callback: .init(handle: {
+                    switch $0 {
+                    case .success(let progressCallback):
+                        print(progressCallback.progress.total)
+                    case .failure(let error):
+                        print(error.localizedDescription)
+                    }
+                })
+            )
+        } catch {
+             // self?.hudRelay.send(.error(.init(with: error)))
         }
     }
 
     func readAll() {
         let assignment = Message.Assignments(isUnread: false)
-        let query = Message.Query(chat: .direct(session.myId, contact.id))
-        _ = try? session.dbManager.bulkUpdateMessages(query, assignment)
+        let query = Message.Query(chat: .direct(myId, contact.id))
+        _ = try? database.bulkUpdateMessages(query, assignment)
     }
 
     func didRequestDeleteAll() {
-        _ = try? session.dbManager.deleteMessages(.init(chat: .direct(session.myId, contact.id)))
+        _ = try? database.deleteMessages(.init(chat: .direct(myId, contact.id)))
     }
 
     func didRequestRetry(_ message: Message) {
-        guard let id = message.id else { return }
-        session.retryMessage(id)
+        var message = message
+
+        do {
+            message.status = .sending
+            message = try database.saveMessage(message)
+
+            var reply: Reply?
+
+            if let replyId = message.replyMessageId {
+                reply = Reply(messageId: replyId, senderId: myId)
+            }
+
+            let report = try e2e.send(
+                messageType: 2,
+                recipientId: contact.id,
+                payload: Payload(
+                    text: message.text,
+                    reply: reply
+                ).asData(),
+                e2eParams: GetE2EParams.liveDefault()
+            )
+
+            try cMix.waitForRoundResult(
+                roundList: try report.encode(),
+                timeoutMS: 5_000,
+                callback: .init(handle: {
+                    switch $0 {
+                    case .delivered:
+                        message.status = .sent
+                        _ = try? self.database.saveMessage(message)
+
+                    case .notDelivered(timedOut: let timedOut):
+                        if timedOut {
+                            message.status = .sendingTimedOut
+                        } else {
+                            message.status = .sendingFailed
+                        }
+
+                        _ = try? self.database.saveMessage(message)
+                    }
+                })
+            )
+
+            message.networkId = report.messageId
+            if let timestamp = report.timestamp {
+                message.date = Date.fromTimestamp(Int(timestamp))
+            }
+
+            message = try database.saveMessage(message)
+        } catch {
+            print(error.localizedDescription)
+            message.status = .sendingFailed
+            _ = try? database.saveMessage(message)
+        }
     }
 
     func didNavigateSomewhere() {
@@ -194,9 +305,60 @@ final class SingleChatViewModel: NSObject {
     }
 
     func send(_ string: String) {
-        let text = string.trimmingCharacters(in: .whitespacesAndNewlines)
-        let payload = Payload(text: text, reply: stagedReply)
-        session.send(payload, toContact: contact)
+        var message: Message = .init(
+            senderId: myId,
+            recipientId: contact.id,
+            groupId: nil,
+            date: Date(),
+            status: .sending,
+            isUnread: false,
+            text: string.trimmingCharacters(in: .whitespacesAndNewlines),
+            replyMessageId: stagedReply?.messageId
+        )
+
+        do {
+            message = try database.saveMessage(message)
+
+            let report = try e2e.send(
+                messageType: 2,
+                recipientId: contact.id,
+                payload: Payload(text: message.text, reply: stagedReply).asData(),
+                e2eParams: GetE2EParams.liveDefault()
+            )
+
+            try cMix.waitForRoundResult(
+                roundList: try report.encode(),
+                timeoutMS: 5_000,
+                callback: .init(handle: {
+                    switch $0 {
+                    case .delivered:
+                        message.status = .sent
+                        _ = try? self.database.saveMessage(message)
+
+                    case .notDelivered(timedOut: let timedOut):
+                        if timedOut {
+                            message.status = .sendingTimedOut
+                        } else {
+                            message.status = .sendingFailed
+                        }
+
+                        _ = try? self.database.saveMessage(message)
+                    }
+                })
+            )
+
+            message.networkId = report.messageId
+            if let timestamp = report.timestamp {
+                message.date = Date.fromTimestamp(Int(timestamp))
+            }
+
+            message = try database.saveMessage(message)
+        } catch {
+            print(error.localizedDescription)
+            message.status = .sendingFailed
+            _ = try? database.saveMessage(message)
+        }
+
         stagedReply = nil
     }
 
@@ -204,7 +366,7 @@ final class SingleChatViewModel: NSObject {
         guard let networkId = message.networkId else { return }
 
         let senderTitle: String = {
-            if message.senderId == session.myId {
+            if message.senderId == myId {
                 return "You"
             } else {
                 return (contact.nickname ?? contact.username) ?? "Fetching username..."
@@ -216,11 +378,11 @@ final class SingleChatViewModel: NSObject {
     }
 
     func getReplyContent(for messageId: Data) -> (String, String) {
-        guard let message = try? session.dbManager.fetchMessages(.init(networkId: messageId)).first else {
+        guard let message = try? database.fetchMessages(.init(networkId: messageId)).first else {
             return ("[DELETED]", "[DELETED]")
         }
 
-        guard let contact = try? session.dbManager.fetchContacts(.init(id: [message.senderId])).first else {
+        guard let contact = try? database.fetchContacts(.init(id: [message.senderId])).first else {
             fatalError()
         }
 
@@ -237,7 +399,7 @@ final class SingleChatViewModel: NSObject {
     }
 
     func didRequestDelete(_ items: [Message]) {
-        _ = try? session.dbManager.deleteMessages(.init(id: Set(items.compactMap(\.id))))
+        _ = try? database.deleteMessages(.init(id: Set(items.compactMap(\.id))))
     }
 
     func itemWith(id: Int64) -> Message? {
diff --git a/Sources/ChatListFeature/ViewModel/ChatListViewModel.swift b/Sources/ChatListFeature/ViewModel/ChatListViewModel.swift
index af0a8401592ec2715527a3af901846253c20ba80..ab527d846e9966c888a8b36eacc0f1742b01d33a 100644
--- a/Sources/ChatListFeature/ViewModel/ChatListViewModel.swift
+++ b/Sources/ChatListFeature/ViewModel/ChatListViewModel.swift
@@ -5,10 +5,12 @@ import Models
 import Combine
 import XXModels
 import Defaults
-import Integration
 import ReportingFeature
 import DependencyInjection
 
+import struct XXModels.Group
+import XXClient
+
 enum SearchSection {
     case chats
     case connections
@@ -23,11 +25,18 @@ typealias RecentsSnapshot = NSDiffableDataSourceSnapshot<SectionId, Contact>
 typealias SearchSnapshot = NSDiffableDataSourceSnapshot<SearchSection, SearchItem>
 
 final class ChatListViewModel {
-    @Dependency private var session: SessionType
-    @Dependency private var reportingStatus: ReportingStatus
+    @Dependency var database: Database
+    @Dependency var groupManager: GroupChat
+    @Dependency var userDiscovery: UserDiscovery
+    @Dependency var reportingStatus: ReportingStatus
 
+    // TO REFACTOR:
     var isOnline: AnyPublisher<Bool, Never> {
-        session.isOnline
+        Just(.init(true)).eraseToAnyPublisher()
+    }
+
+    var myId: Data {
+        try! GetIdFromContact.live(userDiscovery.getContact())
     }
 
     var chatsPublisher: AnyPublisher<[ChatInfo], Never> {
@@ -45,7 +54,7 @@ final class ChatListViewModel {
             isBanned: reportingStatus.isEnabled() ? false : nil
         )
 
-        return session.dbManager.fetchContactsPublisher(query)
+        return database.fetchContactsPublisher(query)
             .assertNoFailure()
             .map {
             let section = SectionId()
@@ -62,13 +71,10 @@ final class ChatListViewModel {
             isBanned: reportingStatus.isEnabled() ? false : nil
         )
 
-        let contactsStream = session.dbManager
-            .fetchContactsPublisher(contactsQuery)
-            .assertNoFailure()
-            .map { $0.filter { $0.id != self.session.myId }}
-
-        return Publishers.CombineLatest3(
-            contactsStream,
+        Publishers.CombineLatest3(
+            database.fetchContactsPublisher(contactsQuery)
+                .assertNoFailure()
+                .map { $0.filter { $0.id != self.session.myId }},
             chatsPublisher,
             searchSubject
                 .removeDuplicates()
@@ -132,8 +138,8 @@ final class ChatListViewModel {
         )
 
         return Publishers.CombineLatest(
-            session.dbManager.fetchContactsPublisher(contactsQuery).assertNoFailure(),
-            session.dbManager.fetchGroupsPublisher(groupQuery).assertNoFailure()
+            database.fetchContactsPublisher(contactsQuery).assertNoFailure(),
+            database.fetchGroupsPublisher(groupQuery).assertNoFailure()
         )
         .map { $0.0.count + $0.1.count }
         .eraseToAnyPublisher()
@@ -145,10 +151,10 @@ final class ChatListViewModel {
     private let hudSubject = CurrentValueSubject<HUDStatus, Never>(.none)
 
     init() {
-        session.dbManager.fetchChatInfosPublisher(
+        database.fetchChatInfosPublisher(
             ChatInfo.Query(
                 contactChatInfoQuery: .init(
-                    userId: session.myId,
+                    userId: myId,
                     authStatus: [.friend],
                     isBlocked: reportingStatus.isEnabled() ? false : nil,
                     isBanned: reportingStatus.isEnabled() ? false : nil
@@ -175,8 +181,8 @@ final class ChatListViewModel {
         hudSubject.send(.on)
 
         do {
-            try session.leave(group: group)
-            try session.dbManager.deleteMessages(.init(chat: .group(group.id)))
+            try groupManager.leaveGroup(groupId: group.id)
+            try database.deleteMessages(.init(chat: .group(group.id)))
             hudSubject.send(.none)
         } catch {
             hudSubject.send(.error(.init(with: error)))
@@ -184,12 +190,12 @@ final class ChatListViewModel {
     }
 
     func clear(_ contact: Contact) {
-        _ = try? session.dbManager.deleteMessages(.init(chat: .direct(session.myId, contact.id)))
+        _ = try? database.deleteMessages(.init(chat: .direct(myId, contact.id)))
     }
 
     func groupInfo(from group: Group) -> GroupInfo? {
         let query = GroupInfo.Query(groupId: group.id)
-        guard let info = try? session.dbManager.fetchGroupInfos(query).first else {
+        guard let info = try? database.fetchGroupInfos(query).first else {
             return nil
         }
 
diff --git a/Sources/ContactFeature/ViewModels/ContactViewModel.swift b/Sources/ContactFeature/ViewModels/ContactViewModel.swift
index 5e6e06698cbfeb359a79ce231dde08f37c03ee6a..c5c5d085efd408b0375b06ad199f0923395b7ce2 100644
--- a/Sources/ContactFeature/ViewModels/ContactViewModel.swift
+++ b/Sources/ContactFeature/ViewModels/ContactViewModel.swift
@@ -3,10 +3,12 @@ import UIKit
 import Models
 import Combine
 import XXModels
-import Integration
+import Defaults
 import CombineSchedulers
 import DependencyInjection
 
+import XXClient
+
 struct ContactViewState: Equatable {
     var title: String?
     var email: String?
@@ -17,7 +19,12 @@ struct ContactViewState: Equatable {
 }
 
 final class ContactViewModel {
-    @Dependency private var session: SessionType
+    @Dependency var e2e: E2E
+    @Dependency var database: Database
+    @Dependency var userDiscovery: UserDiscovery
+    @Dependency var getFactsFromContact: GetFactsFromContact
+
+    @KeyObject(.username, defaultValue: nil) var username: String?
 
     var contact: Contact
 
@@ -33,39 +40,42 @@ final class ContactViewModel {
     private let hudRelay = CurrentValueSubject<HUDStatus, Never>(.none)
     private let stateRelay = CurrentValueSubject<ContactViewState, Never>(.init())
 
+    var myId: Data {
+        try! GetIdFromContact.live(userDiscovery.getContact())
+    }
+
     var backgroundScheduler: AnySchedulerOf<DispatchQueue> = DispatchQueue.global().eraseToAnyScheduler()
 
     init(_ contact: Contact) {
         self.contact = contact
 
-        do {
-            let email = try session.extract(fact: .email, from: contact.marshaled!)
-            let phone = try session.extract(fact: .phone, from: contact.marshaled!)
-
-            stateRelay.value = .init(
-                title: contact.nickname ?? contact.username,
-                email: email,
-                phone: phone,
-                photo: contact.photo != nil ? UIImage(data: contact.photo!) : nil,
-                username: contact.username,
-                nickname: contact.nickname
-            )
-        } catch {
-            print(error.localizedDescription)
-        }
+        let facts = try? getFactsFromContact(contact: contact.marshaled!)
+        let email = facts?.first(where: { $0.type == FactType.email.rawValue })?.fact
+        let phone = facts?.first(where: { $0.type == FactType.phone.rawValue })?.fact
+
+        stateRelay.value = .init(
+            title: contact.nickname ?? contact.username,
+            email: email,
+            phone: phone,
+            photo: contact.photo != nil ? UIImage(data: contact.photo!) : nil,
+            username: contact.username,
+            nickname: contact.nickname
+        )
     }
 
     func didChoosePhoto(_ photo: UIImage) {
         stateRelay.value.photo = photo
         contact.photo = photo.jpegData(compressionQuality: 0.0)
-        _ = try? session.dbManager.saveContact(contact)
+        _ = try? database.saveContact(contact)
     }
 
     func didTapDelete() {
         hudRelay.send(.on)
 
         do {
-            try session.deleteContact(contact)
+            try e2e.deleteRequest.partner(contact.id)
+            try database.deleteContact(contact)
+
             hudRelay.send(.none)
             popToRootRelay.send()
         } catch {
@@ -74,33 +84,49 @@ final class ContactViewModel {
     }
 
     func didTapReject() {
-        try? session.deleteContact(contact)
+        // TODO: Reject function on the API?
+        _ = try? database.deleteContact(contact)
         popRelay.send()
     }
 
     func didTapClear() {
-        _ = try? session.dbManager.deleteMessages(.init(chat: .direct(session.myId, contact.id)))
+        _ = try? database.deleteMessages(.init(chat: .direct(myId, contact.id)))
     }
 
     func didUpdateNickname(_ string: String) {
         contact.nickname = string.isEmpty ? nil : string
         stateRelay.value.title = string.isEmpty ? contact.username : string
-        _ = try? session.dbManager.saveContact(contact)
+        _ = try? database.saveContact(contact)
 
         stateRelay.value.nickname = contact.nickname
     }
 
     func didTapResend() {
         hudRelay.send(.on)
+        contact.authStatus = .requesting
 
         backgroundScheduler.schedule { [weak self] in
             guard let self = self else { return }
 
             do {
-                try self.session.add(self.contact)
+                try self.database.saveContact(self.contact)
+
+                var myFacts = try self.userDiscovery.getFacts()
+                myFacts.append(Fact(fact: self.username!, type: FactType.username.rawValue))
+
+                let _ = try self.e2e.requestAuthenticatedChannel(
+                    partnerContact: self.contact.id,
+                    myFacts: myFacts
+                )
+
+                self.contact.authStatus = .requested
+                try self.database.saveContact(self.contact)
+
                 self.hudRelay.send(.none)
                 self.popRelay.send()
             } catch {
+                self.contact.authStatus = .requestFailed
+                _ = try? self.database.saveContact(self.contact)
                 self.hudRelay.send(.error(.init(with: error)))
             }
         }
@@ -109,15 +135,30 @@ final class ContactViewModel {
     func didTapRequest(with nickname: String) {
         hudRelay.send(.on)
         contact.nickname = nickname
+        contact.authStatus = .requesting
 
         backgroundScheduler.schedule { [weak self] in
             guard let self = self else { return }
 
             do {
-                try self.session.add(self.contact)
+                try self.database.saveContact(self.contact)
+
+                var myFacts = try self.userDiscovery.getFacts()
+                myFacts.append(Fact(fact: self.username!, type: FactType.username.rawValue))
+
+                let _ = try self.e2e.requestAuthenticatedChannel(
+                    partnerContact: self.contact.marshaled!,
+                    myFacts: myFacts
+                )
+
+                self.contact.authStatus = .requested
+                try self.database.saveContact(self.contact)
+
                 self.hudRelay.send(.none)
                 self.successRelay.send()
             } catch {
+                self.contact.authStatus = .requestFailed
+                _ = try? self.database.saveContact(self.contact)
                 self.hudRelay.send(.error(.init(with: error)))
             }
         }
@@ -126,15 +167,24 @@ final class ContactViewModel {
     func didTapAccept(_ nickname: String) {
         hudRelay.send(.on)
         contact.nickname = nickname
+        contact.authStatus = .confirming
 
         backgroundScheduler.schedule { [weak self] in
             guard let self = self else { return }
 
             do {
-                try self.session.confirm(self.contact)
+                try self.database.saveContact(self.contact)
+
+                let _ = try self.e2e.confirmReceivedRequest(partnerContact: self.contact.marshaled!)
+
+                self.contact.authStatus = .friend
+                try self.database.saveContact(self.contact)
+
                 self.hudRelay.send(.none)
                 self.popRelay.send()
             } catch {
+                self.contact.authStatus = .confirmationFailed
+                _ = try? self.database.saveContact(self.contact)
                 self.hudRelay.send(.error(.init(with: error)))
             }
         }
diff --git a/Sources/ContactListFeature/ViewModels/ContactListViewModel.swift b/Sources/ContactListFeature/ViewModels/ContactListViewModel.swift
index 830172f3b9bd298be2c8c8200e2c96f89d264325..f37561acdae5a243b64e84512347c04858bfd174 100644
--- a/Sources/ContactListFeature/ViewModels/ContactListViewModel.swift
+++ b/Sources/ContactListFeature/ViewModels/ContactListViewModel.swift
@@ -2,14 +2,21 @@ import Models
 import Combine
 import XXModels
 import Defaults
-import Integration
 import ReportingFeature
 import DependencyInjection
 
+import Foundation
+import XXClient
+
 final class ContactListViewModel {
-    @Dependency private var session: SessionType
+    @Dependency var database: Database
+    @Dependency var userDiscovery: UserDiscovery
     @Dependency private var reportingStatus: ReportingStatus
 
+    var myId: Data {
+        try! GetIdFromContact.live(userDiscovery.getContact())
+    }
+
     var contacts: AnyPublisher<[Contact], Never> {
         let query = Contact.Query(
             authStatus: [.friend],
@@ -17,9 +24,9 @@ final class ContactListViewModel {
             isBanned: reportingStatus.isEnabled() ? false: nil
         )
 
-        return session.dbManager.fetchContactsPublisher(query)
+        return database.fetchContactsPublisher(query)
             .assertNoFailure()
-            .map { $0.filter { $0.id != self.session.myId }}
+            .map { $0.filter { $0.id != self.myId }}
             .eraseToAnyPublisher()
     }
 
@@ -43,8 +50,8 @@ final class ContactListViewModel {
         )
 
         return Publishers.CombineLatest(
-            session.dbManager.fetchContactsPublisher(contactsQuery).assertNoFailure(),
-            session.dbManager.fetchGroupsPublisher(groupQuery).assertNoFailure()
+            database.fetchContactsPublisher(contactsQuery).assertNoFailure(),
+            database.fetchGroupsPublisher(groupQuery).assertNoFailure()
         )
         .map { $0.0.count + $0.1.count }
         .eraseToAnyPublisher()
diff --git a/Sources/ContactListFeature/ViewModels/CreateGroupViewModel.swift b/Sources/ContactListFeature/ViewModels/CreateGroupViewModel.swift
index 555407535ca52ab7ed00c7d1060d6f98a967030b..06dabcb0a90c33b33be03d6f9c737ea7502bd7b5 100644
--- a/Sources/ContactListFeature/ViewModels/CreateGroupViewModel.swift
+++ b/Sources/ContactListFeature/ViewModels/CreateGroupViewModel.swift
@@ -4,8 +4,9 @@ import Models
 import Combine
 import XXModels
 import Defaults
-import Integration
+import XXClient
 import ReportingFeature
+import CombineSchedulers
 import DependencyInjection
 
 final class CreateGroupViewModel {
@@ -13,11 +14,17 @@ final class CreateGroupViewModel {
 
     // MARK: Injected
 
-    @Dependency private var session: SessionType
-    @Dependency private var reportingStatus: ReportingStatus
+    @Dependency var database: Database
+    @Dependency var groupManager: GroupChat
+    @Dependency var userDiscovery: UserDiscovery
+    @Dependency var reportingStatus: ReportingStatus
 
     // MARK: Properties
 
+    var myId: Data {
+        try! GetIdFromContact.live(userDiscovery.getContact())
+    }
+
     var selected: AnyPublisher<[Contact], Never> {
         selectedContactsRelay.eraseToAnyPublisher()
     }
@@ -34,6 +41,9 @@ final class CreateGroupViewModel {
         infoRelay.eraseToAnyPublisher()
     }
 
+    var backgroundScheduler: AnySchedulerOf<DispatchQueue>
+    = DispatchQueue.global().eraseToAnyScheduler()
+
     private var allContacts = [Contact]()
     private var cancellables = Set<AnyCancellable>()
     private let infoRelay = PassthroughSubject<GroupInfo, Never>()
@@ -50,9 +60,9 @@ final class CreateGroupViewModel {
             isBanned: reportingStatus.isEnabled() ? false : nil
         )
 
-        session.dbManager.fetchContactsPublisher(query)
+        database.fetchContactsPublisher(query)
             .assertNoFailure()
-            .map { $0.filter { $0.id != self.session.myId }}
+            .map { $0.filter { $0.id != self.myId }}
             .map { $0.sorted(by: { $0.username! < $1.username! })}
             .sink { [unowned self] in
                 allContacts = $0
@@ -86,15 +96,54 @@ final class CreateGroupViewModel {
     func create(name: String, welcome: String?, members: [Contact]) {
         hudRelay.send(.on)
 
-        session.createGroup(name: name, welcome: welcome, members: members) { [weak self] in
+        backgroundScheduler.schedule { [weak self] in
             guard let self = self else { return }
 
-            self.hudRelay.send(.none)
-
-            switch $0 {
-            case .success(let info):
-                self.infoRelay.send(info)
-            case .failure(let error):
+            do {
+                let report = try self.groupManager.makeGroup(
+                    membership: members.map(\.id),
+                    message: welcome?.data(using: .utf8),
+                    name: name.data(using: .utf8)
+                )
+
+                let group = Group(
+                    id: report.id,
+                    name: name,
+                    leaderId: self.myId,
+                    createdAt: Date(),
+                    authStatus: .participating,
+                    serialized: try report.encode() // ?
+                )
+
+                _ = try self.database.saveGroup(group)
+
+                if let welcomeMessage = welcome {
+                    try self.database.saveMessage(
+                        Message(
+                            senderId: self.myId,
+                            recipientId: nil,
+                            groupId: group.id,
+                            date: group.createdAt,
+                            status: .sent,
+                            isUnread: false,
+                            text: welcomeMessage,
+                            replyMessageId: nil,
+                            roundURL: nil,
+                            fileTransferId: nil
+                        )
+                    )
+                }
+
+                try members
+                    .map { GroupMember(groupId: group.id, contactId: $0.id) }
+                    .forEach { try self.database.saveGroupMember($0) }
+
+                let query = GroupInfo.Query(groupId: group.id)
+                let info = try self.database.fetchGroupInfos(query).first
+
+                self.infoRelay.send(info!)
+                self.hudRelay.send(.none)
+            } catch {
                 self.hudRelay.send(.error(.init(with: error)))
             }
         }
diff --git a/Sources/Defaults/KeyObject.swift b/Sources/Defaults/KeyObject.swift
index 0ade4e83639f54a5181b4292936a2d9dee049f60..1effae9ca395716e826b9f5864739cbeb92ddab6 100644
--- a/Sources/Defaults/KeyObject.swift
+++ b/Sources/Defaults/KeyObject.swift
@@ -39,7 +39,6 @@ public enum Key: String {
     case crashReporting
     case icognitoKeyboard
 
-    case dummyTrafficOn
     case askedDummyTrafficOnce
 }
 
diff --git a/Sources/Integration/Callbacks.swift b/Sources/Integration/Callbacks.swift
deleted file mode 100644
index ed9d917cf8ff0469015a0dfa4db869a450666bfe..0000000000000000000000000000000000000000
--- a/Sources/Integration/Callbacks.swift
+++ /dev/null
@@ -1,295 +0,0 @@
-import Bindings
-
-final class TextListener: NSObject, BindingsListenerProtocol {
-    let callback: (BindingsMessage?) -> ()
-
-    init(_ callback: @escaping (BindingsMessage?) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func hear(_ message: BindingsMessage?) {
-        callback(message)
-    }
-
-    func name() -> String { "TEXT_LISTENER" }
-}
-
-final class ConfirmationCallback: NSObject, BindingsAuthConfirmCallbackProtocol {
-    let callback: (_ partner: BindingsContact) -> ()
-
-    init(_ callback: @escaping (_ partner: BindingsContact) -> ()) {
-        self.callback = callback
-        super.init()
-    }
-
-    func callback(_ partner: BindingsContact?) {
-        guard let partner = partner else { return }
-        callback(partner)
-    }
-}
-
-final class RequestCallback: NSObject, BindingsAuthRequestCallbackProtocol {
-    let callback: (_ requestor: BindingsContact) -> ()
-
-    init(_ callback: @escaping (_ requestor: BindingsContact) -> ()) {
-        self.callback = callback
-        super.init()
-    }
-
-    func callback(_ requestor: BindingsContact?) {
-        guard let requestor = requestor else { return }
-        callback(requestor)
-    }
-}
-
-final class HealthCallback: NSObject, BindingsNetworkHealthCallbackProtocol {
-    let callback: (Bool) -> Void
-
-    init(_ callback: @escaping (Bool) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func callback(_ p0: Bool) {
-        callback(p0)
-    }
-}
-
-final class LogCallback: NSObject, BindingsLogWriterProtocol {
-    let callback: (String?) -> Void
-
-    init(_ callback: @escaping (String?) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func log(_ p0: String?) {
-        callback(p0)
-    }
-}
-
-final class DeliveryCallback: NSObject, BindingsMessageDeliveryCallbackProtocol {
-    let callback: (DeliveryResult) -> Void
-
-    init(_ callback: @escaping (DeliveryResult) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func eventCallback(_ msgID: Data?, delivered: Bool, timedOut: Bool, roundResults: Data?) {
-
-        let content =
-        """
-        "Delivery Callback:
-        - Timed out: \(timedOut)
-        - Delivered: \(delivered)
-        - Message ID in base64: \(String(describing: msgID?.base64EncodedString()))
-        - Round results in base64: \(String(describing: roundResults?.base64EncodedString()))"
-        """
-
-        log(string: content, type: .info)
-        callback((msgID, delivered, timedOut, roundResults))
-    }
-}
-
-final class RoundCallback: NSObject, BindingsRoundCompletionCallbackProtocol {
-    let callback: (Bool) -> Void
-
-    init(_ callback: @escaping (Bool) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func eventCallback(_ rid: Int, success: Bool, timedOut: Bool) {
-        log(string: ">>> Add/Confirm RoundCallback:\nid: \(rid)\nSuccessfull: \(success)\nTimed out: \(timedOut)", type: .info)
-        callback(success && !timedOut)
-    }
-}
-
-final class SearchCallback: NSObject, BindingsSingleSearchCallbackProtocol {
-    let callback: (Result<BindingsContact, Error>) -> Void
-
-    init(_ callback: @escaping (Result<BindingsContact, Error>) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func callback(_ contact: BindingsContact?, error: String?) {
-        if let error = error, error.count > 0 {
-            callback(.failure(NSError.create(error).friendly()))
-            return
-        }
-
-        if let contact = contact {
-            callback(.success(contact))
-        }
-    }
-}
-
-final class EventCallback: NSObject, BindingsEventCallbackFunctionObjectProtocol {
-    let callback: (BackendEvent) -> Void
-
-    init(_ callback: @escaping (BackendEvent) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func reportEvent(_ priority: Int, category: String?, evtType: String?, details: String?) {
-        callback((priority, category, evtType, details))
-    }
-}
-
-final class GroupRequestCallback: NSObject, BindingsGroupRequestFuncProtocol {
-    let callback: (BindingsGroup) -> Void
-
-    init(_ callback: @escaping (BindingsGroup) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func groupRequestCallback(_ g: BindingsGroup?) {
-        guard let group = g else { return }
-        callback(group)
-    }
-}
-
-final class GroupMessageCallback: NSObject, BindingsGroupReceiveFuncProtocol {
-    let callback: (BindingsGroupMessageReceive) -> Void
-
-    init(_ callback: @escaping (BindingsGroupMessageReceive) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func groupReceiveCallback(_ msg: BindingsGroupMessageReceive?) {
-        guard let message = msg else { return }
-        callback(message)
-    }
-}
-
-final class MultiLookupCallback: NSObject, BindingsMultiLookupCallbackProtocol {
-    let thisCallback: (BindingsContactList?, BindingsIdList?, String?) -> Void
-
-    init(_ callback: @escaping (BindingsContactList?, BindingsIdList?, String?) -> Void) {
-        self.thisCallback = callback
-        super.init()
-    }
-
-    func callback(_ Succeeded: BindingsContactList?, failed: BindingsIdList?, errors: String?) {
-        thisCallback(Succeeded, failed, errors)
-    }
-}
-
-final class PreImageCallback: NSObject, BindingsPreimageNotificationProtocol {
-    let callback: (Data?, Bool) -> Void
-
-    init(_ callback: @escaping (Data?, Bool) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func notify(_ identity: Data?, deleted: Bool) {
-        callback(identity, deleted)
-    }
-}
-
-final class LookupCallback: NSObject, BindingsLookupCallbackProtocol {
-    let callback: (Result<BindingsContact, Error>) -> Void
-
-    init(_ callback: @escaping (Result<BindingsContact, Error>) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func callback(_ contact: BindingsContact?, error: String?) {
-        if let error = error, !error.isEmpty {
-            callback(.failure(NSError.create(error).friendly()))
-            return
-        }
-
-        if let contact = contact {
-            callback(.success(contact))
-        }
-    }
-}
-
-final class IncomingTransferCallback: NSObject, BindingsFileTransferReceiveFuncProtocol {
-    let callback: (Data?, String?, String?, Data?, Int, Data?) -> Void
-
-    init(_ callback: @escaping (Data?, String?, String?, Data?, Int, Data?) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func receiveCallback(_ tid: Data?, fileName: String?, fileType: String?, sender: Data?, size: Int, preview: Data?) {
-        callback(tid, fileName, fileType, sender, size, preview)
-    }
-}
-
-final class IncomingTransferProgressCallback: NSObject, BindingsFileTransferReceivedProgressFuncProtocol {
-    let callback: (Bool, Int, Int, Error?) -> Void
-
-    init(_ callback: @escaping (Bool, Int, Int, Error?) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func receivedProgressCallback(_ completed: Bool, received: Int, total: Int, t: BindingsFilePartTracker?, err: Error?) {
-        callback(completed, received, total, err)
-    }
-}
-
-final class OutgoingTransferProgressCallback: NSObject, BindingsFileTransferSentProgressFuncProtocol {
-    let callback: (Bool, Int, Int, Int, Error?) -> Void
-
-    init(_ callback: @escaping (Bool, Int, Int, Int, Error?) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func sentProgressCallback(_ completed: Bool, sent: Int, arrived: Int, total: Int, t: BindingsFilePartTracker?, err: Error?) {
-        callback(completed, sent, arrived, total, err)
-    }
-}
-
-final class UpdateBackupCallback: NSObject, BindingsUpdateBackupFuncProtocol {
-    let callback: (Data) -> Void
-
-    init(_ callback: @escaping (Data) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func updateBackup(_ encryptedBackup: Data?) {
-        guard let data = encryptedBackup else { return }
-        callback(data)
-    }
-}
-
-final class ResetCallback: NSObject, BindingsAuthResetNotificationCallbackProtocol {
-    let callback: (BindingsContact) -> Void
-
-    init(_ callback: @escaping (BindingsContact) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func callback(_ requestor: BindingsContact?) {
-        guard let requestor = requestor else { return }
-        callback(requestor)
-    }
-}
-
-final class RestoreContactsCallback: NSObject, BindingsRestoreContactsUpdaterProtocol {
-    let callback: (Int, Int, Int, String?) -> Void
-
-    init(_ callback: @escaping (Int, Int, Int, String?) -> Void) {
-        self.callback = callback
-        super.init()
-    }
-
-    func restoreContactsCallback(_ numFound: Int, numRestored: Int, total: Int, err: String?) {
-        callback(numFound, numRestored, total, err)
-    }
-}
diff --git a/Sources/Integration/Client.swift b/Sources/Integration/Client.swift
deleted file mode 100644
index 8fc201af93fe681852c550f62965029316e00811..0000000000000000000000000000000000000000
--- a/Sources/Integration/Client.swift
+++ /dev/null
@@ -1,236 +0,0 @@
-import Retry
-import Models
-import Combine
-import Defaults
-import Bindings
-import XXModels
-import Foundation
-
-public class Client {
-    @KeyObject(.inappnotifications, defaultValue: true) var inappnotifications: Bool
-
-    let bindings: BindingsInterface
-    var backupManager: BackupInterface?
-    var dummyManager: DummyTrafficManaging?
-    var groupManager: GroupManagerInterface?
-    var userDiscovery: UserDiscoveryInterface?
-    var transferManager: TransferManagerInterface?
-
-    var backup: AnyPublisher<Data, Never> { backupSubject.eraseToAnyPublisher() }
-    var network: AnyPublisher<Bool, Never> { networkSubject.eraseToAnyPublisher() }
-    var resets: AnyPublisher<Contact, Never> { resetsSubject.eraseToAnyPublisher() }
-    var messages: AnyPublisher<Message, Never> { messagesSubject.eraseToAnyPublisher() }
-    var requests: AnyPublisher<Contact, Never> { requestsSubject.eraseToAnyPublisher() }
-    var events: AnyPublisher<BackendEvent, Never> { eventsSubject.eraseToAnyPublisher() }
-    var transfers: AnyPublisher<FileTransfer, Never> { transfersSubject.eraseToAnyPublisher() }
-    var requestsSent: AnyPublisher<Contact, Never> { requestsSentSubject.eraseToAnyPublisher() }
-    var confirmations: AnyPublisher<Contact, Never> { confirmationsSubject.eraseToAnyPublisher() }
-    var groupRequests: AnyPublisher<(Group, [Data], String?), Never> { groupRequestsSubject.eraseToAnyPublisher() }
-
-    private let backupSubject = PassthroughSubject<Data, Never>()
-    private let networkSubject = PassthroughSubject<Bool, Never>()
-    private let resetsSubject = PassthroughSubject<Contact, Never>()
-    private let requestsSubject = PassthroughSubject<Contact, Never>()
-    private let messagesSubject = PassthroughSubject<Message, Never>()
-    private let eventsSubject = PassthroughSubject<BackendEvent, Never>()
-    private let requestsSentSubject = PassthroughSubject<Contact, Never>()
-    private let confirmationsSubject = PassthroughSubject<Contact, Never>()
-    private let transfersSubject = PassthroughSubject<FileTransfer, Never>()
-    private let groupRequestsSubject = PassthroughSubject<(Group, [Data], String?), Never>()
-
-    private var isBackupInitialization = false
-    private var isBackupInitializationCompleted = false
-
-    // MARK: Lifecycle
-
-    init(
-        _ bindings: BindingsInterface,
-        fromBackup: Bool,
-        email: String?,
-        phone: String?
-    ) {
-        self.bindings = bindings
-        self.isBackupInitialization = fromBackup
-
-        do {
-            try registerListenersAndStart()
-
-            if fromBackup {
-                try instantiateUserDiscoveryFromBackup(email: email, phone: phone)
-            } else {
-                try instantiateUserDiscovery()
-            }
-
-            try instantiateTransferManager()
-            try instantiateDummyTrafficManager()
-            updatePreImage()
-        } catch {
-            log(string: error.localizedDescription, type: .error)
-        }
-    }
-
-    public func initializeBackup(passphrase: String) {
-        backupManager = nil
-        backupManager = bindings.initializeBackup(passphrase: passphrase) { [weak backupSubject] in
-            backupSubject?.send($0)
-        }
-    }
-
-    public func resumeBackup() {
-        backupManager = nil
-        backupManager = bindings.resumeBackup { [weak backupSubject] in
-            backupSubject?.send($0)
-        }
-    }
-
-    //    public func isBackupRunning() -> Bool {
-    //        guard let backupManager = backupManager else { return false }
-    //        return backupManager.isBackupRunning()
-    //    }
-
-    public func addJson(_ string: String) {
-        guard let backupManager = backupManager else {
-            fatalError("Trying to add json parameters to backup but no backup manager created yet")
-        }
-
-        backupManager.addJson(string)
-    }
-
-    public func stopListeningBackup() {
-        guard let backupManager = backupManager else { return }
-        try? backupManager.stop()
-        self.backupManager = nil
-    }
-
-    public func restoreContacts(fromBackup backup: Data) {
-        var totalPendingRestoration: Int = 0
-
-        let report = bindings.restore(
-            ids: backup,
-            using: userDiscovery!) { [weak self] in
-                guard let self = self else { return }
-
-                switch $0 {
-                case .success(var contact):
-                    contact.authStatus = .requested
-                    self.requestsSentSubject.send(contact)
-                    print(">>> Restored \(contact.username). Setting status as requested")
-                case .failure(let error):
-                    print(">>> \(error.localizedDescription)")
-                }
-            } restoreCallback: { numFound, numRestored, total, errorString in
-                totalPendingRestoration = total
-                let results =
-            """
-            >>> Results from within closure of RestoreContacts:
-            - numFound: \(numFound)
-            - numRestored: \(numRestored)
-            - total: \(total)
-            - errorString: \(errorString)
-            """
-                print(results)
-            }
-
-        guard totalPendingRestoration > 0 else { fatalError("Total is zero, why called restore contacts?") }
-
-        guard report.lenRestored() == totalPendingRestoration else {
-            print(">>> numRestored \(report.lenRestored()) is != than the total (\(totalPendingRestoration)). Going on recursion...\nnumFailed: \(report.lenFailed())\n\(report.getRestoreContactsError())")
-            restoreContacts(fromBackup: backup)
-            return
-        }
-
-        isBackupInitializationCompleted = true
-    }
-
-    private func registerListenersAndStart() throws {
-        bindings.listenNetworkUpdates { [weak networkSubject] in networkSubject?.send($0) }
-
-        bindings.listenRequests { [weak self] in
-            guard let self = self else { return }
-
-            if self.isBackupInitialization {
-                if self.isBackupInitializationCompleted {
-                    self.requestsSubject.send($0)
-                }
-            } else {
-                self.requestsSubject.send($0)
-            }
-        } _: { [weak confirmationsSubject] in
-            confirmationsSubject?.send($0)
-        } _: { [weak resetsSubject] in
-            resetsSubject?.send($0)
-        }
-
-        bindings.listenEvents { [weak eventsSubject] in
-            eventsSubject?.send($0)
-        }
-
-        groupManager = try bindings.listenGroupRequests { [weak groupRequestsSubject] request, members, welcome in
-            groupRequestsSubject?.send((request, members, welcome))
-        } groupMessages: { [weak messagesSubject] in
-            messagesSubject?.send($0)
-        }
-
-        bindings.listenPreImageUpdates()
-
-        try bindings.listenMessages { [weak messagesSubject] in
-            messagesSubject?.send($0)
-        }
-
-        bindings.startNetwork()
-    }
-
-    private func instantiateTransferManager() throws {
-        transferManager = try bindings.generateTransferManager { [weak transfersSubject] tid, name, type, sender in
-
-            /// Someone transfered something to me
-            /// but I haven't received yet. I'll store an
-            /// IncomingTransfer object so later on I can
-            /// pull up whatever this contact has sent me.
-            ///
-            guard let name = name,
-                  let type = type,
-                  let contactId = sender else {
-                      log(string: "Transfer of \(name ?? "nil").\(type ?? "nil") is being dismissed", type: .error)
-                      return
-                  }
-
-            transfersSubject?.send(
-                FileTransfer(
-                    id: tid,
-                    contactId: contactId,
-                    name: name,
-                    type: type,
-                    data: nil,
-                    progress: 0.0,
-                    isIncoming: true,
-                    createdAt: Date()
-                )
-            )
-        }
-    }
-
-    private func instantiateUserDiscovery() throws {
-        retry(max: 4, retryStrategy: .delay(seconds: 1)) { [weak self] in
-            guard let self = self else { return }
-            self.userDiscovery = try self.bindings.generateUD()
-        }
-    }
-
-    private func instantiateUserDiscoveryFromBackup(email: String?, phone: String?) throws {
-        retry(max: 4, retryStrategy: .delay(seconds: 1)) { [weak self] in
-            guard let self = self else { return }
-            self.userDiscovery = try self.bindings.generateUDFromBackup(email: email, phone: phone)
-        }
-    }
-
-    private func instantiateDummyTrafficManager() throws {
-        dummyManager = try bindings.generateDummyTraficManager()
-    }
-
-    private func updatePreImage() {
-        if let defaults = UserDefaults(suiteName: "group.elixxir.messenger") {
-            defaults.set(bindings.getPreImages(), forKey: "preImage")
-        }
-    }
-}
diff --git a/Sources/Integration/Extensions.swift b/Sources/Integration/Extensions.swift
deleted file mode 100644
index f2afdcb99e46f87141081f94e657b7ef5e14721e..0000000000000000000000000000000000000000
--- a/Sources/Integration/Extensions.swift
+++ /dev/null
@@ -1,58 +0,0 @@
-import Models
-import XXModels
-import Bindings
-
-extension Contact {
-    init(with contact: BindingsContact, status: Contact.AuthStatus) {
-        self.init(
-            id: contact.getID()!,
-            marshaled: try! contact.marshal(),
-            username: contact.retrieve(fact: .username) ?? "",
-            email: contact.retrieve(fact: .email),
-            phone: contact.retrieve(fact: .phone),
-            nickname: nil,
-            photo: nil,
-            authStatus: status,
-            isRecent: false,
-            createdAt: Date()
-        )
-    }
-}
-
-extension Message {
-    init(with message: BindingsMessage, myId: Data) {
-        guard let payload = try? Payload(with: message.getPayload()!) else { fatalError() }
-
-        self.init(
-            networkId: message.getID()!,
-            senderId: message.getSender()!,
-            recipientId: myId,
-            groupId: nil,
-            date: Date.fromTimestamp(Int(message.getTimestampNano())),
-            status: .received,
-            isUnread: true,
-            text: payload.text,
-            replyMessageId: payload.reply?.messageId,
-            roundURL: message.getRoundURL(),
-            fileTransferId: nil
-        )
-    }
-
-    init(with message: BindingsGroupMessageReceive) {
-        guard let payload = try? Payload(with: message.getPayload()!) else { fatalError() }
-
-        self.init(
-            networkId: message.getMessageID()!,
-            senderId: message.getSenderID()!,
-            recipientId: nil,
-            groupId: message.getGroupID()!,
-            date: Date.fromTimestamp(Int(message.getTimestampNano())),
-            status: .received,
-            isUnread: true,
-            text: payload.text,
-            replyMessageId: payload.reply?.messageId,
-            roundURL: message.getRoundURL(),
-            fileTransferId: nil
-        )
-    }
-}
diff --git a/Sources/Integration/Implementations/Bindings.swift b/Sources/Integration/Implementations/Bindings.swift
deleted file mode 100644
index a05387dda2653644a26a3bc28b40e011c6eb5e03..0000000000000000000000000000000000000000
--- a/Sources/Integration/Implementations/Bindings.swift
+++ /dev/null
@@ -1,613 +0,0 @@
-import Shared
-import Models
-import Bindings
-import XXModels
-import Foundation
-import DependencyInjection
-
-public let evaluateNotification: NotificationEvaluation = BindingsNotificationsForMe
-
-public protocol NotificationReportProtocol {
-    func forMe() -> Bool
-    func type() -> String
-    func source() -> Data?
-}
-
-public protocol NotificationManyReportProtocol {
-    func len() -> Int
-    func get(index: Int) throws -> NotificationReportProtocol
-}
-
-extension BindingsNotificationForMeReport: NotificationReportProtocol {}
-
-extension BindingsManyNotificationForMeReport: NotificationManyReportProtocol {
-    public func get(index: Int) throws -> NotificationReportProtocol {
-        try get(index)
-    }
-}
-
-extension BindingsClient: BindingsInterface {
-    public func removeContact(_ data: Data) throws {
-        do {
-            try deleteContact(data)
-            log(string: "Deleted a contact", type: .info)
-        } catch {
-            log(string: "Failed to delete a contact: \(error.localizedDescription)", type: .error)
-            throw error.friendly()
-        }
-    }
-
-    func dumpThreads() {
-        log(type: .crumbs)
-
-        var error: NSError?
-        let string = BindingsDumpStack(&error)
-
-        if let error = error {
-            log(string: error.localizedDescription, type: .error)
-            return
-        }
-
-        log(string: string, type: .bindings)
-    }
-
-    public func resetSessionWith(_ recipient: Data) {
-        var int: Int = 0
-
-        do {
-            try resetSession(recipient, meMarshaled: meMarshalled, message: "", ret0_: &int)
-        } catch {
-            print(">>> \(error.localizedDescription)")
-        }
-    }
-
-    public func verify(marshaled: Data, verifiedMarshaled: Data) throws -> Bool {
-        var bool: ObjCBool = false
-        try verifyOwnership(marshaled, verifiedMarshaled: verifiedMarshaled, ret0_: &bool)
-        log(string: "Onwership verification: \(bool.boolValue)", type: bool.boolValue ? .info : .error)
-        return bool.boolValue
-    }
-
-    public func compress(
-        image: Data,
-        _ completion: @escaping(Result<Data, Error>) -> Void
-    ) {
-        var error: NSError?
-        let compressed = BindingsCompressJpeg(image, &error)
-
-        guard error == nil else {
-            log(string: "Error when compressing jpeg: \(error!.localizedDescription)", type: .error)
-            completion(.failure(error!.friendly()))
-            return
-        }
-
-        guard let compressed = compressed else {
-            completion(.failure(NSError.create("Image compression failed without error")))
-            return
-        }
-
-        let compressionRate = String(format: "%.4f", Float(compressed.count)/Float(image.count))
-        log(string: "Compressed image x\(compressionRate) (\(image.count) -> \(compressed.count))", type: .info)
-        completion(.success(compressed))
-    }
-
-    public var hasRunningTasks: Bool {
-        hasRunningProcessies()
-    }
-
-    public var myId: Data {
-        guard let user = getUser(), let contact = user.getContact(), let id = contact.getID() else {
-            fatalError("Couldn't get my ID")
-        }
-
-        return id
-    }
-
-    public var meMarshalled: Data {
-        guard let user = getUser(), let contact = user.getContact(), let marshal = try? contact.marshal() else {
-            fatalError("Couldn't get my own contact marshalled")
-        }
-
-        return marshal
-    }
-
-    public func getPreImages() -> String {
-        getPreimages(receptionId)
-    }
-
-    public func meMarshalled(_ username: String, email: String?, phone: String?) -> Data {
-        guard let user = getUser(),
-              let contact = user.getContact(),
-              let factList = contact.getFactList() else { fatalError() }
-
-        try! factList.add(username, factType: FactType.username.rawValue)
-
-        if let email = email {
-            try! factList.add(email, factType: FactType.email.rawValue)
-        }
-
-        if let phone = phone {
-            try! factList.add(phone, factType: FactType.phone.rawValue)
-        }
-
-        return try! contact.marshal()
-    }
-
-    public var receptionId: Data {
-        guard let user = getUser(), let recId = user.getReceptionID() else { fatalError() }
-        return recId
-    }
-
-    public static let version: String = {
-        return BindingsGetVersion()
-    }()
-
-    public static let new: ClientNew = BindingsNewClient
-
-    public static let fromBackup: ClientFromBackup = BindingsNewClientFromBackup
-
-    public static let secret: (Int) -> Data? = BindingsGenerateSecret
-
-    public static let login: (String?, Data?, String?, NSErrorPointer) -> BindingsInterface? = BindingsLogin
-
-    public static func updateNDF(
-        for env: NetworkEnvironment,
-        _ completion: @escaping (Result<Data?, Error>) -> Void
-    ) {
-        var error: NSError?
-        let ndf = BindingsDownloadAndVerifySignedNdfWithUrl(env.url, env.cert, &error)
-
-        guard error == nil else {
-            Self.updateNDF(for: env, completion)
-            return
-        }
-
-        completion(.success(ndf))
-    }
-
-    /// Fetches a JSON with up-to-date error descriptions
-    /// then passes it to the bindings that will emit cleaner
-    /// errors
-    ///
-    /// - ToDo: Request status codes for errors
-    ///
-    public static func updateErrors() {
-        log(type: .crumbs)
-
-        var error: NSError?
-        if let dbErrors = BindingsDownloadErrorDB(&error) {
-            var otherError: NSError?
-            BindingsUpdateCommonErrors(String(data: dbErrors, encoding: .utf8), &otherError)
-
-            if let otherError = otherError {
-                log(string: otherError.localizedDescription, type: .error)
-            }
-        }
-
-        if let error = error {
-            log(string: error.localizedDescription, type: .error)
-        }
-    }
-
-    /// Starts the network
-    ///
-    /// If network status is != 0 it means the network is
-    /// not ready yet or the device is not ready. A recursion was applied
-    /// as a temporary solution in order to retry indefinitely
-    ///
-    /// - ToDo: Split function into smaller functions
-    ///
-    public func startNetwork() {
-        log(type: .crumbs)
-
-        var error: NSError?
-        let status = networkFollowerStatus()
-
-        BindingsLogLevel(1, &error)
-        registerErrorCallback(BindingsError())
-
-        guard status == 0 else {
-            log(string: ">>> Network is not ready yet. Let's give it a second...", type: .error)
-            sleep(1)
-            startNetwork()
-            return
-        }
-
-        try! startNetworkFollower(10000)
-        log(string: ">>> Starting the network...", type: .info)
-    }
-
-    /// (Tries) to stop the network
-    ///
-    /// - Warning: This function tries to stop several
-    ///            threads and it may take some time.
-    ///            That's why we register a background
-    ///            task on AppDelegate.swift
-    ///
-    public func stopNetwork() {
-        log(type: .crumbs)
-
-        try! stopNetworkFollower()
-        log(string: "Stopping the network...", type: .info)
-    }
-
-    /// Extracts *user id* from a contact
-    ///
-    /// - Parameters:
-    ///   - from: Byte array containing contact object
-    ///
-    /// - Returns: Optional byte array, if *user id* could be retrieved
-    ///
-    public func getId(from marshaled: Data) -> Data? {
-        log(type: .crumbs)
-
-        var error: NSError?
-        let contact = BindingsUnmarshalContact(marshaled, &error)
-
-        if let error = error {
-            log(string: error.localizedDescription, type: .error)
-            return nil
-        }
-
-        return contact?.getID()
-    }
-
-    public func add(_ contact: Data, from me: Data, _ completion: @escaping (Result<Bool, Error>) -> Void) {
-        log(type: .crumbs)
-
-        do {
-            var roundId = Int()
-            try requestAuthenticatedChannel(contact, meMarshaled: me, message: nil, ret0_: &roundId)
-            completion(.success(true))
-        } catch {
-            log(string: error.localizedDescription, type: .error)
-            completion(.failure(error.friendly()))
-        }
-    }
-
-    /// Confirms a contact request
-    ///
-    /// - Parameters:
-    ///   - contact: Byte array containing *contact object*
-    ///   - completion: Result callback with associated
-    ///                 values *boolean* = success &&
-    ///                 !timedOut or *Error* upon throwing
-    ///
-    public func confirm(_ contact: Data, _ completion: @escaping (Result<Bool, Error>) -> Void) {
-        log(type: .crumbs)
-
-        do {
-            var roundId = Int()
-            try confirmAuthenticatedChannel(contact, ret0_: &roundId)
-            completion(.success(true))
-        } catch {
-            log(string: error.localizedDescription, type: .error)
-            completion(.failure(error.friendly()))
-        }
-    }
-
-    /// Sends a message over CMIX
-    ///
-    /// - Parameters:
-    ///   - recipient: Byte array containing *user id*
-    ///   - payload: Byte array containing *message payload*
-    ///
-    /// - Returns: Result w/ associated values
-    ///            byte array containing *SentReport*
-    ///            or *Error* upon throwing
-    ///
-    public func send(_ payload: Data, to recipient: Data) -> Result<E2ESendReportType, Error> {
-        log(type: .crumbs)
-
-        do {
-            let report = try sendE2E(recipient, payload: payload, messageType: 2, parameters: nil)
-
-            var roundIds = [Int]()
-
-            if let roundList = report.getRoundList(), let payloadUnwrapped = try? Payload(with: payload) {
-                let length = roundList.len()
-                for index in 0..<length {
-                    var integer: Int = 0
-                    do {
-                        try roundList.get(index, ret0_: &integer)
-                        roundIds.append(integer)
-                    } catch {
-                        log(string: "Error trying to inspect round list: \(error.localizedDescription)", type: .error)
-                    }
-                }
-
-                log(string: "Round ids for \(payloadUnwrapped.text.prefix(5))... = \(roundIds)", type: .info)
-            }
-
-            return .success(report)
-        } catch {
-            log(string: error.localizedDescription, type: .error)
-            return .failure(error)
-        }
-    }
-
-    /// Listens to the delivery of a message through a report
-    ///
-    /// - Note: Delivery actually refers to the
-    ///         gateway, not necessarily the other end
-    ///         received/read this message yet.
-    ///
-    /// - Parameters:
-    ///   - report: SentReport marshalled
-    ///   - completion: Result callback w/ associated
-    ///                 values *completed* or *Error*
-    ///                 upon throwing
-    ///
-    public func listen(report: Data, _ completion: @escaping (Result<MessageDeliveryStatus, Error>) -> Void) {
-        do {
-            try listenDelivery(of: report) { msgId, delivered, timedOut, roundResults in
-                let status: MessageDeliveryStatus
-
-                if delivered == false {
-                    let extendedLogs =
-                    """
-                    Round delivery callback from wait(forMessageDelivery:)
-                    - timedOut = \(timedOut)
-                    - delivered = \(delivered)
-                    """
-                    log(string: extendedLogs, type: .error)
-                    log(string: extendedLogs, type: .error)
-
-                    if timedOut == true {
-                        status = .timedout
-                    } else {
-                        status = .failed
-                    }
-                } else {
-                    status = .sent
-                }
-
-                completion(.success(status))
-            }
-        } catch {
-            completion(.failure(error))
-        }
-    }
-
-    public func registerNotifications(_ token: Data) throws {
-        let tokenString = token.map { String(format: "%02hhx", $0) }.joined()
-
-        do {
-            try register(forNotifications: tokenString)
-        } catch {
-            throw error.friendly()
-        }
-    }
-
-    /// Unregisters device token on backend
-    ///
-    /// - Throws: If when trying to unregister
-    ///           some exception come up such as
-    ///           timing out or user is not registered
-    ///
-    public func unregisterNotifications() throws {
-        log(type: .crumbs)
-
-        do {
-            try unregisterForNotifications()
-            log(string: "Unregistered notifications", type: .info)
-        } catch {
-            log(string: error.localizedDescription, type: .error)
-            throw error.friendly()
-        }
-    }
-
-    /// Checks if number of nodes already registered is enough
-    ///
-    /// Whenever the user wants to do an operation that involves
-    /// *User Discovery*, the app should make sure that a minimum
-    /// amount of nodes already know about this user
-    ///
-    /// - Throws: `NodeRegistrationError.amountIsTooLow` if
-    ///            the ratio is below minimum (currently 85%).
-    ///            `NodeRegistrationError.networkIsNotHealthyYet`
-    ///            when trying to fetch registration status and
-    ///            network is not healthy yet
-    ///
-    public func nodeRegistrationStatus() throws {
-        log(type: .crumbs)
-
-        enum NodeRegistrationError: Error {
-            case amountIsTooLow
-        }
-
-        var shortRatio: String?
-
-        do {
-            let status = try getNodeRegistrationStatus()
-            let registered = Float(status.getRegistered())
-            let total = Float(status.getTotal())
-            let ratio = Float(registered/total)
-
-            let nf = NumberFormatter()
-            nf.roundingMode = .down
-            nf.maximumFractionDigits = 2
-            nf.numberStyle = .percent
-            shortRatio = nf.string(from: NSNumber(value: ratio))
-
-            guard ratio >= 0.85 else { throw NodeRegistrationError.amountIsTooLow }
-            log(string: "Node registration rate: \(shortRatio ?? "")", type: .info)
-        } catch NodeRegistrationError.amountIsTooLow {
-
-            let string = "Node registration rate is still below 85% (\(shortRatio ?? ""))"
-            log(string: string, type: .error)
-
-            let userError = "We are still establishing a secure registration with the decentralized network. Please try again in a few seconds."
-
-            throw NSError.create(userError)
-        } catch {
-            log(string: error.localizedDescription, type: .error)
-            throw error
-        }
-    }
-
-    /// Instantiates a transfer manager
-    ///
-    /// - Returns: An instance of *BindingsFileTransfer (TransferManager)*
-    ///
-    /// - Throws: `FTError.noInstance` if no error was thrown
-    ///            but also no instance was created
-    ///
-    public func generateTransferManager(
-        _ callback: @escaping (Data, String?, String?, Data?) -> Void
-    ) throws -> TransferManagerInterface {
-        log(type: .crumbs)
-
-        let incomingTransferCallback = IncomingTransferCallback { tid, name, type, sender, size, preview in
-            guard let tid = tid else { fatalError("An incoming transfer has no TID?") }
-
-            callback(tid, name, type, sender)
-        }
-
-        var error: NSError?
-        let manager = BindingsNewFileTransferManager(self, incomingTransferCallback, "", &error)
-
-        guard let error = error else { return manager! }
-        throw error.friendly()
-    }
-
-    public func generateDummyTraficManager() throws -> DummyTrafficManaging {
-        var error: NSError?
-        let manager = BindingsNewDummyTrafficManager(self, 5, 30000, 25000, &error)
-
-        guard let error = error else { return manager! }
-        throw error.friendly()
-    }
-
-    public func generateUDFromBackup(email: String?, phone: String?) throws -> UserDiscoveryInterface {
-        var error: NSError?
-
-        let paramEmail = email != nil ? "E\(email!)" : nil
-        let paramPhone = phone != nil ? "P\(phone!)" : nil
-
-        let udb = BindingsNewUserDiscoveryFromBackup(self, paramEmail, paramPhone, &error)
-
-        /// Alternate udb
-
-        guard let certPath = Bundle.module.path(forResource: "ud.elixxir.io", ofType: "crt") else {
-            fatalError("Couldn't retrieve cert.")
-        }
-
-        guard let contactFilePath = Bundle.module.path(forResource: "udContact-test", ofType: "bin") else {
-            fatalError("Couldn't retrieve cert.")
-        }
-
-//        try! udb!.setAlternative(
-//            "18.198.117.203:11420".data(using: .utf8),
-//            cert: try! Data(contentsOf: URL(fileURLWithPath: certPath)),
-//            contactFile: try! Data(contentsOf: URL(fileURLWithPath: contactFilePath))
-//        )
-
-        guard let error = error else { return udb! }
-        throw error.friendly()
-    }
-
-    public func generateUD() throws -> UserDiscoveryInterface {
-        log(type: .crumbs)
-
-        var error: NSError?
-        let udb = BindingsNewUserDiscovery(self, &error)
-
-        /// Alternate udb
-
-        guard let certPath = Bundle.module.path(forResource: "ud.elixxir.io", ofType: "crt") else {
-            fatalError("Couldn't retrieve cert.")
-        }
-
-        guard let contactFilePath = Bundle.module.path(forResource: "udContact-test", ofType: "bin") else {
-            fatalError("Couldn't retrieve cert.")
-        }
-
-//        try! udb!.setAlternative(
-//            "18.198.117.203:11420".data(using: .utf8),
-//            cert: try! Data(contentsOf: URL(fileURLWithPath: certPath)),
-//            contactFile: try! Data(contentsOf: URL(fileURLWithPath: contactFilePath))
-//        )
-
-        guard let error = error else { return udb! }
-        throw error.friendly()
-    }
-
-    public func restore(
-        ids: Data,
-        using ud: UserDiscoveryInterface,
-        lookupCallback: @escaping (Result<Contact, Error>) -> Void,
-        restoreCallback: @escaping (Int, Int, Int, String?) -> Void
-    ) -> RestoreReportType {
-        let restoreCb = RestoreContactsCallback(restoreCallback)
-
-        let lookupCb = LookupCallback {
-            switch $0 {
-            case .success(let contact):
-                lookupCallback(.success(.init(with: contact, status: .stranger)))
-            case .failure(let error):
-                lookupCallback(.failure(error))
-            }
-        }
-
-        return BindingsRestoreContactsFromBackup(ids, self, ud as? BindingsUserDiscovery, lookupCb, restoreCb)!
-    }
-}
-
-extension BindingsContact {
-
-    /// Scans the contact instance for a specified fact
-    ///
-    /// - Parameters:
-    ///   - fact: enum defined in ```FactType```
-    ///           that specifies the type we're
-    ///           searching
-    ///
-    /// - Note: Since GoLang does not support collections
-    ///         We need to do this workaround *length* and
-    ///         *get* instead of subscripting as in Swift.
-    ///
-    /// - Returns: Optional string in case we find the the fact
-    ///
-    /// - ToDo: Return a struct that contains all possible facts (?)
-    ///
-    func retrieve(fact: FactType) -> String? {
-        log(type: .crumbs)
-
-        guard let factList = getFactList() else { return nil }
-        for index in 0..<factList.num() {
-            if let actualFact = factList.get(index) {
-                if actualFact.type() == fact.rawValue {
-                    return String(actualFact.stringify().dropFirst())
-                }
-            }
-        }
-        return nil
-    }
-}
-
-extension BindingsSendReport: E2ESendReportType {
-    public var marshalled: Data { try! marshal() }
-    public var timestamp: Int64 { getTimestampNano() }
-    public var uniqueId: Data? { getMessageID() }
-    public var roundURL: String { getRoundURL() }
-}
-
-public protocol DummyTrafficManaging {
-    var status: Bool { get }
-    func setStatus(status: Bool)
-}
-
-extension BindingsDummyTraffic: DummyTrafficManaging {
-    public var status: Bool {
-        getStatus()
-    }
-
-    public func setStatus(status: Bool) {
-        try? setStatus(status)
-    }
-}
-
-extension BindingsBackup: BackupInterface {}
-
-extension BindingsRestoreContactsReport: RestoreReportType {}
diff --git a/Sources/Integration/Implementations/GroupManager.swift b/Sources/Integration/Implementations/GroupManager.swift
deleted file mode 100644
index 4b3dc4ef2e03abff18cea433fc30a1f2ed424b33..0000000000000000000000000000000000000000
--- a/Sources/Integration/Implementations/GroupManager.swift
+++ /dev/null
@@ -1,94 +0,0 @@
-import Models
-import XXModels
-import Bindings
-
-extension BindingsGroupChat: GroupManagerInterface {
-    public func send(_ payload: Data, to group: Data) -> Result<(Int64, Data?, String), Error> {
-        log(type: .crumbs)
-
-        do {
-            let report = try send(group, message: payload)
-            return .success((
-                report.getRoundID(),
-                report.getMessageID(),
-                report.getRoundURL()
-            ))
-        } catch {
-            return .failure(error)
-        }
-    }
-
-    public func create(
-        me: Data,
-        name: String,
-        welcome: String?,
-        with ids: [Data],
-        _ completion: @escaping (Result<Group, Error>) -> Void
-    ) {
-        log(type: .crumbs)
-
-        let list = BindingsIdList()
-        ids.forEach { try? list.add($0) }
-
-        var welcomeData: Data?
-
-        DispatchQueue.global().async { [weak self] in
-            guard let self = self else { return }
-
-            if let welcome = welcome {
-                welcomeData = welcome.data(using: .utf8)
-            }
-
-            let report = self.makeGroup(list, name: name.data(using: .utf8), message: welcomeData)
-
-            if let status = report?.getStatus() {
-                switch status {
-                case 0:
-                    completion(.failure(NSError.create("An error occurred before any requests could be sent")))
-                    return
-                case 1, 2:
-                    // 1. All requests failed to send
-                    // 2. Some requests failed and some succeeded
-
-                    if let id = report?.getGroup()?.getID() {
-                        do {
-                            try self.resendRequest(id)
-                            fallthrough
-                        } catch {
-                            completion(.failure(error))
-                            return
-                        }
-                    }
-                case 3:
-                    // All good
-                    guard let group = report?.getGroup() else {
-                        let errorContent = "Couldn't get report from group, although status was 3."
-                        completion(.failure(NSError.create(errorContent)))
-                        log(string: errorContent, type: .error)
-                        return
-                    }
-
-                    completion(.success(.init(
-                        id: group.getID()!,
-                        name: name,
-                        leaderId: me,
-                        createdAt: Date(),
-                        authStatus: .participating,
-                        serialized: group.serialize()!
-                    )))
-                    return
-                default:
-                    break
-                }
-            }
-        }
-    }
-
-    public func join(_ serializedGroup: Data) throws {
-        try joinGroup(serializedGroup)
-    }
-
-    public func leave(_ groupId: Data) throws {
-        try leaveGroup(groupId)
-    }
-}
diff --git a/Sources/Integration/Implementations/TransferManager.swift b/Sources/Integration/Implementations/TransferManager.swift
deleted file mode 100644
index 8c38a91fcc20eb289d83d0a62d9efb71592f2554..0000000000000000000000000000000000000000
--- a/Sources/Integration/Implementations/TransferManager.swift
+++ /dev/null
@@ -1,63 +0,0 @@
-import Models
-import Bindings
-import Foundation
-
-extension BindingsFileTransfer: TransferManagerInterface {
-
-    public func endTransferUpload(
-        with TID: Data
-    ) throws {
-        try closeSend(TID)
-    }
-
-    public func listenUploadFromTransfer(
-        with id: Data,
-        _ callback: @escaping (Bool, Int, Int, Int, Error?) -> Void
-    ) throws {
-        let cb = OutgoingTransferProgressCallback { completed, sent, arrived, total, error in
-            callback(completed, sent, arrived, total, error)
-        }
-
-        try registerSendProgressCallback(id, progressFunc: cb, periodMS: 1000)
-    }
-
-    public func listenDownloadFromTransfer(
-        with id: Data,
-        _ callback: @escaping (Bool, Int, Int, Error?) -> Void
-    ) throws {
-        let cb = IncomingTransferProgressCallback { completed, received, total, error in
-            callback(completed, received, total, error)
-        }
-
-        try registerReceiveProgressCallback(id, progressFunc: cb, periodMS: 1000)
-    }
-
-    public func downloadFileFromTransfer(
-        with id: Data
-    ) throws -> Data {
-        try receive(id)
-    }
-
-    public func uploadFile(
-        url: URL,
-        to recipient: Data,
-        _ callback: @escaping (Bool, Int, Int, Int, Error?) -> Void
-    ) throws -> Data {
-        let cb = OutgoingTransferProgressCallback { completed, sent, arrived, total, error in
-            callback(completed, sent, arrived, total, error)
-        }
-
-        guard let file = try? Data(contentsOf: url) else { fatalError() }
-
-        return try send(
-            url.lastPathComponent,
-            fileType: url.pathExtension,
-            fileData: file,
-            recipientID: recipient,
-            retry: 1,
-            preview: nil,
-            progressFunc: cb,
-            periodMS: 1000
-        )
-    }
-}
diff --git a/Sources/Integration/Implementations/UserDiscovery.swift b/Sources/Integration/Implementations/UserDiscovery.swift
deleted file mode 100644
index 56c9b4de349c6cc807e5a1e7e78a2755ffe7715e..0000000000000000000000000000000000000000
--- a/Sources/Integration/Implementations/UserDiscovery.swift
+++ /dev/null
@@ -1,166 +0,0 @@
-import Retry
-import Models
-import XXModels
-import Bindings
-import Foundation
-
-extension BindingsUserDiscovery: UserDiscoveryInterface {
-    public func lookup(forUserId: Data, _ completion: @escaping (Result<Contact, Error>) -> Void) {
-        let callback = LookupCallback {
-            switch $0 {
-            case .success(let contact):
-                completion(.success(.init(with: contact, status: .stranger)))
-            case .failure(let error):
-                completion(.failure(error))
-            }
-        }
-
-        retry(max: 10, retryStrategy: .delay(seconds: 1)) { [weak self] in
-            guard let self = self else { return }
-            try self.lookup(forUserId, callback: callback, timeoutMS: 20000)
-        }.finalCatch { error in
-            log(string: "UD.lookup 4E2E failed:\n\(error.localizedDescription)", type: .error)
-            completion(.failure(error.friendly()))
-        }
-    }
-
-    public func lookup(idList: [Data], _ completion: @escaping (Result<[Contact], Error>) -> Void) {
-        let list = BindingsIdList()
-        idList.forEach { try? list.add($0) }
-
-        let callback = MultiLookupCallback { [weak self] contactList, idList, error in
-            guard let self = self else { return }
-
-            if let error = error, error.count > 2 {
-                log(string: "UD.lookup group failed: \(error)", type: .error)
-                completion(.failure(NSError.create(error).friendly()))
-                return
-            }
-
-            guard let contacts = contactList else { return }
-            let count = contacts.len()
-            var results = [Contact]()
-
-            for index in 0..<count {
-                guard let contact = try? contacts.get(index),
-                      let marshal = try? contact.marshal(),
-                      ((try? self.retrieve(from: marshal, fact: .username) != nil) != nil) else {
-                    log(string: "Skipping", type: .error); continue
-                }
-
-                results.append(Contact(with: contact, status: .stranger))
-            }
-
-            completion(.success(results))
-        }
-
-        DispatchQueue.global().async { [weak self] in
-            guard let self = self else { return }
-
-            do {
-                try self.multiLookup(list, callback: callback, timeoutMS: 30000)
-            } catch {
-                log(string: "UD.lookup group failed: \(error.localizedDescription)", type: .error)
-                completion(.failure(error.friendly()))
-            }
-        }
-    }
-
-    public func deleteMyself(_ username: String) throws {
-        log(type: .crumbs)
-
-        do {
-            try removeUser("U\(username)")
-        } catch {
-            throw error.friendly()
-        }
-    }
-
-    public func register(_ fact: FactType, value: String, _ completion: @escaping (Result<String?, Error>) -> Void) {
-        log(type: .crumbs)
-
-        if fact == .username {
-            do {
-                try register(value)
-                completion(.success(value))
-                return
-            } catch {
-                completion(.failure(error.friendly()))
-                return
-            }
-        }
-
-        var error: NSError?
-        let bindingsFact = BindingsNewFact(fact.rawValue, value, &error)
-
-        if let error = error {
-            completion(.failure(error.friendly()))
-            return
-        }
-
-        var otherError: NSError?
-        let confirmationId = addFact(bindingsFact?.stringify(), error: &otherError)
-
-        if let otherError = otherError {
-            completion(.failure(otherError))
-            return
-        }
-
-        completion(.success(confirmationId))
-    }
-
-    public func confirm(code: String, id: String) throws {
-        log(type: .crumbs)
-
-        do {
-            try confirmFact(id, code: code)
-        } catch {
-            throw error.friendly()
-        }
-    }
-
-    public func retrieve(
-        from marshaled: Data,
-        fact: FactType
-    ) throws -> String? {
-
-        log(type: .crumbs)
-
-        var error: NSError?
-        let contact = BindingsUnmarshalContact(marshaled, &error)
-        if let err = error {
-            throw err.friendly()
-        }
-
-        return contact?.retrieve(fact: fact)
-    }
-
-    public func remove(_ fact: String) throws {
-        log(type: .crumbs)
-
-        do {
-            try removeFact(fact)
-        } catch {
-            throw error.friendly()
-        }
-    }
-
-    public func search(fact: String, _ completion: @escaping (Result<Contact, Error>) -> Void) throws {
-        log(type: .crumbs)
-
-        let callback = SearchCallback {
-            switch $0 {
-            case .success(let contact):
-                completion(.success(Contact(with: contact, status: .stranger)))
-            case .failure(let error):
-                completion(.failure(error))
-            }
-        }
-
-        do {
-            try searchSingle(fact, callback: callback, timeoutMS: 50000)
-        } catch {
-            throw error.friendly()
-        }
-    }
-}
diff --git a/Sources/Integration/Interfaces/BindingsInterface.swift b/Sources/Integration/Interfaces/BindingsInterface.swift
deleted file mode 100644
index b2eef8f94ba3283557530f35ca68e83a2b8dba62..0000000000000000000000000000000000000000
--- a/Sources/Integration/Interfaces/BindingsInterface.swift
+++ /dev/null
@@ -1,174 +0,0 @@
-import Models
-import Combine
-import XXModels
-import Foundation
-
-public enum MessageDeliveryStatus {
-    case sent
-    case failed
-    case timedout
-}
-
-public typealias DeliveryResult = (Data?, Bool, Bool, Data?)
-
-public typealias BackendEvent = (Int, String?, String?, String?)
-
-public typealias ClientNew = (String?, String?, Data?, String?, NSErrorPointer) -> Bool
-
-public typealias ClientFromBackup = (String?, String?, Data?, Data?, Data?, NSErrorPointer) -> Data?
-
-public typealias NotificationEvaluation = (String?, String?, NSErrorPointer) -> NotificationManyReportProtocol?
-
-public protocol E2ESendReportType {
-    var timestamp: Int64 { get }
-    var uniqueId: Data? { get }
-    var marshalled: Data { get }
-    var roundURL: String { get }
-}
-
-public protocol BackupInterface {
-    func stop() throws
-    func addJson(_: String?)
-    func isBackupRunning() -> Bool
-}
-
-public protocol RestoreReportType {
-    func lenFailed() -> Int
-    func lenRestored() -> Int
-    func getErrorAt(_: Int) -> String
-    func getFailedAt(_: Int) -> Data?
-    func getRestoreContactsError() -> String
-    func getRestoredAt(_: Int) -> Data?
-}
-
-public protocol BindingsInterface {
-
-    // MARK: Properties
-
-    var myId: Data { get }
-
-    var hasRunningTasks: Bool { get }
-
-    var receptionId: Data { get }
-
-    var meMarshalled: Data { get }
-
-    func meMarshalled(_: String, email: String?, phone: String?) -> Data
-
-    func verify(marshaled: Data, verifiedMarshaled: Data) throws -> Bool
-
-    func nodeRegistrationStatus() throws
-
-    // MARK: Static
-
-    static func updateErrors()
-
-    static var version: String { get }
-
-    static var secret: (Int) -> Data? { get }
-
-    static var login: (String?, Data?, String?, NSErrorPointer) -> BindingsInterface? { get }
-
-    static var new: ClientNew { get }
-
-    static var fromBackup: ClientFromBackup { get }
-
-    static func updateNDF(for: NetworkEnvironment, _: @escaping (Result<Data?, Error>) -> Void)
-
-    // MARK: Network
-
-    func startNetwork()
-    
-    func stopNetwork()
-
-    func replayRequests()
-
-    // MARK: Contacts
-    
-    func getId(from: Data) -> Data?
-
-    func confirm(_: Data, _: @escaping (Result<Bool, Error>) -> Void)
-
-    func add(_: Data, from: Data, _: @escaping (Result<Bool, Error>) -> Void)
-
-    // MARK: Messages
-
-    func send(_ payload: Data, to recipient: Data) -> Result<E2ESendReportType, Error>
-
-    func compress(image: Data, _: @escaping(Result<Data, Error>) -> Void)
-
-    func resetSessionWith(_: Data)
-
-    func listen(
-        report: Data,
-        _: @escaping (Result<MessageDeliveryStatus, Error>) -> Void
-    )
-    
-    func listenRound(
-        id: Int,
-        _: @escaping (Result<Bool, Error>) -> Void
-    )
-
-    // MARK: Notifications
-
-    func getPreImages() -> String
-
-    func registerNotifications(_ token: Data) throws
-
-    func unregisterNotifications() throws
-
-    func generateDummyTraficManager() throws -> DummyTrafficManaging
-
-    // MARK: UD
-    
-    func generateUD() throws -> UserDiscoveryInterface
-
-    func generateUDFromBackup(email: String?, phone: String?) throws -> UserDiscoveryInterface
-
-    // MARK: FileTransfer
-
-    func generateTransferManager(
-        _: @escaping (Data, String?, String?, Data?) -> Void
-    ) throws -> TransferManagerInterface
-
-    // MARK: Listeners
-
-    static func listenLogs()
-
-    func listenEvents(_: @escaping (BackendEvent) -> Void)
-
-    func listenMessages(_: @escaping (Message) -> Void) throws
-
-    func initializeBackup(
-        passphrase: String,
-        callback: @escaping (Data) -> Void
-    ) -> BackupInterface
-
-    func resumeBackup(
-        callback: @escaping (Data) -> Void
-    ) -> BackupInterface
-
-    func listenRequests(
-        _ requests: @escaping (Contact) -> Void,
-        _ confirmations: @escaping (Contact) -> Void,
-        _ resets: @escaping (Contact) -> Void
-    )
-
-    func listenPreImageUpdates()
-
-    func listenGroupRequests(
-        _: @escaping (Group, [Data], String?) -> Void,
-        groupMessages: @escaping (Message) -> Void
-    ) throws -> GroupManagerInterface?
-
-    func listenNetworkUpdates(_: @escaping (Bool) -> Void)
-
-    func removeContact(_ data: Data) throws
-
-    func restore(
-        ids: Data,
-        using: UserDiscoveryInterface,
-        lookupCallback: @escaping (Result<Contact, Error>) -> Void,
-        restoreCallback: @escaping (Int, Int, Int, String?) -> Void
-    ) -> RestoreReportType
-}
diff --git a/Sources/Integration/Interfaces/GroupManagerInterface.swift b/Sources/Integration/Interfaces/GroupManagerInterface.swift
deleted file mode 100644
index dcddfa9e39efe1f67d33a172e28c5cf84b595267..0000000000000000000000000000000000000000
--- a/Sources/Integration/Interfaces/GroupManagerInterface.swift
+++ /dev/null
@@ -1,14 +0,0 @@
-import Models
-import XXModels
-import Foundation
-
-public protocol GroupManagerInterface {
-
-    func join(_: Data) throws
-
-    func leave(_: Data) throws
-
-    func send(_: Data, to: Data) -> Result<(Int64, Data?, String), Error>
-
-    func create(me: Data, name: String, welcome: String?, with: [Data], _: @escaping (Result<Group, Error>) -> Void)
-}
diff --git a/Sources/Integration/Interfaces/TransferManagerInterface.swift b/Sources/Integration/Interfaces/TransferManagerInterface.swift
deleted file mode 100644
index b95d1ee34d2cd154192f74b336a44d6deed9dc69..0000000000000000000000000000000000000000
--- a/Sources/Integration/Interfaces/TransferManagerInterface.swift
+++ /dev/null
@@ -1,27 +0,0 @@
-import Foundation
-
-public protocol TransferManagerInterface {
-    func endTransferUpload(
-        with TID: Data
-    ) throws
-
-    func listenUploadFromTransfer(
-        with: Data,
-        _: @escaping (Bool, Int, Int, Int, Error?) -> Void
-    ) throws
-
-    func listenDownloadFromTransfer(
-        with: Data,
-        _: @escaping (Bool, Int, Int, Error?) -> Void
-    ) throws
-
-    func downloadFileFromTransfer(
-        with: Data
-    ) throws -> Data
-
-    func uploadFile(
-        url: URL,
-        to: Data,
-        _: @escaping (Bool, Int, Int, Int, Error?) -> Void
-    ) throws -> Data
-}
diff --git a/Sources/Integration/Interfaces/UserDiscoveryInterface.swift b/Sources/Integration/Interfaces/UserDiscoveryInterface.swift
deleted file mode 100644
index ded311ecdf19e7b179b2f91d325588f57a33ff2d..0000000000000000000000000000000000000000
--- a/Sources/Integration/Interfaces/UserDiscoveryInterface.swift
+++ /dev/null
@@ -1,27 +0,0 @@
-import Models
-import XXModels
-import Foundation
-
-public struct LookupResult {
-    public let id: Data
-    public let username: String
-}
-
-public protocol UserDiscoveryInterface {
-
-    func remove(_: String) throws
-
-    func deleteMyself(_: String) throws
-
-    func confirm(code: String, id: String) throws
-
-    func retrieve(from: Data, fact: FactType) throws -> String?
-
-    func lookup(forUserId: Data, _: @escaping (Result<Contact, Error>) -> Void)
-
-    func search(fact: String, _: @escaping (Result<Contact, Error>) -> Void) throws
-
-    func lookup(idList: [Data], _: @escaping (Result<[Contact], Error>) -> Void)
-
-    func register(_: FactType, value: String, _: @escaping (Result<String?, Error>) -> Void)
-}
diff --git a/Sources/Integration/Listeners.swift b/Sources/Integration/Listeners.swift
deleted file mode 100644
index 7ab877603cb879c6d660384a0a596e259a8856e3..0000000000000000000000000000000000000000
--- a/Sources/Integration/Listeners.swift
+++ /dev/null
@@ -1,151 +0,0 @@
-import Models
-import Shared
-import os.log
-import Combine
-import XXModels
-import Bindings
-import Foundation
-
-public extension BindingsClient {
-    static func listenLogs() {
-        let callback = LogCallback { log(string: $0 ?? "", type: .bindings) }
-        BindingsRegisterLogWriter(callback)
-    }
-
-    func listenPreImageUpdates() {
-        let callback = PreImageCallback { [weak self] _, _ in
-            if let defaults = UserDefaults(suiteName: "group.elixxir.messenger") {
-                let preImage = self?.getPreImages()
-                defaults.set(preImage, forKey: "preImage")
-            }
-        }
-
-        registerPreimageCallback(receptionId, pin: callback)
-    }
-
-    func initializeBackup(passphrase: String, callback: @escaping (Data) -> Void) -> BackupInterface {
-        var error: NSError?
-        os_signpost(.begin, log: logHandler, name: "Encrypting", "Calling BindingsInitializeBackup")
-        let backup = BindingsInitializeBackup(passphrase, UpdateBackupCallback(callback), self, &error)
-        os_signpost(.end, log: logHandler, name: "Encrypting", "Finished BindingsInitializeBackup")
-        return backup!
-    }
-
-    func resumeBackup(callback: @escaping (Data) -> Void) -> BackupInterface {
-        var error: NSError?
-        let backup = BindingsResumeBackup(UpdateBackupCallback(callback), self, &error)
-        return backup!
-    }
-
-    func listenMessages(_ callback: @escaping (Message) -> Void) throws {
-        let zeroBytes = [UInt8](repeating: 0, count: 33)
-
-        let listener = TextListener { bindingsMessage in
-            guard let message = bindingsMessage else { return }
-            let domainModel = Message(with: message, myId: self.myId)
-            callback(domainModel)
-        }
-
-        _ = try! registerListener(Data(zeroBytes), msgType: 2, listener: listener)
-    }
-
-    func listenRequests(
-        _ requests: @escaping (Contact) -> Void,
-        _ confirmations: @escaping (Contact) -> Void,
-        _ resets: @escaping (Contact) -> Void
-    ) {
-        let resetCallback = ResetCallback { resets(Contact(with: $0, status: .friend)) }
-        let confirmCallback = ConfirmationCallback { confirmations(Contact(with: $0, status: .friend)) }
-        let requestCallback = RequestCallback { requests(Contact(with: $0, status: .verificationInProgress)) }
-        registerAuthCallbacks(requestCallback, confirm: confirmCallback, reset: resetCallback)
-    }
-
-    func listenNetworkUpdates(_ callback: @escaping (Bool) -> Void) {
-        registerNetworkHealthCB(HealthCallback(callback))
-    }
-
-    func listenEvents(_ completion: @escaping (BackendEvent) -> Void) {
-        do {
-            try registerEventCallback("EventListener", myObj: EventCallback(completion))
-        } catch {
-            log(string: ">>> Event listener failed: \(error.localizedDescription)", type: .error)
-        }
-    }
-
-    func listenRound(id: Int, _ completion: @escaping (Result<Bool, Error>) -> Void) {
-        let callback = RoundCallback { completion(.success($0)) }
-        
-        do {
-            try wait(forRoundCompletion: id, rec: callback, timeoutMS: 15000)
-        } catch {
-            completion(.failure(error))
-        }
-    }
-
-    func listenDelivery(of report: Data, _ completion: @escaping (DeliveryResult) -> Void) throws {
-        let callback = DeliveryCallback { completion($0) }
-
-        var roundIds = [Int]()
-
-        var unmarshalError: NSError?
-
-        if let unmarshaled = BindingsUnmarshalSendReport(report, &unmarshalError),
-            let roundList = unmarshaled.getRoundList() {
-            let length = roundList.len()
-            for index in 0..<length {
-                var integer: Int = 0
-                do {
-                    try roundList.get(index, ret0_: &integer)
-                    roundIds.append(integer)
-                } catch {
-                    log(string: ">>> Error inspecting round list:\n\(error.localizedDescription)", type: .error)
-                }
-            }
-        }
-
-        try! wait(forMessageDelivery: report, mdc: callback, timeoutMS: 30000)
-    }
-
-    func listenGroupRequests(
-        _ groupRequests: @escaping (Group, [Data], String?) -> Void,
-        groupMessages: @escaping (Message) -> Void
-    ) throws -> GroupManagerInterface? {
-        var error: NSError?
-
-        let requestCallback = GroupRequestCallback {
-            guard let id = $0.getID(),
-                  let name = $0.getName(),
-                  let serialize = $0.serialize(),
-                  let memberList = $0.getMembership() else { return }
-
-            var members = [Data]()
-
-            var welcomeMessage: String?
-
-            if let welcomeData = $0.getInitMessage() {
-                welcomeMessage = String(data: welcomeData, encoding: .utf8)
-            }
-
-            for index in 0..<memberList.len() {
-                guard let member = try? memberList.get(index),
-                      let memberId = member.getID() else { continue }
-                members.append(memberId)
-            }
-
-            groupRequests(.init(
-                id: id,
-                name: String(data: name, encoding: .utf8)!,
-                leaderId: members.first!,
-                createdAt: Date(),
-                authStatus: .pending,
-                serialized: serialize
-            ), members, welcomeMessage)
-        }
-
-        let messageCallback = GroupMessageCallback { groupMessages(Message(with: $0)) }
-        let groupManager = BindingsNewGroupManager(self, requestCallback, messageCallback, &error)
-
-        guard let error = error else { return groupManager }
-        fatalError(error.localizedDescription)
-    }
-}
diff --git a/Sources/Integration/Logging.swift b/Sources/Integration/Logging.swift
deleted file mode 100644
index c37e60b32c1261112930efe2a84248a74290fe3b..0000000000000000000000000000000000000000
--- a/Sources/Integration/Logging.swift
+++ /dev/null
@@ -1,85 +0,0 @@
-import Bindings
-import XXLogger
-import CrashReporting
-import DependencyInjection
-import Foundation
-import os
-
-let oslogger = Logger(subsystem: "logs_xxmessenger", category: "Logging.swift")
-
-final class BindingsError: NSObject, BindingsClientErrorProtocol {
-    func report(_ source: String?, message: String?, trace: String?) {
-        var content = ""
-
-        content += String(describing: source) + "\n"
-        content += String(describing: message) + "\n"
-        content += String(describing: trace)
-
-        log(string: content, type: .error)
-    }
-}
-
-extension Error {
-    func friendly() -> NSError {
-        log(string: ">>> Switching to friendly error from: \(localizedDescription)", type: .error)
-        
-        let error = BindingsErrorStringToUserFriendlyMessage(localizedDescription)
-        if error.hasPrefix("UR") {
-            let crashReporter = try! DependencyInjection.Container.shared.resolve() as CrashReporter
-            crashReporter.sendError(self as NSError)
-            return NSError.create("Unexpected error. Please try again")
-        } else {
-            return NSError.create(error)
-        }
-    }
-}
-
-enum LogType {
-    case info
-    case error
-    case crumbs
-    case bindings
-
-    var icon: String {
-        switch self {
-        case .error:
-            return "🟥"
-        case .crumbs:
-            return "🍞"
-        case .bindings:
-            return "⚙️"
-        case .info:
-            return "✅"
-        }
-    }
-}
-
-func log(
-    string: String? = nil,
-    type: LogType,
-    function: String = #function,
-    file: String = #file,
-    line: Int = #line
-) {
-    var trimmedFile = ""
-    if let index = file.lastIndex(of: "/") {
-        let afterEqualsTo = String(file.suffix(from: index).dropFirst())
-        trimmedFile = afterEqualsTo
-    }
-
-    let content = "\(type.icon) \(function) @\(trimmedFile):\(line) \(string ?? "")"
-    let logger = try! DependencyInjection.Container.shared.resolve() as XXLogger
-
-    switch type {
-    case .info:
-        logger.info(content)
-        oslogger.info("\(content)")
-    case .error:
-        logger.error(content)
-        oslogger.error("\(content)")
-    case .crumbs:
-        logger.debug(content)
-    case .bindings:
-        logger.warning(content)
-    }
-}
diff --git a/Sources/Integration/Mocks/GroupManagerMock.swift b/Sources/Integration/Mocks/GroupManagerMock.swift
deleted file mode 100644
index 137cfca69c25a188f20c60af867befc3d79a04cf..0000000000000000000000000000000000000000
--- a/Sources/Integration/Mocks/GroupManagerMock.swift
+++ /dev/null
@@ -1,21 +0,0 @@
-import Models
-import XXModels
-import Foundation
-
-final class GroupManagerMock: GroupManagerInterface {
-    func join(_: Data) throws {}
-
-    func leave(_: Data) throws {}
-
-    func send(_: Data, to: Data) -> Result<(Int64, Data?, String), Error> {
-        .success((1, nil, "https://www.google.com.br"))
-    }
-
-    func create(
-        me: Data,
-        name: String,
-        welcome: String?,
-        with: [Data],
-        _: @escaping (Result<Group, Error>) -> Void
-    ) {}
-}
diff --git a/Sources/Integration/Mocks/TransferManagerMock.swift b/Sources/Integration/Mocks/TransferManagerMock.swift
deleted file mode 100644
index 9b87da5d214d5cf0dcc5d39cdd88a979ff1a6e76..0000000000000000000000000000000000000000
--- a/Sources/Integration/Mocks/TransferManagerMock.swift
+++ /dev/null
@@ -1,33 +0,0 @@
-import Foundation
-
-final class TransferManagerMock: TransferManagerInterface {
-    func endTransferUpload(
-        with TID: Data
-    ) throws {}
-
-    func listenDownloadFromTransfer(
-        with: Data,
-        _: @escaping (Bool, Int, Int, Error?) -> Void
-    ) throws {
-        fatalError()
-    }
-
-    func listenUploadFromTransfer(
-        with: Data,
-        _: @escaping (Bool, Int, Int, Int, Error?) -> Void
-    ) throws {}
-
-    func downloadFileFromTransfer(
-        with: Data
-    ) throws -> Data {
-        fatalError()
-    }
-
-    func uploadFile(
-        url: URL,
-        to: Data,
-        _: @escaping (Bool, Int, Int, Int, Error?) -> Void
-    ) throws -> Data {
-        Data()
-    }
-}
diff --git a/Sources/Integration/Mocks/UserDiscoveryMock.swift b/Sources/Integration/Mocks/UserDiscoveryMock.swift
deleted file mode 100644
index bb1a8f2440ce0baf65bd8eb5dff4ef305babb842..0000000000000000000000000000000000000000
--- a/Sources/Integration/Mocks/UserDiscoveryMock.swift
+++ /dev/null
@@ -1,45 +0,0 @@
-import Models
-import XXModels
-import Foundation
-
-final class UserDiscoveryMock: UserDiscoveryInterface {
-
-    func remove(_ fact: String) throws {}
-
-    func deleteMyself(_ username: String) throws {}
-
-    func confirm(code: String, id: String) throws {}
-
-    func lookup(idList: [Data], _: @escaping (Result<[Contact], Error>) -> Void) {}
-
-    func retrieve(from: Data, fact: FactType) throws -> String? { fact.description }
-
-    func search(fact: String, _ completion: @escaping (Result<Contact, Error>) -> Void) throws {
-        completion(.success(.georgeDiscovered))
-    }
-
-    func register(_: FactType, value: String, _ completion: @escaping (Result<String?, Error>) -> Void) {
-        completion(.success("#CONFIRMATION_CODE_FOR \(value)"))
-    }
-
-    func lookup(
-        forUserId: Data,
-        _ completion: @escaping (Result<Contact, Error>) -> Void
-    ) {
-        DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
-            completion(.success(
-                .init(
-                    id: "mock_username".data(using: .utf8)!,
-                    marshaled: "mock_username".data(using: .utf8)!,
-                    username: "mock_username",
-                    email: nil,
-                    phone: nil,
-                    nickname: "mock_nickname",
-                    photo: nil,
-                    authStatus: .stranger,
-                    isRecent: false,
-                    createdAt: Date()
-            )))
-        }
-    }
-}
diff --git a/Sources/Integration/Resources/cert_mainnet.txt b/Sources/Integration/Resources/cert_mainnet.txt
deleted file mode 100644
index 40045d63666dded7450e22eb82c15b62a17d4d68..0000000000000000000000000000000000000000
--- a/Sources/Integration/Resources/cert_mainnet.txt
+++ /dev/null
@@ -1 +0,0 @@
-[PLACE THE CERTIFICATE CONTENT HERE]
diff --git a/Sources/Integration/Session/Session+Chat.swift b/Sources/Integration/Session/Session+Chat.swift
deleted file mode 100644
index b8d6e02d45f0cb6681fe206a31c117d7807a70c5..0000000000000000000000000000000000000000
--- a/Sources/Integration/Session/Session+Chat.swift
+++ /dev/null
@@ -1,270 +0,0 @@
-import UIKit
-import Models
-import Shared
-import XXModels
-import Foundation
-
-extension Session {
-    public func send(imageData: Data, to contact: Contact, completion: @escaping (Result<Void, Error>) -> Void) {
-        client.bindings.compress(image: imageData) { [weak self] result in
-            guard let self = self else {
-                completion(.success(()))
-                return
-            }
-
-            switch result {
-            case .success(let compressedImage):
-                do {
-                    let url = try FileManager.store(
-                        data: compressedImage,
-                        name: "image_\(Date.asTimestamp)",
-                        type: "jpeg"
-                    )
-
-                    self.sendFile(url: url, to: contact)
-                    completion(.success(()))
-                } catch {
-                    completion(.failure(error))
-                }
-
-            case .failure(let error):
-                completion(.failure(error))
-                log(string: "Error when compressing image: \(error.localizedDescription)", type: .error)
-            }
-        }
-    }
-
-    public func sendFile(url: URL, to contact: Contact) {
-        guard let manager = client.transferManager else { fatalError("A transfer manager was not created") }
-
-        DispatchQueue.global().async { [weak self] in
-            guard let self = self else { return }
-
-            var tid: Data?
-
-            do {
-                tid = try manager.uploadFile(url: url, to: contact.id) { completed, send, arrived, total, error in
-                    guard let tid = tid else { return }
-
-                    if completed {
-                        self.endTransferWith(tid: tid)
-                    } else {
-                        if error != nil {
-                            self.failTransferWith(tid: tid)
-                        } else {
-                            self.progressTransferWith(tid: tid, arrived: Float(arrived), total: Float(total))
-                        }
-                    }
-                }
-
-                guard let tid = tid else { return }
-
-                let content = url.pathExtension == "m4a" ? "a voice message" : "an image"
-
-                let transfer = FileTransfer(
-                    id: tid,
-                    contactId: contact.id,
-                    name: url.deletingPathExtension().lastPathComponent,
-                    type: url.pathExtension,
-                    data: try? Data(contentsOf: url),
-                    progress: 0.0,
-                    isIncoming: false,
-                    createdAt: Date()
-                )
-
-                _ = try? self.dbManager.saveFileTransfer(transfer)
-
-                let message = Message(
-                    networkId: nil,
-                    senderId: self.client.bindings.myId,
-                    recipientId: contact.id,
-                    groupId: nil,
-                    date: Date(),
-                    status: .sending,
-                    isUnread: false,
-                    text: "You sent \(content)",
-                    replyMessageId: nil,
-                    roundURL: nil,
-                    fileTransferId: tid
-                )
-
-                _ = try? self.dbManager.saveMessage(message)
-            } catch {
-                print(error.localizedDescription)
-            }
-        }
-    }
-
-    public func send(_ payload: Payload, toContact contact: Contact) {
-        var message = Message(
-            networkId: nil,
-            senderId: client.bindings.myId,
-            recipientId: contact.id,
-            groupId: nil,
-            date: Date(),
-            status: .sending,
-            isUnread: false,
-            text: payload.text,
-            replyMessageId: payload.reply?.messageId,
-            roundURL: nil,
-            fileTransferId: nil
-        )
-
-        do {
-            message = try dbManager.saveMessage(message)
-            send(message: message)
-        } catch {
-            log(string: error.localizedDescription, type: .error)
-        }
-    }
-
-    public func retryMessage(_ id: Int64) {
-        if var message = try? dbManager.fetchMessages(.init(id: [id])).first {
-            message.status = .sending
-            message.date = Date()
-
-            if let message = try? dbManager.saveMessage(message) {
-                if let _ = message.recipientId {
-                    send(message: message)
-                } else {
-                    send(groupMessage: message)
-                }
-            }
-        }
-    }
-
-    func send(message: Message) {
-        var message = message
-
-        var reply: Reply?
-        if let replyId = message.replyMessageId,
-           let replyMessage = try? dbManager.fetchMessages(Message.Query(networkId: replyId)).first {
-            reply = Reply(messageId: replyId, senderId: replyMessage.senderId)
-        }
-
-        let payloadData = Payload(text: message.text, reply: reply).asData()
-
-        DispatchQueue.global().async { [weak self] in
-            guard let self = self else { return }
-            switch self.client.bindings.send(payloadData, to: message.recipientId!) {
-            case .success(let report):
-                message.roundURL = report.roundURL
-
-                self.client.bindings.listen(report: report.marshalled) { result in
-                    switch result {
-                    case .success(let status):
-                        switch status {
-                        case .failed:
-                            message.status = .sendingFailed
-                        case .sent:
-                            message.status = .sent
-                        case .timedout:
-                            message.status = .sendingTimedOut
-                        }
-                    case .failure:
-                        message.status = .sendingFailed
-                    }
-
-                    message.networkId = report.uniqueId
-                    message.date = Date.fromTimestamp(Int(report.timestamp))
-                    DispatchQueue.main.async {
-                        do {
-                            _ = try self.dbManager.saveMessage(message)
-                        } catch {
-                            log(string: error.localizedDescription, type: .error)
-                        }
-                    }
-                }
-            case .failure(let error):
-                message.status = .sendingFailed
-                log(string: error.localizedDescription, type: .error)
-            }
-
-            DispatchQueue.main.async {
-                do {
-                    _ = try self.dbManager.saveMessage(message)
-                } catch {
-                    log(string: error.localizedDescription, type: .error)
-                }
-            }
-        }
-    }
-
-    private func endTransferWith(tid: Data) {
-        guard let manager = client.transferManager else {
-            fatalError("A transfer manager was not created")
-        }
-
-        try? manager.endTransferUpload(with: tid)
-
-        if var message = try? dbManager.fetchMessages(.init(fileTransferId: tid)).first {
-            message.status = .sent
-            _ = try? dbManager.saveMessage(message)
-        }
-
-        if var transfer = try? dbManager.fetchFileTransfers(.init(id: [tid])).first {
-            transfer.progress = 1.0
-            _ = try? dbManager.saveFileTransfer(transfer)
-        }
-    }
-
-    private func failTransferWith(tid: Data) {
-        if var message = try? dbManager.fetchMessages(.init(fileTransferId: tid)).first {
-            message.status = .sendingFailed
-            _ = try? dbManager.saveMessage(message)
-        }
-    }
-
-    private func progressTransferWith(tid: Data, arrived: Float, total: Float) {
-        if var transfer = try? dbManager.fetchFileTransfers(.init(id: [tid])).first {
-            transfer.progress = arrived/total
-            _ = try? dbManager.saveFileTransfer(transfer)
-        }
-    }
-
-    func handle(incomingTransfer transfer: FileTransfer) {
-        guard let manager = client.transferManager else {
-            fatalError("A transfer manager was not created")
-        }
-
-        let content = transfer.type == "m4a" ? "a voice message" : "an image"
-
-        var message = try! dbManager.saveMessage(
-            Message(
-                networkId: nil,
-                senderId: transfer.contactId,
-                recipientId: myId,
-                groupId: nil,
-                date: transfer.createdAt,
-                status: .receiving,
-                isUnread: true,
-                text: "Sent you \(content)",
-                replyMessageId: nil,
-                roundURL: nil,
-                fileTransferId: transfer.id
-            )
-        )
-
-        try! manager.listenDownloadFromTransfer(with: transfer.id) { completed, arrived, total, error in
-            if let error = error {
-                print(error.localizedDescription)
-                return
-            }
-
-            if completed {
-                if let data = try? manager.downloadFileFromTransfer(with: transfer.id),
-                   let _ = try? FileManager.store(data: data, name: transfer.name, type: transfer.type) {
-                    var transfer = transfer
-                    transfer.data = data
-                    transfer.progress = 1.0
-                    message.status = .received
-
-                    _ = try? self.dbManager.saveFileTransfer(transfer)
-                    _ = try? self.dbManager.saveMessage(message)
-                }
-            } else {
-                self.progressTransferWith(tid: transfer.id, arrived: Float(arrived), total: Float(total))
-            }
-        }
-    }
-}
diff --git a/Sources/Integration/Session/Session+Network.swift b/Sources/Integration/Session/Session+Network.swift
deleted file mode 100644
index 070ea2cddeb608418f2d80ec400a8b7f0d63e24d..0000000000000000000000000000000000000000
--- a/Sources/Integration/Session/Session+Network.swift
+++ /dev/null
@@ -1,15 +0,0 @@
-import Foundation
-
-extension Session {
-    public func start() {
-        DispatchQueue.global().async { [weak client] in
-            client?.bindings.startNetwork()
-        }
-    }
-
-    public func stop() {
-        DispatchQueue.global().async { [weak client] in
-            client?.bindings.stopNetwork()
-        }
-    }
-}
diff --git a/Sources/Integration/Session/Session+Notifications.swift b/Sources/Integration/Session/Session+Notifications.swift
deleted file mode 100644
index b4e98e9647d8292051d8df61679d629740c84407..0000000000000000000000000000000000000000
--- a/Sources/Integration/Session/Session+Notifications.swift
+++ /dev/null
@@ -1,11 +0,0 @@
-import Foundation
-
-extension Session {
-    public func registerNotifications(_ token: Data) throws {
-        try client.bindings.registerNotifications(token)
-    }
-
-    public func unregisterNotifications() throws {
-        try client.bindings.unregisterNotifications()
-    }
-}
diff --git a/Sources/Integration/Session/Session+UD.swift b/Sources/Integration/Session/Session+UD.swift
deleted file mode 100644
index 27add4b13b1839482aefe29badc0f0fbe4e61e8f..0000000000000000000000000000000000000000
--- a/Sources/Integration/Session/Session+UD.swift
+++ /dev/null
@@ -1,118 +0,0 @@
-import Retry
-import Models
-import Combine
-import XXModels
-import Foundation
-
-extension Session {
-    public func waitForNodes(timeout: Int) -> AnyPublisher<Void, Error> {
-        Deferred {
-            Future { promise in
-                retry(max: timeout, retryStrategy: .delay(seconds: 1)) { [weak self] in
-                    guard let self = self else { return }
-                    try self.client.bindings.nodeRegistrationStatus()
-                    promise(.success(()))
-                }.finalCatch {
-                    promise(.failure($0))
-                }
-            }
-        }.eraseToAnyPublisher()
-    }
-
-    public func search(fact: String) -> AnyPublisher<Contact, Error> {
-        Deferred {
-            Future { promise in
-                guard let ud = self.client.userDiscovery else {
-                    let error = NSError(domain: "", code: 0)
-                    promise(.failure(error))
-                    return
-                }
-
-                do {
-                    try self.client.bindings.nodeRegistrationStatus()
-                    try ud.search(fact: fact) {
-                        switch $0 {
-                        case .success(let contact):
-                            promise(.success(contact))
-                        case .failure(let error):
-                            promise(.failure(error))
-                        }
-                    }
-                } catch {
-                    promise(.failure(error))
-                }
-            }
-        }.eraseToAnyPublisher()
-    }
-
-    public func search(fact: String, _ completion: @escaping (Result<Contact, Error>) -> Void) throws {
-        guard let ud = client.userDiscovery else { return }
-        try client.bindings.nodeRegistrationStatus()
-        try ud.search(fact: fact, completion)
-    }
-
-    public func extract(fact: FactType, from marshalled: Data) throws -> String? {
-        guard let ud = client.userDiscovery else { return nil }
-        return try ud.retrieve(from: marshalled, fact: fact)
-    }
-
-    public func unregister(fact: FactType) throws {
-        guard let ud = client.userDiscovery else { return }
-
-        switch fact {
-        case .phone:
-            try ud.remove("P" + phone!)
-            isSharingPhone = false
-            phone = nil
-        case .email:
-            try ud.remove("E" + email!)
-            isSharingEmail = false
-            email = nil
-        default:
-            break
-        }
-    }
-
-    public func register(_ fact: FactType, value: String, _ completion: @escaping (Result<String?, Error>) -> Void) {
-        guard let ud = client.userDiscovery else { return }
-
-        switch fact {
-        case .username:
-            ud.register(.username, value: value) { [weak self] in
-                guard let self = self else { return }
-
-                switch $0 {
-                case .success(_):
-                    self.username = value
-
-                    if var me = try? self.myContact() {
-                        me.username = value
-                        _ = try? self.dbManager.saveContact(me)
-                    }
-
-                    completion(.success(nil))
-                case .failure(let error):
-                    completion(.failure(error))
-                }
-            }
-        default:
-            ud.register(fact, value: value, completion)
-        }
-    }
-
-    public func confirm(code: String, confirmation: AttributeConfirmation) throws {
-        guard let ud = client.userDiscovery else { return }
-
-        try ud.confirm(code: code, id: confirmation.confirmationId!)
-
-        if confirmation.isEmail {
-            email = confirmation.content
-        } else {
-            phone = confirmation.content
-        }
-
-        if let _ = client.backupManager {
-            updateFactsOnBackup()
-        }
-    }
-}
diff --git a/Sources/Integration/Session/SessionType.swift b/Sources/Integration/Session/SessionType.swift
deleted file mode 100644
index effd6c96c3239904722b74f2856f2a953f0b986e..0000000000000000000000000000000000000000
--- a/Sources/Integration/Session/SessionType.swift
+++ /dev/null
@@ -1,73 +0,0 @@
-import Models
-import Combine
-import XXModels
-import Foundation
-
-public protocol SessionType {
-    var myId: Data { get }
-    var myQR: Data { get }
-    var version: String { get }
-    var hasRunningTasks: Bool { get }
-    var isOnline: AnyPublisher<Bool, Never> { get }
-
-    var dbManager: Database { get }
-
-    func deleteMyself() throws
-    func getId(from: Data) -> Data?
-
-    func sendFile(url: URL, to: Contact)
-    func send(imageData: Data, to: Contact, completion: @escaping (Result<Void, Error>) -> Void)
-
-    func verify(contact: Contact)
-
-    func setDummyTraffic(status: Bool)
-
-    // UserDiscovery
-
-    func unregister(fact: FactType) throws
-    func extract(fact: FactType, from: Data) throws -> String?
-    func confirm(code: String, confirmation: AttributeConfirmation) throws
-    func search(fact: String, _: @escaping (Result<Contact, Error>) -> Void) throws
-    func register(_: FactType, value: String, _: @escaping (Result<String?, Error>) -> Void)
-
-    // Notifications
-
-    func unregisterNotifications() throws
-    func registerNotifications(_ token: Data) throws
-
-    // Network
-
-    func start()
-    func stop()
-
-    // Messages
-
-    func retryMessage(_: Int64)
-    func send(_: Payload, toContact: Contact)
-
-    // Contacts
-
-    func add(_: Contact) throws
-    func confirm(_: Contact) throws
-    func deleteContact(_: Contact) throws
-
-    func retryRequest(_: Contact) throws
-    func scanStrangers(_: @escaping () -> Void)
-
-    // Groups
-
-    func join(group: Group) throws
-    func send(_: Payload, toGroup: Group)
-    func leave(group: Group) throws
-
-    func createGroup(
-        name: String,
-        welcome: String?,
-        members: [Contact],
-        _ completion: @escaping (Result<GroupInfo, Error>) -> Void
-    )
-
-    func search(fact: String) -> AnyPublisher<Contact, Error>
-
-    func waitForNodes(timeout: Int) -> AnyPublisher<Void, Error>
-}
diff --git a/Sources/Integration/XXNetwork.swift b/Sources/Integration/XXNetwork.swift
deleted file mode 100644
index 1273a26a68e4487227c96fe953ecabe23994e450..0000000000000000000000000000000000000000
--- a/Sources/Integration/XXNetwork.swift
+++ /dev/null
@@ -1,173 +0,0 @@
-import Shared
-import XXLogger
-import Keychain
-import Foundation
-import DependencyInjection
-
-public enum NetworkEnvironment {
-    case mainnet
-}
-
-public protocol XXNetworking {
-    var hasClient: Bool { get }
-
-    func writeLogs()
-    func purgeFiles()
-    func updateErrors()
-    func newClient(ndf: String) throws -> Client
-
-    func updateNDF(
-        _: @escaping (Result<String, Error>) -> Void
-    )
-
-    func loadClient(
-        with: Data,
-        fromBackup: Bool,
-        email: String?,
-        phone: String?
-    ) throws -> Client
-
-    func newClientFromBackup(
-        passphrase: String,
-        data: Data,
-        ndf: String
-    ) throws -> (Client, Data?)
-}
-
-public struct XXNetwork<B: BindingsInterface> {
-    @Dependency private var logger: XXLogger
-    @Dependency private var keychain: KeychainHandling
-
-    public init() {}
-}
-
-extension XXNetwork: XXNetworking {
-    public var hasClient: Bool {
-        guard let files = FileManager.xxContents else { return false }
-        return files.count > 0
-    }
-
-    public func writeLogs() {
-        B.listenLogs()
-    }
-
-    public func updateErrors() {
-        B.updateErrors()
-    }
-
-    public func updateNDF(_ completion: @escaping (Result<String, Error>) -> Void) {
-        B.updateNDF(for: .mainnet) {
-            switch $0 {
-            case .success(let data):
-                guard let ndfData = data, let ndf = String(data: ndfData, encoding: .utf8) else {
-                    completion(.failure(NSError.create("NDF is empty (?)")))
-                    return
-                }
-
-                completion(.success(ndf))
-            case .failure(let error):
-                completion(.failure(error))
-            }
-        }
-    }
-
-    public func purgeFiles() {
-        FileManager.xxCleanup()
-    }
-
-    public func newClientFromBackup(
-        passphrase: String,
-        data: Data,
-        ndf: String
-    ) throws -> (Client, Data?) {
-        var error: NSError?
-
-        let password = B.secret(32)!
-        try keychain.store(password: password)
-
-        let backupData = B.fromBackup(
-            ndf,
-            FileManager.xxPath,
-            password,
-            "\(passphrase)".data(using: .utf8),
-            data,
-            &error
-        )
-
-        if let error = error { throw error }
-
-        var email: String?
-        var phone: String?
-
-        let report = try! JSONDecoder().decode(BackupReport.self, from: backupData!)
-
-        if !report.parameters.isEmpty {
-            let params = try! JSONDecoder().decode(BackupParameters.self, from: Data(report.parameters.utf8))
-            phone = params.phone
-            email = params.email
-        }
-
-        let client = try loadClient(with: password, fromBackup: true, email: email, phone: phone)
-        return (client, backupData)
-    }
-
-    public func newClient(ndf: String) throws -> Client {
-        var password: Data!
-
-        if hasClient == false {
-            var error: NSError?
-
-            password = B.secret(32)
-            try keychain.store(password: password)
-
-            _ = B.new(ndf, FileManager.xxPath, password, nil, &error)
-            if let error = error { throw error }
-        } else {
-            guard let secret = try keychain.getPassword() else {
-                throw NSError.create("Empty stored secret")
-            }
-
-            password = secret
-        }
-
-        return try loadClient(with: password, fromBackup: false, email: nil, phone: nil)
-    }
-
-    public func loadClient(
-        with secret: Data,
-        fromBackup: Bool,
-        email: String?,
-        phone: String?
-    ) throws -> Client {
-        var error: NSError?
-        let bindings = B.login(FileManager.xxPath, secret, "", &error)
-        if let error = error { throw error }
-
-        if let defaults = UserDefaults(suiteName: "group.elixxir.messenger") {
-            defaults.set(bindings!.receptionId.base64EncodedString(), forKey: "receptionId")
-        }
-
-        return Client(bindings!, fromBackup: fromBackup, email: email, phone: phone)
-    }
-}
-
-extension NetworkEnvironment {
-    var url: String {
-        switch self {
-        case .mainnet:
-            return "https://elixxir-bins.s3.us-west-1.amazonaws.com/ndf/mainnet.json"
-        }
-    }
-
-    var cert: String {
-        switch self {
-        case .mainnet:
-            guard let filepath = Bundle.module.path(forResource: "cert_mainnet", ofType: "txt"),
-                  let certString = try? String(contentsOfFile: filepath) else {
-                      fatalError("Couldn't retrieve network cert file.")
-                  }
-
-            return certString
-        }
-    }
-}
diff --git a/Sources/LaunchFeature/LaunchController.swift b/Sources/LaunchFeature/LaunchController.swift
index cf8b093b2131d2becbb7d5e6bb55a3b02fb73c0e..a17c9fc3d0f07161d49018f0473bb0b8a70e699e 100644
--- a/Sources/LaunchFeature/LaunchController.swift
+++ b/Sources/LaunchFeature/LaunchController.swift
@@ -86,8 +86,8 @@ public final class LaunchController: UIViewController {
 
                     coordinator.toChats(from: self)
 
-                case .onboarding(let ndf):
-                    coordinator.toOnboarding(with: ndf, from: self)
+                case .onboarding:
+                    coordinator.toOnboarding(from: self)
 
                 case .update(let model):
                     offerUpdate(model: model)
diff --git a/Sources/LaunchFeature/LaunchCoordinator.swift b/Sources/LaunchFeature/LaunchCoordinator.swift
index 37035773d6cfd875d5acf6de309b4ac84d72ae6f..acdc52aa74bd3a428abe438d539888f82bbbe957 100644
--- a/Sources/LaunchFeature/LaunchCoordinator.swift
+++ b/Sources/LaunchFeature/LaunchCoordinator.swift
@@ -8,7 +8,7 @@ public protocol LaunchCoordinating {
     func toTerms(from: UIViewController)
     func toRequests(from: UIViewController)
     func toSearch(searching: String, from: UIViewController)
-    func toOnboarding(with: String, from: UIViewController)
+    func toOnboarding(from: UIViewController)
     func toSingleChat(with: Contact, from: UIViewController)
     func toGroupChat(with: GroupInfo, from: UIViewController)
 }
@@ -20,7 +20,7 @@ public struct LaunchCoordinator: LaunchCoordinating {
     var searchFactory: (String) -> UIViewController
     var requestsFactory: () -> UIViewController
     var chatListFactory: () -> UIViewController
-    var onboardingFactory: (String) -> UIViewController
+    var onboardingFactory: () -> UIViewController
     var singleChatFactory: (Contact) -> UIViewController
     var groupChatFactory: (GroupInfo) -> UIViewController
 
@@ -29,7 +29,7 @@ public struct LaunchCoordinator: LaunchCoordinating {
         searchFactory: @escaping (String) -> UIViewController,
         requestsFactory: @escaping () -> UIViewController,
         chatListFactory: @escaping () -> UIViewController,
-        onboardingFactory: @escaping (String) -> UIViewController,
+        onboardingFactory: @escaping () -> UIViewController,
         singleChatFactory: @escaping (Contact) -> UIViewController,
         groupChatFactory: @escaping (GroupInfo) -> UIViewController
     ) {
@@ -65,8 +65,8 @@ public extension LaunchCoordinator {
         replacePresenter.present(screen, from: parent)
     }
 
-    func toOnboarding(with ndf: String, from parent: UIViewController) {
-        let screen = onboardingFactory(ndf)
+    func toOnboarding(from parent: UIViewController) {
+        let screen = onboardingFactory()
         replacePresenter.present(screen, from: parent)
     }
 
diff --git a/Sources/LaunchFeature/LaunchViewModel.swift b/Sources/LaunchFeature/LaunchViewModel.swift
index 73fa6722f37c0fec119a11866046db37ddb0ae9e..ecfcbfb557d0c2b5a111229a88c5135e9d76849a 100644
--- a/Sources/LaunchFeature/LaunchViewModel.swift
+++ b/Sources/LaunchFeature/LaunchViewModel.swift
@@ -6,7 +6,6 @@ import Defaults
 import XXModels
 import Keychain
 import Foundation
-import Integration
 import Permissions
 import ToastFeature
 import DropboxFeature
@@ -15,6 +14,12 @@ import ReportingFeature
 import CombineSchedulers
 import DependencyInjection
 
+import XXClient
+import struct XXClient.FileTransfer
+
+import XXDatabase
+import XXLegacyDatabaseMigrator
+
 struct Update {
     let content: String
     let urlString: String
@@ -26,20 +31,22 @@ struct Update {
 enum LaunchRoute {
     case chats
     case update(Update)
-    case onboarding(String)
+    case onboarding
 }
 
 final class LaunchViewModel {
-    @Dependency private var network: XXNetworking
-    @Dependency private var versionChecker: VersionChecker
-    @Dependency private var dropboxService: DropboxInterface
-    @Dependency private var keychainHandler: KeychainHandling
-    @Dependency private var permissionHandler: PermissionHandling
-    @Dependency private var fetchBannedList: FetchBannedList
-    @Dependency private var reportingStatus: ReportingStatus
-    @Dependency private var processBannedList: ProcessBannedList
-    @Dependency private var toastController: ToastController
-    @Dependency private var session: SessionType
+    @Dependency var database: Database
+    @Dependency var cMixManager: CMixManager
+    @Dependency var versionChecker: VersionChecker
+    @Dependency var dropboxService: DropboxInterface
+    @Dependency var fetchBannedList: FetchBannedList
+    @Dependency var reportingStatus: ReportingStatus
+    @Dependency var toastController: ToastController
+    @Dependency var keychainHandler: KeychainHandling
+    @Dependency var getIdFromContact: GetIdFromContact
+    @Dependency var processBannedList: ProcessBannedList
+    @Dependency var permissionHandler: PermissionHandling
+    @Dependency var getFactsFromContact: GetFactsFromContact
 
     @KeyObject(.username, defaultValue: nil) var username: String?
     @KeyObject(.biometrics, defaultValue: false) var isBiometricsOn: Bool
@@ -86,56 +93,101 @@ final class LaunchViewModel {
     }
 
     func versionApproved() {
-        network.writeLogs()
-
-        network.updateNDF { [weak self] in
-            guard let self = self else { return }
+        //self.updateBannedList {
 
-            switch $0 {
-            case .success(let ndf):
-                self.network.updateErrors()
+        _ = try? SetLogLevel.live(.trace)
 
-                guard self.network.hasClient else {
-                    self.hudSubject.send(.none)
-                    self.routeSubject.send(.onboarding(ndf))
-                    self.dropboxService.unlink()
-                    try? self.keychainHandler.clear()
-                    return
-                }
-
-                guard self.username != nil else {
-                    self.network.purgeFiles()
-                    self.hudSubject.send(.none)
-                    self.routeSubject.send(.onboarding(ndf))
-                    self.dropboxService.unlink()
-                    try? self.keychainHandler.clear()
-                    return
-                }
+        try! setupDatabase()
 
-                self.backgroundScheduler.schedule { [weak self] in
-                    guard let self = self else { return }
+        if cMixManager.hasStorage(), username != nil {
+            checkBiometrics { [weak self] in
+                guard let self = self else { return }
 
+                switch $0 {
+                case .success(false):
+                    break
+                case .success(true):
                     do {
-                        let session = try Session(ndf: ndf)
-                        DependencyInjection.Container.shared.register(session as SessionType)
-
-                        self.updateBannedList {
-                            DispatchQueue.main.async {
-                                self.hudSubject.send(.none)
-                                self.checkBiometrics()
-                            }
+                        //UpdateCommonErrors.live(jsonFile: ) DOWNLOAD THE JSON FROM THE REPO
+
+                        let cMix = try self.initCMix()
+                        try cMix.startNetworkFollower(timeoutMS: 10_000)
+                        guard cMix.waitForNetwork(timeoutMS: 10_000) else {
+                            fatalError("^^^ cMix.waitForNetwork returned FALSE")
                         }
+
+                        let e2e = try self.initE2E(cMix)
+                        _ = try self.initUD(alternative: true, e2e: e2e, cMix: cMix)
+                        _ = try self.initGroupManager(e2e)
+                        _ = try self.initTransferManager(e2e)
+                        _ = try self.initDummyTrafficManager(e2e)
+
+
+                        self.hudSubject.send(.none)
+                        self.routeSubject.send(.chats)
                     } catch {
-                        DispatchQueue.main.async {
-                            self.hudSubject.send(.error(HUDError(with: error)))
-                        }
+                        self.hudSubject.send(.error(.init(with: error)))
                     }
+                case .failure(let error):
+                    self.hudSubject.send(.error(.init(with: error)))
                 }
-
             case .failure(let error):
                 self.hudSubject.send(.error(HUDError(with: error)))
             }
+        } else {
+            cleanUp()
+            presentOnboardingFlow()
+        }
+    }
+
+    private func cleanUp() {
+        try? cMixManager.remove()
+        try? keychainHandler.clear()
+
+        dropboxService.unlink()
+    }
+
+    private func presentOnboardingFlow() {
+        hudSubject.send(.none)
+        routeSubject.send(.onboarding)
+    }
+
+    private func setupDatabase() throws {
+        let legacyOldPath = NSSearchPathForDirectoriesInDomains(
+            .documentDirectory, .userDomainMask, true
+        )[0].appending("/xxmessenger.sqlite")
+
+        let legacyPath = FileManager.default
+            .containerURL(forSecurityApplicationGroupIdentifier: "group.elixxir.messenger")!
+            .appendingPathComponent("database")
+            .appendingPathExtension("sqlite").path
+
+        let dbExistsInLegacyOldPath = FileManager.default.fileExists(atPath: legacyOldPath)
+        let dbExistsInLegacyPath = FileManager.default.fileExists(atPath: legacyPath)
+
+        if dbExistsInLegacyOldPath && !dbExistsInLegacyPath {
+            try? FileManager.default.moveItem(atPath: legacyOldPath, toPath: legacyPath)
+        }
+
+        let dbPath = FileManager.default
+            .containerURL(forSecurityApplicationGroupIdentifier: "group.elixxir.messenger")!
+            .appendingPathComponent("xxm_database")
+            .appendingPathExtension("sqlite").path
+
+        let database = try Database.onDisk(path: dbPath)
+
+        if dbExistsInLegacyPath {
+            try Migrator.live()(
+                try .init(path: legacyPath),
+                to: database,
+                myContactId: Data(), //client.bindings.myId,
+                meMarshaled: Data() //client.bindings.meMarshalled
+            )
+
+            try FileManager.default.moveItem(atPath: legacyPath, toPath: legacyPath.appending("-backup"))
         }
+
+        DependencyInjection.Container.shared.register(database)
     }
 
     func getContactWith(userId: Data) -> Contact? {
@@ -145,12 +197,23 @@ final class LaunchViewModel {
             isBanned: reportingStatus.isEnabled() ? false : nil
         )
 
-        return try! session.dbManager.fetchContacts(query).first
+        guard let database: Database = try? DependencyInjection.Container.shared.resolve(),
+              let contact = try? database.fetchContacts(query).first else {
+            return nil
+        }
+
+        return contact
     }
 
     func getGroupInfoWith(groupId: Data) -> GroupInfo? {
         let query = GroupInfo.Query(groupId: groupId)
-        return try! session.dbManager.fetchGroupInfos(query).first
+
+        guard let database: Database = try? DependencyInjection.Container.shared.resolve(),
+              let info = try? database.fetchGroupInfos(query).first else {
+            return nil
+        }
+
+        return info
     }
 
     private func versionFailed(error: Error) {
@@ -189,25 +252,253 @@ final class LaunchViewModel {
         routeSubject.send(.update(model))
     }
 
-    private func checkBiometrics() {
+    private func checkBiometrics(completion: @escaping (Result<Bool, Error>) -> Void) {
         if permissionHandler.isBiometricsAvailable && isBiometricsOn {
-            permissionHandler.requestBiometrics { [weak self] in
-                guard let self = self else { return }
-
+            permissionHandler.requestBiometrics {
                 switch $0 {
                 case .success(let granted):
-                    guard granted else { return }
-                    self.routeSubject.send(.chats)
+                    completion(.success(granted))
 
                 case .failure(let error):
-                    self.hudSubject.send(.error(HUDError(with: error)))
+                    completion(.failure(error))
                 }
             }
         } else {
-            self.routeSubject.send(.chats)
+            completion(.success(true))
+        }
+    }
+
+    private func initCMix() throws -> CMix {
+        if let cMix = try? DependencyInjection.Container.shared.resolve() as CMix {
+            return cMix
+        }
+
+        let cMix = try cMixManager.load()
+        DependencyInjection.Container.shared.register(cMix)
+        return cMix
+    }
+
+    private func initE2E(_ cMix: CMix) throws -> E2E {
+        if let e2e = try? DependencyInjection.Container.shared.resolve() as E2E {
+            return e2e
+        }
+
+        let e2e = try Login.live(
+            cMixId: cMix.getId(),
+            authCallbacks: .init(
+                handle: {
+                    switch $0 {
+                    case .reset(contact: let contact, receptionId: _, ephemeralId: _, roundId: _):
+                        self.handleReset(from: contact)
+                    case .confirm(contact: let contact, receptionId: _, ephemeralId: _, roundId: _):
+                        self.handleConfirm(from: contact)
+                    case .request(contact: let contact, receptionId: _, ephemeralId: _, roundId: _):
+                        self.handleRequest(from: contact)
+                    }
+                }
+            ),
+            identity: cMix.makeLegacyReceptionIdentity()
+        )
+
+        try e2e.registerListener(
+            senderId: nil,
+            messageType: 2,
+            callback: .init(handle: { message in
+                print(message.timestamp)
+            })
+        )
+
+        DependencyInjection.Container.shared.register(e2e)
+        return e2e
+    }
+
+    private func initUD(alternative: Bool, e2e: E2E, cMix: CMix) throws -> UserDiscovery {
+        if let userDiscovery = try? DependencyInjection.Container.shared.resolve() as UserDiscovery {
+            return userDiscovery
+        }
+
+        guard let certPath = Bundle.module.path(forResource: "cmix.rip", ofType: "crt"),
+              let contactFilePath = Bundle.module.path(forResource: "udContact", ofType: "bin") else {
+            fatalError("Couldn't retrieve alternative UD credentials")
+        }
+
+        let address = alternative ? "46.101.98.49:18001" : e2e.getUdAddressFromNdf()
+        let cert = alternative ? try Data(contentsOf: URL(fileURLWithPath: certPath)) : e2e.getUdCertFromNdf()
+        let contactFile = alternative ? try Data(contentsOf: URL(fileURLWithPath: contactFilePath)) : try e2e.getUdContactFromNdf()
+
+        let userDiscovery = try NewOrLoadUd.live(.init(
+            e2eId: e2e.getId(),
+            follower: .init(handle: { cMix.networkFollowerStatus().rawValue }),
+            username: username!,
+            registrationValidationSignature: cMix.getReceptionRegistrationValidationSignature(),
+            cert: cert,
+            contactFile: contactFile,
+            address: address
+        ))
+
+        DependencyInjection.Container.shared.register(userDiscovery)
+        return userDiscovery
+    }
+
+    private func initGroupManager(_ e2e: E2E) throws -> GroupChat {
+        if let groupManager = try? DependencyInjection.Container.shared.resolve() as GroupChat {
+            return groupManager
+        }
+
+        let groupManager = try NewGroupChat.live(
+            e2eId: e2e.getId(),
+            groupRequest: .init(handle: { print($0) }),
+            groupChatProcessor: .init(handle: { print($0) })
+        )
+
+        DependencyInjection.Container.shared.register(groupManager)
+        return groupManager
+    }
+
+    private func initTransferManager(_ e2e: E2E) throws -> XXClient.FileTransfer {
+        if let transferManager = try? DependencyInjection.Container.shared.resolve() as FileTransfer {
+            return transferManager
+        }
+
+        let transferManager = try InitFileTransfer.live(
+            e2eId: e2e.getId(),
+            callback: .init(handle: {
+                switch $0 {
+                case .success(let receivedFile):
+                    print(receivedFile.name)
+                case .failure(let error):
+                    print(error.localizedDescription)
+                }
+            })
+        )
+
+        DependencyInjection.Container.shared.register(transferManager)
+        return transferManager
+    }
+
+    private func initDummyTrafficManager(_ e2e: E2E) throws -> DummyTraffic {
+        if let dummyTrafficManager = try? DependencyInjection.Container.shared.resolve() as DummyTraffic {
+            return dummyTrafficManager
+        }
+
+        let dummyTrafficManager = try NewDummyTrafficManager.live(
+            cMixId: e2e.getId(),
+            maxNumMessages: 1,
+            avgSendDeltaMS: 1,
+            randomRangeMS: 1
+        )
+
+        DependencyInjection.Container.shared.register(dummyTrafficManager)
+        return dummyTrafficManager
+    }
+
+    private func handleRequest(from contact: Data) {
+        guard isRepeatedRequest(from: contact) == false else { return }
+
+        do {
+            let facts = try? getFactsFromContact(contact: contact)
+
+            let model = try self.database.saveContact(.init(
+                id: try getIdFromContact(contact),
+                marshaled: contact,
+                username: facts?.first(where: { $0.type == FactType.username.rawValue })?.fact,
+                email: facts?.first(where: { $0.type == FactType.email.rawValue })?.fact,
+                phone: facts?.first(where: { $0.type == FactType.phone.rawValue })?.fact,
+                nickname: nil,
+                photo: nil,
+                authStatus: .verificationInProgress,
+                isRecent: true,
+                createdAt: Date()
+            ))
+
+            if model.email == nil, model.phone == nil {
+                performLookup(on: model)
+            } else {
+                //performSearch()
+            }
+        } catch {
+            print("^^^ Request processing failed: \(error.localizedDescription)")
         }
     }
 
+    private func isRepeatedRequest(from contact: Data) -> Bool {
+        if let id = try? getIdFromContact(contact),
+           let _ = try? self.database.fetchContacts(Contact.Query(id: [id])).first {
+            return true
+        }
+
+        return false
+    }
+
+    private func performLookup(on contact: Contact) {
+        guard let e2e = try? DependencyInjection.Container.shared.resolve() as E2E,
+              let userDiscovery = try? DependencyInjection.Container.shared.resolve() as UserDiscovery else {
+            print("^^^ couldn't resolve UD/E2E to process lookup")
+            return
+        }
+
+        do {
+            let _ = try LookupUD.live(
+                e2eId: e2e.getId(),
+                udContact: try userDiscovery.getContact(),
+                lookupId: contact.id,
+                callback: .init(handle: { [weak self] in
+                    guard let self = self else { return }
+
+                    switch $0 {
+                    case .success(let id):
+                        self.performOwnershipVerification(contact: contact, idLookedUp: id)
+                    case .failure(let error):
+                        print("^^^ Lookup failed: \(error.localizedDescription)")
+                    }
+                })
+            )
+        } catch {
+            print("^^^ Error when trying to run lookup: \(error.localizedDescription)")
+        }
+    }
+
+    private func performOwnershipVerification(contact: Contact, idLookedUp: Data) {
+        guard let e2e = try? DependencyInjection.Container.shared.resolve() as E2E else {
+            print("^^^ couldn't resolve E2E to process verification")
+            return
+        }
+
+        do {
+            let result = try e2e.verifyOwnership(
+                receivedContact: contact.marshaled!,
+                verifiedContact: idLookedUp,
+                e2eId: e2e.getId()
+            )
+
+            if result == true {
+                var contact = contact
+                contact.authStatus = .verified
+                try database.saveContact(contact)
+            } else {
+                try database.deleteContact(contact)
+            }
+        } catch {
+            print("^^^ Exception thrown at verify ownership")
+        }
+    }
+
+    private func handleConfirm(from contact: Data) {
+        guard let id = try? getIdFromContact(contact) else {
+            print("^^^ Couldn't get id from contact. Confirmation failed")
+            return
+        }
+
+        if var model = try? database.fetchContacts(.init(id: [id])).first {
+            model.authStatus = .friend
+            _ = try? database.saveContact(model)
+        }
+    }
+
+    private func handleReset(from contact: Data) {
+        // TODO
+    }
+
     private func updateBannedList(completion: @escaping () -> Void) {
         fetchBannedList { result in
             switch result {
diff --git a/Sources/LaunchFeature/Resources/cmix.rip.crt b/Sources/LaunchFeature/Resources/cmix.rip.crt
new file mode 100644
index 0000000000000000000000000000000000000000..baa29e6a035a4beb81f4b82ad980593e3640f869
--- /dev/null
+++ b/Sources/LaunchFeature/Resources/cmix.rip.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx
+GzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJp
+cDAeFw0xOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNV
+BAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDh
+Dwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfs
+WYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSE
+tJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uA
+m3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9
+bJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEA
+AaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEA
+neUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIf
+U/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2
+qvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4
+cyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1R
+tgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E5
+6m52PyzMNV+2N21IPppKwA==
+-----END CERTIFICATE-----
diff --git a/Sources/LaunchFeature/Resources/udContact.bin b/Sources/LaunchFeature/Resources/udContact.bin
new file mode 100644
index 0000000000000000000000000000000000000000..b2611d4124e7d083ad99cf37eba3810cc6d8926c
--- /dev/null
+++ b/Sources/LaunchFeature/Resources/udContact.bin
@@ -0,0 +1 @@
+<xxc(2)7mbKFLE201WzH4SGxAOpHjjehwztIV+KGifi5L/PYPcDkAZiB9kZo+Dl3Vc7dD2SdZCFMOJVgwqGzfYRDkjc8RGEllBqNxq2sRRX09iQVef0kJQUgJCHNCOcvm6Ki0JJwvjLceyFh36iwK8oLbhLgqEZY86UScdACTyBCzBIab3ob5mBthYc3mheV88yq5PGF2DQ+dEvueUm+QhOSfwzppAJA/rpW9Wq9xzYcQzaqc3ztAGYfm2BBAHS7HVmkCbvZ/K07Xrl4EBPGHJYq12tWAN/C3mcbbBYUOQXyEzbSl/mO7sL3ORr0B4FMuqCi8EdlD6RO52pVhY+Cg6roRH1t5Ng1JxPt8Mv1yyjbifPhZ5fLKwxBz8UiFORfk0/jnhwgm25LRHqtNRRUlYXLvhv0HhqyYTUt17WNtCLATSVbqLrFGdy2EGadn8mP+kQNHp93f27d/uHgBNNe7LpuYCJMdWpoG6bOqmHEftxt0/MIQA8fTtTm3jJzv+7/QjZJDvQIv0SNdp8HFogpuwde+GuS4BcY7v5xz+ArGWcRR63ct2z83MqQEn9ODr1/gAAAgA7szRpDDQIdFUQo9mkWg8xBA==xxc>
\ No newline at end of file
diff --git a/Sources/MenuFeature/ViewModels/MenuViewModel.swift b/Sources/MenuFeature/ViewModels/MenuViewModel.swift
index 72fbe071d7b81db1f192b41d1ee5480a7a03d226..ce8161fe4e1c248a0a841f8560751cba05be0213 100644
--- a/Sources/MenuFeature/ViewModels/MenuViewModel.swift
+++ b/Sources/MenuFeature/ViewModels/MenuViewModel.swift
@@ -1,14 +1,14 @@
 import Combine
 import XXModels
+import XXClient
 import Defaults
 import Foundation
-import Integration
 import ReportingFeature
 import DependencyInjection
 
 final class MenuViewModel {
-    @Dependency private var session: SessionType
-    @Dependency private var reportingStatus: ReportingStatus
+    @Dependency var database: Database
+    @Dependency var reportingStatus: ReportingStatus
 
     @KeyObject(.avatar, defaultValue: nil) var avatar: Data?
     @KeyObject(.username, defaultValue: "") var username: String
@@ -33,15 +33,15 @@ final class MenuViewModel {
         )
 
         return Publishers.CombineLatest(
-            session.dbManager.fetchContactsPublisher(contactsQuery).assertNoFailure(),
-            session.dbManager.fetchGroupsPublisher(groupQuery).assertNoFailure()
+            database.fetchContactsPublisher(contactsQuery).assertNoFailure(),
+            database.fetchGroupsPublisher(groupQuery).assertNoFailure()
         )
         .map { $0.0.count + $0.1.count }
         .eraseToAnyPublisher()
     }
 
     var xxdk: String {
-        session.version
+        GetVersion.live()
     }
 
     var build: String {
diff --git a/Sources/OnboardingFeature/Controllers/OnboardingStartController.swift b/Sources/OnboardingFeature/Controllers/OnboardingStartController.swift
index d9b970329040862abe2222493c0ecaf0ee2b34c4..3fce498d995b7bbabaf62517313b1705c9996b1b 100644
--- a/Sources/OnboardingFeature/Controllers/OnboardingStartController.swift
+++ b/Sources/OnboardingFeature/Controllers/OnboardingStartController.swift
@@ -11,20 +11,12 @@ public final class OnboardingStartController: UIViewController {
 
     lazy private var screenView = OnboardingStartView()
 
-    private let ndf: String
     private var cancellables = Set<AnyCancellable>()
 
     public override func loadView() {
         view = screenView
     }
 
-    public init(_ ndf: String) {
-        self.ndf = ndf
-        super.init(nibName: nil, bundle: nil)
-    }
-
-    required init?(coder: NSCoder) { nil }
-
     public override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
         navigationItem.backButtonTitle = ""
@@ -53,7 +45,7 @@ public final class OnboardingStartController: UIViewController {
         super.viewDidLoad()
 
         screenView.startButton.publisher(for: .touchUpInside)
-            .sink { [unowned self] in coordinator.toTerms(ndf: ndf, from: self) }
+            .sink { [unowned self] in coordinator.toTerms(from: self) }
             .store(in: &cancellables)
     }
 }
diff --git a/Sources/OnboardingFeature/Controllers/OnboardingUsernameController.swift b/Sources/OnboardingFeature/Controllers/OnboardingUsernameController.swift
index d42e1f81f055d800cb2fe86afb5ac0870c6ca39a..fd349efb4f4acfba8e6538e5892a1bf3025d5617 100644
--- a/Sources/OnboardingFeature/Controllers/OnboardingUsernameController.swift
+++ b/Sources/OnboardingFeature/Controllers/OnboardingUsernameController.swift
@@ -15,9 +15,8 @@ public final class OnboardingUsernameController: UIViewController {
     lazy private var screenView = OnboardingUsernameView()
     lazy private var scrollViewController = ScrollViewController()
 
-    private let ndf: String
     private var cancellables = Set<AnyCancellable>()
-    private let viewModel: OnboardingUsernameViewModel!
+    private let viewModel = OnboardingUsernameViewModel()
     private var drawerCancellables = Set<AnyCancellable>()
 
     public override func viewWillAppear(_ animated: Bool) {
@@ -27,14 +26,6 @@ public final class OnboardingUsernameController: UIViewController {
         navigationController?.navigationBar.customize(translucent: true)
     }
 
-    public init(_ ndf: String) {
-        self.ndf = ndf
-        self.viewModel = OnboardingUsernameViewModel(ndf: ndf)
-        super.init(nibName: nil, bundle: nil)
-    }
-
-    required init?(coder: NSCoder) { nil }
-
     public override func viewDidLoad() {
         super.viewDidLoad()
         setupScrollView()
@@ -74,7 +65,7 @@ public final class OnboardingUsernameController: UIViewController {
         screenView.restoreView.restoreButton
             .publisher(for: .touchUpInside)
             .receive(on: DispatchQueue.main)
-            .sink { [unowned self] in coordinator.toRestoreList(with: ndf, from: self) }
+            .sink { [unowned self] in coordinator.toRestoreList(from: self) }
             .store(in: &cancellables)
 
         screenView.inputField.returnPublisher
diff --git a/Sources/OnboardingFeature/Coordinator/OnboardingCoordinator.swift b/Sources/OnboardingFeature/Coordinator/OnboardingCoordinator.swift
index 9ea57da2c51a02679f40c9132b88498fb139fa68..dd26a3f6dc34173d156ff8724c6af949e5e3e86d 100644
--- a/Sources/OnboardingFeature/Coordinator/OnboardingCoordinator.swift
+++ b/Sources/OnboardingFeature/Coordinator/OnboardingCoordinator.swift
@@ -10,10 +10,10 @@ public protocol OnboardingCoordinating {
     func toChats(from: UIViewController)
     func toEmail(from: UIViewController)
     func toPhone(from: UIViewController)
+    func toTerms(from: UIViewController)
     func toWelcome(from: UIViewController)
-    func toTerms(ndf: String, from: UIViewController)
-    func toUsername(with: String, from: UIViewController)
-    func toRestoreList(with: String, from: UIViewController)
+    func toUsername(from: UIViewController)
+    func toRestoreList(from: UIViewController)
     func toDrawer(_: UIViewController, from: UIViewController)
     func toSuccess(with: OnboardingSuccessModel, from: UIViewController)
 
@@ -45,9 +45,9 @@ public struct OnboardingCoordinator: OnboardingCoordinating {
     var searchFactory: (String?) -> UIViewController
     var welcomeFactory: () -> UIViewController
     var chatListFactory: () -> UIViewController
-    var usernameFactory: (String) -> UIViewController
-    var restoreListFactory: (String) -> UIViewController
-    var termsFactory: (String?) -> UIViewController
+    var termsFactory: () -> UIViewController
+    var usernameFactory: () -> UIViewController
+    var restoreListFactory: () -> UIViewController
     var successFactory: (OnboardingSuccessModel) -> UIViewController
     var countriesFactory: (@escaping (Country) -> Void) -> UIViewController
     var phoneConfirmationFactory: (AttributeConfirmation, @escaping AttributeControllerClosure) -> UIViewController
@@ -59,9 +59,9 @@ public struct OnboardingCoordinator: OnboardingCoordinating {
         searchFactory: @escaping (String?) -> UIViewController,
         welcomeFactory: @escaping () -> UIViewController,
         chatListFactory: @escaping () -> UIViewController,
-        termsFactory: @escaping (String?) -> UIViewController,
-        usernameFactory: @escaping (String) -> UIViewController,
-        restoreListFactory: @escaping (String) -> UIViewController,
+        termsFactory: @escaping () -> UIViewController,
+        usernameFactory: @escaping () -> UIViewController,
+        restoreListFactory: @escaping () -> UIViewController,
         successFactory: @escaping (OnboardingSuccessModel) -> UIViewController,
         countriesFactory: @escaping (@escaping (Country) -> Void) -> UIViewController,
         phoneConfirmationFactory: @escaping (AttributeConfirmation, @escaping AttributeControllerClosure) -> UIViewController,
@@ -83,11 +83,8 @@ public struct OnboardingCoordinator: OnboardingCoordinating {
 }
 
 public extension OnboardingCoordinator {
-    func toTerms(
-        ndf: String,
-        from parent: UIViewController
-    ) {
-        let screen = termsFactory(ndf)
+    func toTerms(from parent: UIViewController) {
+        let screen = termsFactory()
         pushPresenter.present(screen, from: parent)
     }
 
@@ -106,8 +103,8 @@ public extension OnboardingCoordinator {
         replacePresenter.present(screen, from: parent)
     }
 
-    func toRestoreList(with ndf: String, from parent: UIViewController) {
-        let screen = restoreListFactory(ndf)
+    func toRestoreList(from parent: UIViewController) {
+        let screen = restoreListFactory()
         pushPresenter.present(screen, from: parent)
     }
 
@@ -116,8 +113,8 @@ public extension OnboardingCoordinator {
         replacePresenter.present(screen, from: parent)
     }
 
-    func toUsername(with ndf: String, from parent: UIViewController) {
-        let screen = usernameFactory(ndf)
+    func toUsername(from parent: UIViewController) {
+        let screen = usernameFactory()
         replacePresenter.present(screen, from: parent)
     }
 
diff --git a/Sources/OnboardingFeature/Resources/cmix.rip.crt b/Sources/OnboardingFeature/Resources/cmix.rip.crt
new file mode 100644
index 0000000000000000000000000000000000000000..baa29e6a035a4beb81f4b82ad980593e3640f869
--- /dev/null
+++ b/Sources/OnboardingFeature/Resources/cmix.rip.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx
+GzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJp
+cDAeFw0xOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNV
+BAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDh
+Dwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfs
+WYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSE
+tJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uA
+m3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9
+bJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEA
+AaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEA
+neUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIf
+U/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2
+qvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4
+cyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1R
+tgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E5
+6m52PyzMNV+2N21IPppKwA==
+-----END CERTIFICATE-----
diff --git a/Sources/OnboardingFeature/Resources/udContact.bin b/Sources/OnboardingFeature/Resources/udContact.bin
new file mode 100644
index 0000000000000000000000000000000000000000..b2611d4124e7d083ad99cf37eba3810cc6d8926c
--- /dev/null
+++ b/Sources/OnboardingFeature/Resources/udContact.bin
@@ -0,0 +1 @@
+<xxc(2)7mbKFLE201WzH4SGxAOpHjjehwztIV+KGifi5L/PYPcDkAZiB9kZo+Dl3Vc7dD2SdZCFMOJVgwqGzfYRDkjc8RGEllBqNxq2sRRX09iQVef0kJQUgJCHNCOcvm6Ki0JJwvjLceyFh36iwK8oLbhLgqEZY86UScdACTyBCzBIab3ob5mBthYc3mheV88yq5PGF2DQ+dEvueUm+QhOSfwzppAJA/rpW9Wq9xzYcQzaqc3ztAGYfm2BBAHS7HVmkCbvZ/K07Xrl4EBPGHJYq12tWAN/C3mcbbBYUOQXyEzbSl/mO7sL3ORr0B4FMuqCi8EdlD6RO52pVhY+Cg6roRH1t5Ng1JxPt8Mv1yyjbifPhZ5fLKwxBz8UiFORfk0/jnhwgm25LRHqtNRRUlYXLvhv0HhqyYTUt17WNtCLATSVbqLrFGdy2EGadn8mP+kQNHp93f27d/uHgBNNe7LpuYCJMdWpoG6bOqmHEftxt0/MIQA8fTtTm3jJzv+7/QjZJDvQIv0SNdp8HFogpuwde+GuS4BcY7v5xz+ArGWcRR63ct2z83MqQEn9ODr1/gAAAgA7szRpDDQIdFUQo9mkWg8xBA==xxc>
\ No newline at end of file
diff --git a/Sources/OnboardingFeature/ViewModels/OnboardingEmailConfirmationViewModel.swift b/Sources/OnboardingFeature/ViewModels/OnboardingEmailConfirmationViewModel.swift
index b3871d6234517f1d493ab61da1466bc754446fd7..b22252cbe844cfb0c1db48a4c3469d814fb09a9b 100644
--- a/Sources/OnboardingFeature/ViewModels/OnboardingEmailConfirmationViewModel.swift
+++ b/Sources/OnboardingFeature/ViewModels/OnboardingEmailConfirmationViewModel.swift
@@ -5,7 +5,7 @@ import Shared
 import Combine
 import Defaults
 import InputField
-import Integration
+import XXClient
 import CombineSchedulers
 import DependencyInjection
 
@@ -16,7 +16,9 @@ struct OnboardingEmailConfirmationViewState: Equatable {
 }
 
 final class OnboardingEmailConfirmationViewModel {
-    @Dependency private var session: SessionType
+    @Dependency var userDiscovery: UserDiscovery
+
+    @KeyObject(.email, defaultValue: nil) var email: String?
 
     var hud: AnyPublisher<HUDStatus, Never> { hudRelay.eraseToAnyPublisher() }
     private let hudRelay = CurrentValueSubject<HUDStatus, Never>(.none)
@@ -64,11 +66,13 @@ final class OnboardingEmailConfirmationViewModel {
             guard let self = self else { return }
 
             do {
-                try self.session.confirm(
-                    code: self.stateRelay.value.input,
-                    confirmation: self.confirmation
+                try self.userDiscovery.confirmFact(
+                    confirmationId: self.confirmation.confirmationId!,
+                    code: self.stateRelay.value.input
                 )
 
+                self.email = self.confirmation.content
+
                 self.timer?.invalidate()
                 self.hudRelay.send(.none)
                 self.completionRelay.send(self.confirmation)
diff --git a/Sources/OnboardingFeature/ViewModels/OnboardingEmailViewModel.swift b/Sources/OnboardingFeature/ViewModels/OnboardingEmailViewModel.swift
index c3cbbb897840964e15f908b9fa83d5d6537f7b23..85776bd9ef7f2631fe1fbb98396beec8b15852dd 100644
--- a/Sources/OnboardingFeature/ViewModels/OnboardingEmailViewModel.swift
+++ b/Sources/OnboardingFeature/ViewModels/OnboardingEmailViewModel.swift
@@ -5,7 +5,7 @@ import Shared
 import Combine
 import Defaults
 import InputField
-import Integration
+import XXClient
 import CombineSchedulers
 import DependencyInjection
 
@@ -16,9 +16,9 @@ struct OnboardingEmailViewState: Equatable {
 }
 
 final class OnboardingEmailViewModel {
-    @KeyObject(.pushNotifications, defaultValue: false) private var pushNotifications
+    @Dependency var userDiscovery: UserDiscovery
 
-    @Dependency private var session: SessionType
+    @KeyObject(.pushNotifications, defaultValue: false) private var pushNotifications
 
     var hud: AnyPublisher<HUDStatus, Never> { hudRelay.eraseToAnyPublisher() }
     private let hudRelay = CurrentValueSubject<HUDStatus, Never>(.none)
@@ -43,17 +43,19 @@ final class OnboardingEmailViewModel {
         backgroundScheduler.schedule { [weak self] in
             guard let self = self else { return }
 
-            self.session.register(.email, value: self.stateRelay.value.input) { [weak self] in
-                guard let self = self else { return }
+            do {
+                let confirmationId = try self.userDiscovery.sendRegisterFact(
+                    .init(fact: self.stateRelay.value.input, type: FactType.email.rawValue)
+                )
 
-                switch $0 {
-                case .success(let confirmationId):
-                    self.hudRelay.send(.none)
-                    self.stateRelay.value.confirmation =
-                        .init(content: self.stateRelay.value.input, isEmail: true, confirmationId: confirmationId)
-                case .failure(let error):
-                    self.hudRelay.send(.error(.init(with: error)))
-                }
+                self.hudRelay.send(.none)
+                self.stateRelay.value.confirmation = .init(
+                    content: self.stateRelay.value.input,
+                    isEmail: true,
+                    confirmationId: confirmationId
+                )
+            } catch {
+                self.hudRelay.send(.error(.init(with: error)))
             }
         }
     }
diff --git a/Sources/OnboardingFeature/ViewModels/OnboardingPhoneConfirmationViewModel.swift b/Sources/OnboardingFeature/ViewModels/OnboardingPhoneConfirmationViewModel.swift
index 2bd5a7ae35fbca7bf871479f998abeef9e4ce625..b05a6b21842b8e7f89824ae8127b0b8d582b49ac 100644
--- a/Sources/OnboardingFeature/ViewModels/OnboardingPhoneConfirmationViewModel.swift
+++ b/Sources/OnboardingFeature/ViewModels/OnboardingPhoneConfirmationViewModel.swift
@@ -5,7 +5,7 @@ import Shared
 import Combine
 import Defaults
 import InputField
-import Integration
+import XXClient
 import CombineSchedulers
 import DependencyInjection
 
@@ -16,7 +16,9 @@ struct OnboardingPhoneConfirmationViewState: Equatable {
 }
 
 final class OnboardingPhoneConfirmationViewModel {
-    @Dependency private var session: SessionType
+    @Dependency var userDiscovery: UserDiscovery
+
+    @KeyObject(.phone, defaultValue: nil) var phone: String?
 
     var hud: AnyPublisher<HUDStatus, Never> { hudRelay.eraseToAnyPublisher() }
     private let hudRelay = CurrentValueSubject<HUDStatus, Never>(.none)
@@ -64,11 +66,13 @@ final class OnboardingPhoneConfirmationViewModel {
             guard let self = self else { return }
 
             do {
-                try self.session.confirm(
-                    code: self.stateRelay.value.input,
-                    confirmation: self.confirmation
+                try self.userDiscovery.confirmFact(
+                    confirmationId: self.confirmation.confirmationId!,
+                    code: self.stateRelay.value.input
                 )
 
+                self.phone = self.confirmation.content
+
                 self.timer?.invalidate()
                 self.hudRelay.send(.none)
                 self.completionRelay.send(self.confirmation)
diff --git a/Sources/OnboardingFeature/ViewModels/OnboardingPhoneViewModel.swift b/Sources/OnboardingFeature/ViewModels/OnboardingPhoneViewModel.swift
index 0aff02f402420b959d03f166ba4eb456d1098bea..3469c45c079f3bb198e7586c4c8fe3d16ca3ecbb 100644
--- a/Sources/OnboardingFeature/ViewModels/OnboardingPhoneViewModel.swift
+++ b/Sources/OnboardingFeature/ViewModels/OnboardingPhoneViewModel.swift
@@ -4,7 +4,7 @@ import Models
 import Combine
 import Countries
 import InputField
-import Integration
+import XXClient
 import CombineSchedulers
 import DependencyInjection
 
@@ -16,7 +16,7 @@ struct OnboardingPhoneViewState: Equatable {
 }
 
 final class OnboardingPhoneViewModel {
-    @Dependency private var session: SessionType
+    @Dependency var userDiscovery: UserDiscovery
 
     var hud: AnyPublisher<HUDStatus, Never> { hudRelay.eraseToAnyPublisher() }
     private let hudRelay = CurrentValueSubject<HUDStatus, Never>(.none)
@@ -53,19 +53,19 @@ final class OnboardingPhoneViewModel {
             guard let self = self else { return }
 
             let content = "\(self.stateRelay.value.input)\(self.stateRelay.value.country.code)"
-            self.session.register(.phone, value: content) { [weak self] in
-                guard let self = self else { return }
-
-                switch $0 {
-                case .success(let confirmationId):
-                    self.hudRelay.send(.none)
-                    self.stateRelay.value.confirmation = .init(
-                        content: content,
-                        confirmationId: confirmationId
-                    )
-                case .failure(let error):
-                    self.hudRelay.send(.error(.init(with: error)))
-                }
+
+            do {
+                let confirmationId = try self.userDiscovery.sendRegisterFact(
+                    .init(fact: content, type: FactType.phone.rawValue)
+                )
+
+                self.hudRelay.send(.none)
+                self.stateRelay.value.confirmation = .init(
+                    content: content,
+                    confirmationId: confirmationId
+                )
+            } catch {
+                self.hudRelay.send(.error(.init(with: error)))
             }
         }
     }
diff --git a/Sources/OnboardingFeature/ViewModels/OnboardingUsernameViewModel.swift b/Sources/OnboardingFeature/ViewModels/OnboardingUsernameViewModel.swift
index ecb64035e73e259bf147ce4ee7f427723d40b3f3..8204662cd4be86e178846626993e95e120cbe2c0 100644
--- a/Sources/OnboardingFeature/ViewModels/OnboardingUsernameViewModel.swift
+++ b/Sources/OnboardingFeature/ViewModels/OnboardingUsernameViewModel.swift
@@ -1,21 +1,31 @@
 import HUD
 import Shared
+import Models
 import Combine
+import Defaults
+import XXModels
 import InputField
-import Integration
+import XXClient
 import CombineSchedulers
 import DependencyInjection
 
+import struct XXClient.FileTransfer
+
 struct OnboardingUsernameViewState: Equatable {
     var input: String = ""
     var status: InputField.ValidationStatus = .unknown(nil)
 }
 
 final class OnboardingUsernameViewModel {
+    @Dependency var database: Database
+    @Dependency var cMixManager: CMixManager
+    @Dependency var getIdFromContact: GetIdFromContact
+    @Dependency var getFactsFromContact: GetFactsFromContact
 
-    let ndf: String
+    @KeyObject(.username, defaultValue: "") var username: String
 
-    var backgroundScheduler: AnySchedulerOf<DispatchQueue> = DispatchQueue.global().eraseToAnyScheduler()
+    var backgroundScheduler: AnySchedulerOf<DispatchQueue>
+    = DispatchQueue.global().eraseToAnyScheduler()
 
     var greenPublisher: AnyPublisher<Void, Never> { greenRelay.eraseToAnyPublisher() }
     private let greenRelay = PassthroughSubject<Void, Never>()
@@ -26,10 +36,6 @@ final class OnboardingUsernameViewModel {
     var state: AnyPublisher<OnboardingUsernameViewState, Never> { stateRelay.eraseToAnyPublisher() }
     private let stateRelay = CurrentValueSubject<OnboardingUsernameViewState, Never>(.init())
 
-    init(ndf: String) {
-        self.ndf = ndf
-    }
-
     func didInput(_ string: String) {
         stateRelay.value.input = string.trimmingCharacters(in: .whitespacesAndNewlines)
 
@@ -48,31 +54,255 @@ final class OnboardingUsernameViewModel {
             guard let self = self else { return }
 
             do {
-                var session: SessionType!
+                let cMix = try self.initCMix()
+                try cMix.startNetworkFollower(timeoutMS: 10_000)
+                guard cMix.waitForNetwork(timeoutMS: 10_000) else {
+                    fatalError("^^^ cMix.waitForNetwork returned FALSE")
+                }
+                let e2e = try self.initE2E(cMix)
+                let ud = try self.initUD(alternative: true, e2e: e2e, cMix: cMix)
+                _ = try self.initGroupManager(e2e)
+                _ = try self.initTransferManager(e2e)
+                _ = try self.initDummyTrafficManager(e2e)
+
+                self.hudRelay.send(.none)
+                self.greenRelay.send()
+            } catch {
+                self.hudRelay.send(.none)
+                self.stateRelay.value.status = .invalid(error.localizedDescription)
+            }
+        }
+    }
+
+    private func initCMix() throws -> CMix {
+        if let cMix = try? DependencyInjection.Container.shared.resolve() as CMix {
+            return cMix
+        }
+
+        let cMix = try cMixManager.create()
+        DependencyInjection.Container.shared.register(cMix)
+        return cMix
+    }
+
+    private func initE2E(_ cMix: CMix) throws -> E2E {
+        if let e2e = try? DependencyInjection.Container.shared.resolve() as E2E {
+            return e2e
+        }
 
-                if let injectedSession = try? DependencyInjection.Container.shared.resolve() as SessionType {
-                    session = injectedSession
-                } else {
-                    session = try Session(ndf: self.ndf)
-                    DependencyInjection.Container.shared.register(session as SessionType)
+        let e2e = try Login.live(
+            cMixId: cMix.getId(),
+            authCallbacks: .init(
+                handle: {
+                    switch $0 {
+                    case .reset(contact: let contact, receptionId: _, ephemeralId: _, roundId: _):
+                        self.handleReset(from: contact)
+                    case .confirm(contact: let contact, receptionId: _, ephemeralId: _, roundId: _):
+                        self.handleConfirm(from: contact)
+                    case .request(contact: let contact, receptionId: _, ephemeralId: _, roundId: _):
+                        self.handleRequest(from: contact)
+                    }
                 }
+            ),
+            identity: cMix.makeLegacyReceptionIdentity()
+        )
 
-                session.register(.username, value: self.stateRelay.value.input) { [weak self] in
+        try e2e.registerListener(
+            senderId: nil,
+            messageType: 2,
+            callback: .init(handle: { message in
+                print(message.timestamp)
+            })
+        )
+
+        DependencyInjection.Container.shared.register(e2e)
+        return e2e
+    }
+
+    private func initUD(alternative: Bool, e2e: E2E, cMix: CMix) throws -> UserDiscovery {
+        if let userDiscovery = try? DependencyInjection.Container.shared.resolve() as UserDiscovery {
+            return userDiscovery
+        }
+
+        guard let certPath = Bundle.module.path(forResource: "cmix.rip", ofType: "crt"),
+              let contactFilePath = Bundle.module.path(forResource: "udContact", ofType: "bin") else {
+            fatalError("Couldn't retrieve alternative UD credentials")
+        }
+
+        let address = alternative ? "46.101.98.49:18001" : e2e.getUdAddressFromNdf()
+        let cert = alternative ? try Data(contentsOf: URL(fileURLWithPath: certPath)) : e2e.getUdCertFromNdf()
+        let contactFile = alternative ? try Data(contentsOf: URL(fileURLWithPath: contactFilePath)) : try e2e.getUdContactFromNdf()
+
+        let userDiscovery = try NewOrLoadUd.live(.init(
+            e2eId: e2e.getId(),
+            follower: .init(handle: { cMix.networkFollowerStatus().rawValue }),
+            username: self.stateRelay.value.input,
+            registrationValidationSignature: cMix.getReceptionRegistrationValidationSignature(),
+            cert: cert,
+            contactFile: contactFile,
+            address: address
+        ))
+
+        username = self.stateRelay.value.input
+        DependencyInjection.Container.shared.register(userDiscovery)
+        return userDiscovery
+    }
+
+    private func initGroupManager(_ e2e: E2E) throws -> GroupChat {
+        if let groupManager = try? DependencyInjection.Container.shared.resolve() as GroupChat {
+            return groupManager
+        }
+
+        let groupManager = try NewGroupChat.live(
+            e2eId: e2e.getId(),
+            groupRequest: .init(handle: { print($0) }),
+            groupChatProcessor: .init(handle: { print($0) })
+        )
+
+        DependencyInjection.Container.shared.register(groupManager)
+        return groupManager
+    }
+
+    private func initTransferManager(_ e2e: E2E) throws -> XXClient.FileTransfer {
+        if let transferManager = try? DependencyInjection.Container.shared.resolve() as FileTransfer {
+            return transferManager
+        }
+
+        let transferManager = try InitFileTransfer.live(
+            e2eId: e2e.getId(),
+            callback: .init(handle: {
+                switch $0 {
+                case .success(let receivedFile):
+                    print(receivedFile.name)
+                case .failure(let error):
+                    print(error.localizedDescription)
+                }
+            })
+        )
+
+        DependencyInjection.Container.shared.register(transferManager)
+        return transferManager
+    }
+
+    private func initDummyTrafficManager(_ e2e: E2E) throws -> DummyTraffic {
+        if let dummyTrafficManager = try? DependencyInjection.Container.shared.resolve() as DummyTraffic {
+            return dummyTrafficManager
+        }
+
+        let dummyTrafficManager = try NewDummyTrafficManager.live(
+            cMixId: e2e.getId(),
+            maxNumMessages: 1,
+            avgSendDeltaMS: 1,
+            randomRangeMS: 1
+        )
+
+        DependencyInjection.Container.shared.register(dummyTrafficManager)
+        return dummyTrafficManager
+    }
+
+    private func handleRequest(from contact: Data) {
+        guard isRepeatedRequest(from: contact) == false else { return }
+
+        do {
+            let facts = try? getFactsFromContact(contact: contact)
+
+            let model = try self.database.saveContact(.init(
+                id: try getIdFromContact(contact),
+                marshaled: contact,
+                username: facts?.first(where: { $0.type == FactType.username.rawValue })?.fact,
+                email: facts?.first(where: { $0.type == FactType.email.rawValue })?.fact,
+                phone: facts?.first(where: { $0.type == FactType.phone.rawValue })?.fact,
+                nickname: nil,
+                photo: nil,
+                authStatus: .verificationInProgress,
+                isRecent: true,
+                createdAt: Date()
+            ))
+
+            if model.email == nil, model.phone == nil {
+                performLookup(on: model)
+            } else {
+                //performSearch()
+            }
+        } catch {
+            print("^^^ Request processing failed: \(error.localizedDescription)")
+        }
+    }
+
+    private func isRepeatedRequest(from contact: Data) -> Bool {
+        if let id = try? getIdFromContact(contact),
+           let _ = try? self.database.fetchContacts(Contact.Query(id: [id])).first {
+            return true
+        }
+
+        return false
+    }
+
+    private func performLookup(on contact: Contact) {
+        guard let e2e = try? DependencyInjection.Container.shared.resolve() as E2E,
+              let userDiscovery = try? DependencyInjection.Container.shared.resolve() as UserDiscovery else {
+            print("^^^ couldn't resolve UD/E2E to process lookup")
+            return
+        }
+
+        do {
+            let _ = try LookupUD.live(
+                e2eId: e2e.getId(),
+                udContact: try userDiscovery.getContact(),
+                lookupId: contact.id,
+                callback: .init(handle: { [weak self] in
                     guard let self = self else { return }
 
                     switch $0 {
-                    case .success(_):
-                        self.hudRelay.send(.none)
-                        self.greenRelay.send()
+                    case .success(let id):
+                        self.performOwnershipVerification(contact: contact, idLookedUp: id)
                     case .failure(let error):
-                        self.hudRelay.send(.none)
-                        self.stateRelay.value.status = .invalid(error.localizedDescription)
+                        print("^^^ Lookup failed: \(error.localizedDescription)")
                     }
-                }
-            } catch {
-                self.hudRelay.send(.none)
-                self.stateRelay.value.status = .invalid(error.localizedDescription)
+                })
+            )
+        } catch {
+            print("^^^ Error when trying to run lookup: \(error.localizedDescription)")
+        }
+    }
+
+    private func performOwnershipVerification(contact: Contact, idLookedUp: Data) {
+        guard let e2e = try? DependencyInjection.Container.shared.resolve() as E2E else {
+            print("^^^ couldn't resolve E2E to process verification")
+            return
+        }
+
+        do {
+            let result = try e2e.verifyOwnership(
+                receivedContact: contact.marshaled!,
+                verifiedContact: idLookedUp,
+                e2eId: e2e.getId()
+            )
+
+            if result == true {
+                var contact = contact
+                contact.authStatus = .verified
+                try database.saveContact(contact)
+            } else {
+                try database.deleteContact(contact)
             }
+        } catch {
+            print("^^^ Exception thrown at verify ownership")
+        }
+    }
+
+    private func handleConfirm(from contact: Data) {
+        guard let id = try? getIdFromContact(contact) else {
+            print("^^^ Couldn't get id from contact. Confirmation failed")
+            return
         }
+
+        if var model = try? database.fetchContacts(.init(id: [id])).first {
+            model.authStatus = .friend
+            _ = try? database.saveContact(model)
+        }
+    }
+
+    private func handleReset(from contact: Data) {
+        // TODO
     }
 }
diff --git a/Sources/ProfileFeature/ViewModels/ProfileCodeViewModel.swift b/Sources/ProfileFeature/ViewModels/ProfileCodeViewModel.swift
index d9763e989e23e37c9736582a41fcf1b63aef03b2..49be007760d32cba219bb97aaa66cb728b6d424b 100644
--- a/Sources/ProfileFeature/ViewModels/ProfileCodeViewModel.swift
+++ b/Sources/ProfileFeature/ViewModels/ProfileCodeViewModel.swift
@@ -2,8 +2,9 @@ import HUD
 import Shared
 import Models
 import Combine
+import Defaults
 import InputField
-import Integration
+import XXClient
 import CombineSchedulers
 import DependencyInjection
 
@@ -14,7 +15,10 @@ struct ProfileCodeViewState: Equatable {
 }
 
 final class ProfileCodeViewModel {
-    @Dependency private var session: SessionType
+    @Dependency var userDiscovery: UserDiscovery
+
+    @KeyObject(.email, defaultValue: nil) var email: String?
+    @KeyObject(.phone, defaultValue: nil) var phone: String?
 
     let confirmation: AttributeConfirmation
 
@@ -63,11 +67,17 @@ final class ProfileCodeViewModel {
             guard let self = self else { return }
 
             do {
-                try self.session.confirm(
-                    code: self.stateRelay.value.input,
-                    confirmation: self.confirmation
+                try self.userDiscovery.confirmFact(
+                    confirmationId: self.confirmation.confirmationId!,
+                    code: self.stateRelay.value.input
                 )
 
+                if self.confirmation.isEmail {
+                    self.email = self.confirmation.content
+                } else {
+                    self.phone = self.confirmation.content
+                }
+
                 self.timer?.invalidate()
                 self.hudRelay.send(.none)
                 self.completionRelay.send(self.confirmation)
diff --git a/Sources/ProfileFeature/ViewModels/ProfileEmailViewModel.swift b/Sources/ProfileFeature/ViewModels/ProfileEmailViewModel.swift
index 6b57bc81fe4040faaccaeefff057a275a90deaac..21ec9fa87d5fd30cf53849c0a42611764c87eaa6 100644
--- a/Sources/ProfileFeature/ViewModels/ProfileEmailViewModel.swift
+++ b/Sources/ProfileFeature/ViewModels/ProfileEmailViewModel.swift
@@ -3,7 +3,7 @@ import Models
 import Shared
 import Combine
 import InputField
-import Integration
+import XXClient
 import CombineSchedulers
 import DependencyInjection
 
@@ -16,7 +16,7 @@ struct ProfileEmailViewState: Equatable {
 final class ProfileEmailViewModel {
     // MARK: Injected
 
-    @Dependency private var session: SessionType
+    @Dependency var userDiscovery: UserDiscovery
 
     // MARK: Properties
 
@@ -45,20 +45,19 @@ final class ProfileEmailViewModel {
         backgroundScheduler.schedule { [weak self] in
             guard let self = self else { return }
 
-            self.session.register(.email, value: self.stateRelay.value.input) { [weak self] in
-                guard let self = self else { return }
-
-                switch $0 {
-                case .success(let confirmationId):
-                    self.hudRelay.send(.none)
-                    self.stateRelay.value.confirmation = .init(
-                        content: self.stateRelay.value.input,
-                        isEmail: true,
-                        confirmationId: confirmationId
-                    )
-                case .failure(let error):
-                    self.hudRelay.send(.error(.init(with: error)))
-                }
+            do {
+                let confirmationId = try self.userDiscovery.sendRegisterFact(
+                    .init(fact: self.stateRelay.value.input, type: FactType.email.rawValue)
+                )
+
+                self.hudRelay.send(.none)
+                self.stateRelay.value.confirmation = .init(
+                    content: self.stateRelay.value.input,
+                    isEmail: true,
+                    confirmationId: confirmationId
+                )
+            } catch {
+                self.hudRelay.send(.error(.init(with: error)))
             }
         }
     }
diff --git a/Sources/ProfileFeature/ViewModels/ProfilePhoneViewModel.swift b/Sources/ProfileFeature/ViewModels/ProfilePhoneViewModel.swift
index 1013725b419a118c4e437d3e8959c50748447d72..37db504ebe7c48c6169a091d408f2446096eb0a9 100644
--- a/Sources/ProfileFeature/ViewModels/ProfilePhoneViewModel.swift
+++ b/Sources/ProfileFeature/ViewModels/ProfilePhoneViewModel.swift
@@ -4,7 +4,7 @@ import Models
 import Combine
 import Countries
 import InputField
-import Integration
+import XXClient
 import CombineSchedulers
 import DependencyInjection
 
@@ -18,7 +18,7 @@ struct ProfilePhoneViewState: Equatable {
 final class ProfilePhoneViewModel {
     // MARK: Injected
 
-    @Dependency private var session: SessionType
+    @Dependency var userDiscovery: UserDiscovery
 
     // MARK: Properties
 
@@ -54,19 +54,19 @@ final class ProfilePhoneViewModel {
 
             let content = "\(self.stateRelay.value.input)\(self.stateRelay.value.country.code)"
 
-            self.session.register(.phone, value: content) { [weak self] in
-                guard let self = self else { return }
-
-                switch $0 {
-                case .success(let confirmationId):
-                    self.hudRelay.send(.none)
-                    self.stateRelay.value.confirmation = .init(
-                        content: content,
-                        confirmationId: confirmationId
-                    )
-                case .failure(let error):
-                    self.hudRelay.send(.error(.init(with: error)))
-                }
+            do {
+                let confirmationId = try self.userDiscovery.sendRegisterFact(
+                    .init(fact: content, type: FactType.phone.rawValue)
+                )
+
+                self.hudRelay.send(.none)
+                self.stateRelay.value.confirmation = .init(
+                    content: content,
+                    confirmationId: confirmationId
+                )
+
+            } catch {
+                self.hudRelay.send(.error(.init(with: error)))
             }
         }
     }
diff --git a/Sources/ProfileFeature/ViewModels/ProfileViewModel.swift b/Sources/ProfileFeature/ViewModels/ProfileViewModel.swift
index a7066eccfaada6e74960beb7a5b3b8b7e72548cb..d6bc8bb352c6035e417c93b63c05c107a53401f3 100644
--- a/Sources/ProfileFeature/ViewModels/ProfileViewModel.swift
+++ b/Sources/ProfileFeature/ViewModels/ProfileViewModel.swift
@@ -1,12 +1,13 @@
 import HUD
 import UIKit
 import Shared
+import Models
 import Combine
 import Defaults
 import Countries
 import Foundation
 import Permissions
-import Integration
+import XXClient
 import CombineSchedulers
 import DependencyInjection
 
@@ -30,7 +31,7 @@ final class ProfileViewModel {
     @KeyObject(.sharingEmail, defaultValue: false) var isEmailSharing: Bool
     @KeyObject(.sharingPhone, defaultValue: false) var isPhoneSharing: Bool
 
-    @Dependency private var session: SessionType
+    @Dependency var userDiscovery: UserDiscovery
     @Dependency private var permissions: PermissionHandling
 
     var name: String { username! }
@@ -89,7 +90,20 @@ final class ProfileViewModel {
             guard let self = self else { return }
 
             do {
-                try self.session.unregister(fact: isEmail ? .email : .phone)
+                try self.userDiscovery.removeFact(
+                    .init(
+                        fact: isEmail ? "E\(self.emailStored!)" : "P\(self.phoneStored!)",
+                        type: isEmail ? FactType.email.rawValue : FactType.phone.rawValue
+                    )
+                )
+
+                if isEmail {
+                    self.emailStored = nil
+                    self.isEmailSharing = false
+                } else {
+                    self.phoneStored = nil
+                    self.isPhoneSharing = false
+                }
 
                 self.hudRelay.send(.none)
                 self.refresh()
diff --git a/Sources/PushFeature/PushExtractor.swift b/Sources/PushFeature/PushExtractor.swift
index 045f0e898276350914d9c0d335a58997d4fbdfa1..6141650b414965931487d56a51f285000857e474 100644
--- a/Sources/PushFeature/PushExtractor.swift
+++ b/Sources/PushFeature/PushExtractor.swift
@@ -1,5 +1,4 @@
 import Foundation
-import Integration
 
 public struct PushExtractor {
     enum Constants {
@@ -13,26 +12,27 @@ public struct PushExtractor {
 
 public extension PushExtractor {
     static let live = PushExtractor { dictionary in
-        var error: NSError?
-
-        guard let data = dictionary[Constants.notificationData] as? String,
-              let defaults = UserDefaults(suiteName: Constants.appGroup),
-              let preImage = defaults.value(forKey: Constants.preImage) as? String,
-              let reports = evaluateNotification(data, preImage, &error) else {
-            return .success(nil)
-        }
-
-        if let error = error {
-            return .failure(error)
-        }
-
-        let pushes = (0..<reports.len())
-            .compactMap { try? reports.get(index: $0) }
-            .filter { $0.forMe() }
-            .filter { $0.type() != PushType.silent.rawValue }
-            .filter { $0.type() != PushType.default.rawValue }
-            .compactMap { Push(type: $0.type(), source: $0.source()) }
-
-        return .success(pushes)
+        fatalError(">>> Missing API for notifications")
+//        var error: NSError?
+//
+//        guard let data = dictionary[Constants.notificationData] as? String,
+//              let defaults = UserDefaults(suiteName: Constants.appGroup),
+//              let preImage = defaults.value(forKey: Constants.preImage) as? String,
+//              let reports = evaluateNotification(data, preImage, &error) else {
+//            return .success(nil)
+//        }
+//
+//        if let error = error {
+//            return .failure(error)
+//        }
+//
+//        let pushes = (0..<reports.len())
+//            .compactMap { try? reports.get(index: $0) }
+//            .filter { $0.forMe() }
+//            .filter { $0.type() != PushType.silent.rawValue }
+//            .filter { $0.type() != PushType.default.rawValue }
+//            .compactMap { Push(type: $0.type(), source: $0.source()) }
+//
+//        return .success(pushes)
     }
 }
diff --git a/Sources/PushFeature/PushHandler.swift b/Sources/PushFeature/PushHandler.swift
index b090664f1f7bb55086cc4909afd8bf2639cf7e59..acee5de05830efd6a348a982523fbee405bba27f 100644
--- a/Sources/PushFeature/PushHandler.swift
+++ b/Sources/PushFeature/PushHandler.swift
@@ -2,7 +2,7 @@ import UIKit
 import Models
 import Defaults
 import XXModels
-import Integration
+import XXDatabase
 import ReportingFeature
 import DependencyInjection
 
@@ -38,8 +38,7 @@ public final class PushHandler: PushHandling {
 
     public func registerToken(_ token: Data) {
         do {
-            let session = try DependencyInjection.Container.shared.resolve() as SessionType
-            try session.registerNotifications(token)
+            fatalError(">>> Missing API for notifications")
         } catch {
             isPushEnabled = false
         }
diff --git a/Sources/RequestsFeature/ViewModels/RequestsFailedViewModel.swift b/Sources/RequestsFeature/ViewModels/RequestsFailedViewModel.swift
index b7d81db3a65b791e001a897506418295b56f8b3a..6b3cf746e22da6571ed12a3732ddbbe7f9062e0a 100644
--- a/Sources/RequestsFeature/ViewModels/RequestsFailedViewModel.swift
+++ b/Sources/RequestsFeature/ViewModels/RequestsFailedViewModel.swift
@@ -2,12 +2,18 @@ import HUD
 import UIKit
 import Models
 import Combine
-import Integration
+import XXModels
+import Defaults
+import XXClient
 import CombineSchedulers
 import DependencyInjection
 
 final class RequestsFailedViewModel {
-    @Dependency private var session: SessionType
+    @Dependency var e2e: E2E
+    @Dependency var database: Database
+    @Dependency var userDiscovery: UserDiscovery
+
+    @KeyObject(.username, defaultValue: nil) var username: String?
 
     var hudPublisher: AnyPublisher<HUDStatus, Never> {
         hudSubject.eraseToAnyPublisher()
@@ -24,7 +30,7 @@ final class RequestsFailedViewModel {
     var backgroundScheduler: AnySchedulerOf<DispatchQueue> = DispatchQueue.global().eraseToAnyScheduler()
 
     init() {
-        session.dbManager.fetchContactsPublisher(.init(authStatus: [.requestFailed]))
+        database.fetchContactsPublisher(.init(authStatus: [.requestFailed]))
             .assertNoFailure()
             .map { data -> NSDiffableDataSourceSnapshot<Section, Request> in
                 var snapshot = NSDiffableDataSourceSnapshot<Section, Request>()
@@ -43,7 +49,14 @@ final class RequestsFailedViewModel {
             guard let self = self else { return }
 
             do {
-                try self.session.retryRequest(contact)
+                var myFacts = try self.userDiscovery.getFacts()
+                myFacts.append(Fact(fact: self.username!, type: FactType.username.rawValue))
+
+                let _ = try self.e2e.requestAuthenticatedChannel(
+                    partnerContact: contact.id,
+                    myFacts: myFacts
+                )
+
                 self.hudSubject.send(.none)
             } catch {
                 self.hudSubject.send(.error(.init(with: error)))
diff --git a/Sources/RequestsFeature/ViewModels/RequestsReceivedViewModel.swift b/Sources/RequestsFeature/ViewModels/RequestsReceivedViewModel.swift
index 3f4be9cbe3541dd0b2a2431967c1e4ec8df5ce93..9ae5fc8e88209566d488134c9e6eb75d284cb607 100644
--- a/Sources/RequestsFeature/ViewModels/RequestsReceivedViewModel.swift
+++ b/Sources/RequestsFeature/ViewModels/RequestsReceivedViewModel.swift
@@ -5,12 +5,14 @@ import Shared
 import Combine
 import Defaults
 import XXModels
-import Integration
+import XXClient
 import DrawerFeature
 import ReportingFeature
 import CombineSchedulers
 import DependencyInjection
 
+import struct XXModels.Group
+
 struct RequestReceived: Hashable, Equatable {
     var request: Request?
     var isHidden: Bool
@@ -18,8 +20,11 @@ struct RequestReceived: Hashable, Equatable {
 }
 
 final class RequestsReceivedViewModel {
-    @Dependency private var session: SessionType
-    @Dependency private var reportingStatus: ReportingStatus
+    @Dependency var e2e: E2E
+    @Dependency var database: Database
+    @Dependency var groupManager: GroupChat
+    @Dependency var userDiscovery: UserDiscovery
+    @Dependency var reportingStatus: ReportingStatus
 
     @KeyObject(.isShowingHiddenRequests, defaultValue: false) var isShowingHiddenRequests: Bool
 
@@ -75,8 +80,8 @@ final class RequestsReceivedViewModel {
             isBanned: reportingStatus.isEnabled() ? false : nil
         )
 
-        let groupStream = session.dbManager.fetchGroupsPublisher(groupsQuery).assertNoFailure()
-        let contactsStream = session.dbManager.fetchContactsPublisher(contactsQuery).assertNoFailure()
+        let groupStream = database.fetchGroupsPublisher(groupsQuery).assertNoFailure()
+        let contactsStream = database.fetchContactsPublisher(contactsQuery).assertNoFailure()
 
         Publishers.CombineLatest3(
             groupStream,
@@ -139,11 +144,49 @@ final class RequestsReceivedViewModel {
     }
 
     func didTapStateButtonFor(request: Request) {
-        guard case let .contact(contact) = request else { return }
+        guard case var .contact(contact) = request else { return }
 
         if request.status == .failedToVerify {
             backgroundScheduler.schedule { [weak self] in
-                self?.session.verify(contact: contact)
+                guard let self = self else { return }
+
+                do {
+                    contact.authStatus = .verificationInProgress
+                    try self.database.saveContact(contact)
+
+                    if contact.email == nil && contact.phone == nil {
+                        let _ = try LookupUD.live(
+                            e2eId: self.e2e.getId(),
+                            udContact: self.userDiscovery.getContact(),
+                            lookupId: contact.id,
+                            callback: .init(handle: {
+                                switch $0 {
+                                case .success(let data):
+                                    let ownershipResult = try! self.e2e.verifyOwnership(
+                                        receivedContact: contact.marshaled!,
+                                        verifiedContact: data,
+                                        e2eId: self.e2e.getId()
+                                    )
+
+                                    if ownershipResult == true {
+                                        contact.authStatus = .verified
+                                        _ = try? self.database.saveContact(contact)
+                                    } else {
+                                        _ = try? self.database.deleteContact(contact)
+                                    }
+                                case .failure(let error):
+                                    print("^^^ \(#file):\(#line)  \(error.localizedDescription)")
+                                    contact.authStatus = .verificationFailed
+                                    _ = try? self.database.saveContact(contact)
+                                }
+                            })
+                        )
+                    }
+                } catch {
+                    print("^^^ \(#file):\(#line)  \(error.localizedDescription)")
+                    contact.authStatus = .verificationFailed
+                    _ = try? self.database.saveContact(contact)
+                }
             }
         } else if request.status == .verifying {
             verifyingSubject.send()
@@ -151,9 +194,9 @@ final class RequestsReceivedViewModel {
     }
 
     func didRequestHide(group: Group) {
-        if var group = try? session.dbManager.fetchGroups(.init(id: [group.id])).first {
+        if var group = try? database.fetchGroups(.init(id: [group.id])).first {
             group.authStatus = .hidden
-            _ = try? session.dbManager.saveGroup(group)
+            _ = try? database.saveGroup(group)
         }
     }
 
@@ -161,12 +204,23 @@ final class RequestsReceivedViewModel {
         hudSubject.send(.on)
 
         backgroundScheduler.schedule { [weak self] in
+            guard let self = self else { return }
+
             do {
-                try self?.session.join(group: group)
-                self?.hudSubject.send(.none)
-                self?.groupConfirmationSubject.send(group)
+                let trackedId = try self.groupManager
+                    .getGroup(groupId: group.id)
+                    .getTrackedID()
+
+                try self.groupManager.joinGroup(trackedGroupId: trackedId)
+
+                var group = group
+                group.authStatus = .participating
+                try self.database.saveGroup(group)
+
+                self.hudSubject.send(.none)
+                self.groupConfirmationSubject.send(group)
             } catch {
-                self?.hudSubject.send(.error(.init(with: error)))
+                self.hudSubject.send(.error(.init(with: error)))
             }
         }
     }
@@ -175,8 +229,8 @@ final class RequestsReceivedViewModel {
         _ group: Group,
         _ completion: @escaping (Result<[DrawerTableCellModel], Error>) -> Void
     ) {
-        if let info = try? session.dbManager.fetchGroupInfos(.init(groupId: group.id)).first {
-            session.dbManager.fetchContactsPublisher(.init(id: Set(info.members.map(\.id))))
+        if let info = try? database.fetchGroupInfos(.init(groupId: group.id)).first {
+            database.fetchContactsPublisher(.init(id: Set(info.members.map(\.id))))
                 .assertNoFailure()
                 .sink { members in
                     let withUsername = members
@@ -209,9 +263,9 @@ final class RequestsReceivedViewModel {
     }
 
     func didRequestHide(contact: Contact) {
-        if var contact = try? session.dbManager.fetchContacts(.init(id: [contact.id])).first {
+        if var contact = try? database.fetchContacts(.init(id: [contact.id])).first {
             contact.authStatus = .hidden
-            _ = try? session.dbManager.saveContact(contact)
+            _ = try? database.saveContact(contact)
         }
     }
 
@@ -219,21 +273,31 @@ final class RequestsReceivedViewModel {
         hudSubject.send(.on)
 
         var contact = contact
+        contact.authStatus = .confirming
         contact.nickname = nickname ?? contact.username
 
         backgroundScheduler.schedule { [weak self] in
+            guard let self = self else { return }
+
             do {
-                try self?.session.confirm(contact)
-                self?.hudSubject.send(.none)
-                self?.contactConfirmationSubject.send(contact)
+                try self.database.saveContact(contact)
+
+                let _ = try self.e2e.confirmReceivedRequest(partnerContact: contact.id)
+                contact.authStatus = .friend
+                try self.database.saveContact(contact)
+
+                self.hudSubject.send(.none)
+                self.contactConfirmationSubject.send(contact)
             } catch {
-                self?.hudSubject.send(.error(.init(with: error)))
+                contact.authStatus = .confirmationFailed
+                _ = try? self.database.saveContact(contact)
+                self.hudSubject.send(.error(.init(with: error)))
             }
         }
     }
 
     func groupChatWith(group: Group) -> GroupInfo {
-        guard let info = try? session.dbManager.fetchGroupInfos(.init(groupId: group.id)).first else {
+        guard let info = try? database.fetchGroupInfos(.init(groupId: group.id)).first else {
             fatalError()
         }
 
diff --git a/Sources/RequestsFeature/ViewModels/RequestsSentViewModel.swift b/Sources/RequestsFeature/ViewModels/RequestsSentViewModel.swift
index 40964837a7a4254badcc48c5750389def82a3fda..2463f0118773fa6af6794efe60ed34430c5a2c55 100644
--- a/Sources/RequestsFeature/ViewModels/RequestsSentViewModel.swift
+++ b/Sources/RequestsFeature/ViewModels/RequestsSentViewModel.swift
@@ -5,7 +5,8 @@ import Shared
 import Combine
 import Defaults
 import XXModels
-import Integration
+import Defaults
+import XXClient
 import ToastFeature
 import ReportingFeature
 import CombineSchedulers
@@ -17,9 +18,13 @@ struct RequestSent: Hashable, Equatable {
 }
 
 final class RequestsSentViewModel {
-    @Dependency private var session: SessionType
-    @Dependency private var reportingStatus: ReportingStatus
-    @Dependency private var toastController: ToastController
+    @Dependency var e2e: E2E
+    @Dependency var database: Database
+    @Dependency var userDiscovery: UserDiscovery
+    @Dependency var reportingStatus: ReportingStatus
+    @Dependency var toastController: ToastController
+
+    @KeyObject(.username, defaultValue: nil) var username: String?
 
     var hudPublisher: AnyPublisher<HUDStatus, Never> {
         hudSubject.eraseToAnyPublisher()
@@ -45,7 +50,7 @@ final class RequestsSentViewModel {
             isBanned: reportingStatus.isEnabled() ? false : nil
         )
 
-        session.dbManager.fetchContactsPublisher(query)
+        database.fetchContactsPublisher(query)
             .assertNoFailure()
             .removeDuplicates()
             .map { data -> NSDiffableDataSourceSnapshot<Section, RequestSent> in
@@ -65,7 +70,14 @@ final class RequestsSentViewModel {
             guard let self = self else { return }
 
             do {
-                try self.session.retryRequest(contact)
+                var myFacts = try self.userDiscovery.getFacts()
+                myFacts.append(Fact(fact: self.username!, type: FactType.username.rawValue))
+
+                let _ = try self.e2e.requestAuthenticatedChannel(
+                    partnerContact: contact.id,
+                    myFacts: myFacts
+                )
+
                 self.hudSubject.send(.none)
 
                 var item = item
diff --git a/Sources/RestoreFeature/Controllers/RestoreController.swift b/Sources/RestoreFeature/Controllers/RestoreController.swift
index f2081aaef8eca0773f552bf685976dbfe67d75c9..5ba058c634a7e790927794f6a981a91368acee05 100644
--- a/Sources/RestoreFeature/Controllers/RestoreController.swift
+++ b/Sources/RestoreFeature/Controllers/RestoreController.swift
@@ -14,8 +14,8 @@ public final class RestoreController: UIViewController {
     private var cancellables = Set<AnyCancellable>()
     private var drawerCancellables = Set<AnyCancellable>()
 
-    public init(_ ndf: String, _ settings: RestoreSettings) {
-        viewModel = .init(ndf: ndf, settings: settings)
+    public init(_ settings: RestoreSettings) {
+        viewModel = .init(settings: settings)
         super.init(nibName: nil, bundle: nil)
     }
 
diff --git a/Sources/RestoreFeature/Controllers/RestoreListController.swift b/Sources/RestoreFeature/Controllers/RestoreListController.swift
index 33470e44212a67e1ee6833cfd70664aca840321f..a10fdfcf8101fc59cd63b8ff7a8807aa56aea77f 100644
--- a/Sources/RestoreFeature/Controllers/RestoreListController.swift
+++ b/Sources/RestoreFeature/Controllers/RestoreListController.swift
@@ -11,7 +11,6 @@ public final class RestoreListController: UIViewController {
 
     lazy private var screenView = RestoreListView()
 
-    private let ndf: String
     private let viewModel = RestoreListViewModel()
     private var cancellables = Set<AnyCancellable>()
     private var drawerCancellables = Set<AnyCancellable>()
@@ -21,13 +20,6 @@ public final class RestoreListController: UIViewController {
         presentWarning()
     }
 
-    public init(_ ndf: String) {
-        self.ndf = ndf
-        super.init(nibName: nil, bundle: nil)
-    }
-
-    public required init?(coder: NSCoder) { nil }
-
     public override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
         navigationItem.backButtonTitle = ""
@@ -45,7 +37,7 @@ public final class RestoreListController: UIViewController {
         viewModel.backupPublisher
             .receive(on: DispatchQueue.main)
             .sink { [unowned self] in
-                coordinator.toRestore(using: ndf, with: $0, from: self)
+                coordinator.toRestore(with: $0, from: self)
             }.store(in: &cancellables)
 
         screenView.cancelButton
diff --git a/Sources/RestoreFeature/Coordinator/RestoreCoordinator.swift b/Sources/RestoreFeature/Coordinator/RestoreCoordinator.swift
index 2183035bca4a57ee9fd4435b2656fed7123de814..b5f5d05716247e1fa164a935c8bc72f25f5b5969 100644
--- a/Sources/RestoreFeature/Coordinator/RestoreCoordinator.swift
+++ b/Sources/RestoreFeature/Coordinator/RestoreCoordinator.swift
@@ -8,7 +8,7 @@ public protocol RestoreCoordinating {
     func toSuccess(from: UIViewController)
     func toDrawer(_: UIViewController, from: UIViewController)
     func toPassphrase(from: UIViewController, _: @escaping StringClosure)
-    func toRestore(using: String, with: RestoreSettings, from: UIViewController)
+    func toRestore(with: RestoreSettings, from: UIViewController)
 }
 
 public struct RestoreCoordinator: RestoreCoordinating {
@@ -18,13 +18,13 @@ public struct RestoreCoordinator: RestoreCoordinating {
 
     var successFactory: () -> UIViewController
     var chatListFactory: () -> UIViewController
-    var restoreFactory: (String, RestoreSettings) -> UIViewController
+    var restoreFactory: (RestoreSettings) -> UIViewController
     var passphraseFactory: (@escaping StringClosure) -> UIViewController
 
     public init(
         successFactory: @escaping () -> UIViewController,
         chatListFactory: @escaping () -> UIViewController,
-        restoreFactory: @escaping (String, RestoreSettings) -> UIViewController,
+        restoreFactory: @escaping (RestoreSettings) -> UIViewController,
         passphraseFactory: @escaping (@escaping StringClosure) -> UIViewController
     ) {
         self.successFactory = successFactory
@@ -36,11 +36,10 @@ public struct RestoreCoordinator: RestoreCoordinating {
 
 public extension RestoreCoordinator {
     func toRestore(
-        using ndf: String,
         with settings: RestoreSettings,
         from parent: UIViewController
     ) {
-        let screen = restoreFactory(ndf, settings)
+        let screen = restoreFactory(settings)
         pushPresenter.present(screen, from: parent)
     }
 
diff --git a/Sources/RestoreFeature/Resources/cmix.rip.crt b/Sources/RestoreFeature/Resources/cmix.rip.crt
new file mode 100644
index 0000000000000000000000000000000000000000..baa29e6a035a4beb81f4b82ad980593e3640f869
--- /dev/null
+++ b/Sources/RestoreFeature/Resources/cmix.rip.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx
+GzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJp
+cDAeFw0xOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNV
+BAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDh
+Dwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfs
+WYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSE
+tJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uA
+m3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9
+bJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEA
+AaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEA
+neUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIf
+U/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2
+qvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4
+cyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1R
+tgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E5
+6m52PyzMNV+2N21IPppKwA==
+-----END CERTIFICATE-----
diff --git a/Sources/RestoreFeature/Resources/udContact.bin b/Sources/RestoreFeature/Resources/udContact.bin
new file mode 100644
index 0000000000000000000000000000000000000000..b2611d4124e7d083ad99cf37eba3810cc6d8926c
--- /dev/null
+++ b/Sources/RestoreFeature/Resources/udContact.bin
@@ -0,0 +1 @@
+<xxc(2)7mbKFLE201WzH4SGxAOpHjjehwztIV+KGifi5L/PYPcDkAZiB9kZo+Dl3Vc7dD2SdZCFMOJVgwqGzfYRDkjc8RGEllBqNxq2sRRX09iQVef0kJQUgJCHNCOcvm6Ki0JJwvjLceyFh36iwK8oLbhLgqEZY86UScdACTyBCzBIab3ob5mBthYc3mheV88yq5PGF2DQ+dEvueUm+QhOSfwzppAJA/rpW9Wq9xzYcQzaqc3ztAGYfm2BBAHS7HVmkCbvZ/K07Xrl4EBPGHJYq12tWAN/C3mcbbBYUOQXyEzbSl/mO7sL3ORr0B4FMuqCi8EdlD6RO52pVhY+Cg6roRH1t5Ng1JxPt8Mv1yyjbifPhZ5fLKwxBz8UiFORfk0/jnhwgm25LRHqtNRRUlYXLvhv0HhqyYTUt17WNtCLATSVbqLrFGdy2EGadn8mP+kQNHp93f27d/uHgBNNe7LpuYCJMdWpoG6bOqmHEftxt0/MIQA8fTtTm3jJzv+7/QjZJDvQIv0SNdp8HFogpuwde+GuS4BcY7v5xz+ArGWcRR63ct2z83MqQEn9ODr1/gAAAgA7szRpDDQIdFUQo9mkWg8xBA==xxc>
\ No newline at end of file
diff --git a/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift b/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift
index bea37e5113ad33a547e5680e478a0ed7717db741..4207eb1b82eacd2f726bb8e0f8d07d7ce8a6e5c8 100644
--- a/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift
+++ b/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift
@@ -4,7 +4,6 @@ import Shared
 import Combine
 import Defaults
 import Foundation
-import Integration
 import BackupFeature
 import DependencyInjection
 
@@ -13,6 +12,9 @@ import iCloudFeature
 import DropboxFeature
 import GoogleDriveFeature
 
+import XXClient
+import struct Models.Backup
+
 enum RestorationStep {
     case idle(CloudService, Backup?)
     case downloading(Float, Float)
@@ -39,12 +41,16 @@ extension RestorationStep: Equatable {
 }
 
 final class RestoreViewModel {
+    @Dependency var cMixManager: CMixManager
+
     @Dependency private var sftpService: SFTPService
     @Dependency private var iCloudService: iCloudInterface
     @Dependency private var dropboxService: DropboxInterface
     @Dependency private var googleService: GoogleDriveInterface
 
     @KeyObject(.username, defaultValue: nil) var username: String?
+    @KeyObject(.phone, defaultValue: nil) var phone: String?
+    @KeyObject(.email, defaultValue: nil) var email: String?
 
     var step: AnyPublisher<RestorationStep, Never> {
         stepRelay.eraseToAnyPublisher()
@@ -54,13 +60,11 @@ final class RestoreViewModel {
     //
     private var pendingData: Data?
 
-    private let ndf: String
     private var passphrase: String!
     private let settings: RestoreSettings
     private let stepRelay: CurrentValueSubject<RestorationStep, Never>
 
-    init(ndf: String, settings: RestoreSettings) {
-        self.ndf = ndf
+    init(settings: RestoreSettings) {
         self.settings = settings
         self.stepRelay = .init(.idle(settings.cloudService, settings.backup))
     }
@@ -155,13 +159,120 @@ final class RestoreViewModel {
             guard let self = self else { return }
 
             do {
-                let session = try Session(
-                    passphrase: self.passphrase,
-                    backupFile: data,
-                    ndf: self.ndf
+                let report = try self.cMixManager.restore(
+                    backup: data,
+                    passphrase: self.passphrase
+                )
+
+                struct BackupParameters: Codable {
+                    var email: String?
+                    var phone: String?
+                    var username: String
+                }
+
+                guard let paramsData = report.params.data(using: .utf8) else {
+                    fatalError("Couldn't parse parameters from backup to byte array")
+                }
+
+                let facts = try JSONDecoder().decode(
+                    BackupParameters.self,
+                    from: paramsData
+                )
+
+                var phoneFact: Fact?
+
+                self.phone = facts.phone
+                self.email = facts.email
+
+                let cMix = try self.cMixManager.load()
+
+                DependencyInjection.Container.shared.register(cMix)
+
+                let e2e = try Login.live(
+                    cMixId: cMix.getId(),
+                    authCallbacks: .init(
+                        handle: { callbacks in
+                            switch callbacks {
+                            case .reset(
+                                contact: _,
+                                receptionId: _,
+                                ephemeralId: _,
+                                roundId: _
+                            ):
+                                break
+                            case .confirm(
+                                contact: _,
+                                receptionId: _,
+                                ephemeralId: _,
+                                roundId: _
+                            ):
+                                break
+                            case .request(
+                                contact: _,
+                                receptionId: _,
+                                ephemeralId: _,
+                                roundId: _
+                            ):
+                                break
+                            }
+                        }
+                    ),
+                    identity: try cMix.makeLegacyReceptionIdentity()
                 )
 
-                DependencyInjection.Container.shared.register(session as SessionType)
+                guard let certPath = Bundle.module.path(forResource: "cmix.rip", ofType: "crt"),
+                      let contactFilePath = Bundle.module.path(forResource: "udContact", ofType: "bin") else {
+                    fatalError("Couldn't retrieve alternative UD credentials")
+                }
+
+                let userDiscovery = try NewUdManagerFromBackup.live(.init(
+                    e2eId: e2e.getId(),
+                    follower: .init(handle: { cMix.networkFollowerStatus().rawValue }),
+                    email: nil,
+                    phone: nil,
+                    cert: Data(contentsOf: URL(fileURLWithPath: certPath)),
+                    contactFile: Data(contentsOf: URL(fileURLWithPath: contactFilePath)),
+                    address: "46.101.98.49:18001"
+                ))
+
+                DependencyInjection.Container.shared.register(userDiscovery)
+
+                try e2e.registerListener(
+                    senderId: nil,
+                    messageType: 2,
+                    callback: .init(handle: { message in
+                        print(message.timestamp)
+                    })
+                )
+
+                DependencyInjection.Container.shared.register(e2e)
+
+                let groupManager = try NewGroupChat.live(
+                    e2eId: e2e.getId(),
+                    groupRequest: .init(handle: {
+                        print($0)
+                    }),
+                    groupChatProcessor: .init(handle: {
+                        print($0)
+                    })
+                )
+
+                DependencyInjection.Container.shared.register(groupManager)
+
+                let transferManager = try InitFileTransfer.live(
+                    e2eId: e2e.getId(),
+                    callback: .init(handle: {
+                        switch $0 {
+                        case .success(let receivedFile):
+                            print(receivedFile.name)
+                        case .failure(let error):
+                            print(error.localizedDescription)
+                        }
+                    })
+                )
+
+                DependencyInjection.Container.shared.register(transferManager)
+
                 self.stepRelay.send(.done)
             } catch {
                 self.pendingData = data
diff --git a/Sources/ScanFeature/ViewModels/ScanDisplayViewModel.swift b/Sources/ScanFeature/ViewModels/ScanDisplayViewModel.swift
index df4560653bbf5bd8f342148a3847ddef9f383d97..1b7ed9b26093ceb6e0a8da599f04cce410368db8 100644
--- a/Sources/ScanFeature/ViewModels/ScanDisplayViewModel.swift
+++ b/Sources/ScanFeature/ViewModels/ScanDisplayViewModel.swift
@@ -1,8 +1,9 @@
 import UIKit
+import Models
 import Combine
 import Defaults
 import Countries
-import Integration
+import XXClient
 import DependencyInjection
 
 struct ScanDisplayViewState: Equatable {
@@ -14,7 +15,7 @@ struct ScanDisplayViewState: Equatable {
 }
 
 final class ScanDisplayViewModel {
-    @Dependency private var session: SessionType
+    @Dependency var userDiscovery: UserDiscovery
 
     @KeyObject(.email, defaultValue: nil) private var email: String?
     @KeyObject(.phone, defaultValue: nil) private var phone: String?
@@ -58,7 +59,23 @@ final class ScanDisplayViewModel {
     func generateQR() {
         guard let filter = CIFilter(name: "CIQRCodeGenerator") else { return }
 
-        filter.setValue(session.myQR, forKey: "inputMessage")
+        var facts: [Fact] = []
+        let myContact = try! userDiscovery.getContact()
+
+        if sharingPhone {
+            facts.append(Fact(fact: phone!, type: FactType.phone.rawValue))
+        }
+
+        if sharingEmail {
+            facts.append(Fact(fact: email!, type: FactType.email.rawValue))
+        }
+
+        let myContactWithFacts = try! SetFactsOnContact.live(
+            contact: myContact,
+            facts: facts
+        )
+
+        filter.setValue(myContactWithFacts, forKey: "inputMessage")
         let transform = CGAffineTransform(scaleX: 5, y: 5)
 
         if let output = filter.outputImage?.transformed(by: transform) {
diff --git a/Sources/ScanFeature/ViewModels/ScanViewModel.swift b/Sources/ScanFeature/ViewModels/ScanViewModel.swift
index b940226d75390dc33a79118d44ca74ca4cbe3240..c7c9b11a61521cf16903fb14845277712e74cbba 100644
--- a/Sources/ScanFeature/ViewModels/ScanViewModel.swift
+++ b/Sources/ScanFeature/ViewModels/ScanViewModel.swift
@@ -3,7 +3,7 @@ import Models
 import Combine
 import XXModels
 import Foundation
-import Integration
+import XXClient
 import CombineSchedulers
 import DependencyInjection
 
@@ -26,7 +26,8 @@ struct ScanViewState: Equatable {
 }
 
 final class ScanViewModel {
-    @Dependency private var session: SessionType
+    @Dependency var database: Database
+    @Dependency var getFactsFromContact: GetFactsFromContact
 
     var backgroundScheduler: AnySchedulerOf<DispatchQueue>
         = DispatchQueue.global().eraseToAnyScheduler()
@@ -56,7 +57,7 @@ final class ScanViewModel {
 
 
 
-                if let previouslyAdded = try? self.session.dbManager.fetchContacts(.init(id: [usernameAndId.1])).first {
+                if let previouslyAdded = try? self.database.fetchContacts(.init(id: [usernameAndId.1])).first {
                     var error = ScanError.unknown(Localized.Scan.Error.general)
 
                     switch previouslyAdded.authStatus {
@@ -72,12 +73,16 @@ final class ScanViewModel {
                     return
                 }
 
+                let facts = try? self.getFactsFromContact(contact: data)
+                let contactEmail = facts?.first(where: { $0.type == FactType.email.rawValue })?.fact
+                let contactPhone = facts?.first(where: { $0.type == FactType.phone.rawValue })?.fact
+
                 let contact = Contact(
                     id: usernameAndId.1,
                     marshaled: data,
                     username: usernameAndId.0,
-                    email: try? self.session.extract(fact: .email, from: data),
-                    phone: try? self.session.extract(fact: .phone, from: data),
+                    email: contactEmail,
+                    phone: contactPhone,
                     nickname: nil,
                     photo: nil,
                     authStatus: .stranger,
@@ -93,9 +98,11 @@ final class ScanViewModel {
     }
 
     private func verifyScanned(_ data: Data) throws -> (String, Data)? {
-        guard let username = try session.extract(fact: .username, from: data),
-                let id = session.getId(from: data) else { return nil }
+        let id = try? GetIdFromContact.live(data)
+        let facts = try? getFactsFromContact(contact: data)
+        let username = facts?.first(where: { $0.type == FactType.username.rawValue })?.fact
 
+        guard let id = id, let username = username else { return nil }
         return (username, id)
     }
 
diff --git a/Sources/SearchFeature/ViewModels/SearchContainerViewModel.swift b/Sources/SearchFeature/ViewModels/SearchContainerViewModel.swift
index e308f6a5b21134224ec17155b9585a9718cf1204..9ca3794c922d0ff49e24e3a6db450c57fbd853ea 100644
--- a/Sources/SearchFeature/ViewModels/SearchContainerViewModel.swift
+++ b/Sources/SearchFeature/ViewModels/SearchContainerViewModel.swift
@@ -1,15 +1,14 @@
 import UIKit
 import Combine
 import Defaults
-import Integration
 import PushFeature
+import XXClient
 import DependencyInjection
 
 final class SearchContainerViewModel {
-    @Dependency var session: SessionType
     @Dependency var pushHandler: PushHandling
+    @Dependency var dummyTrafficManager: DummyTraffic
 
-    @KeyObject(.dummyTrafficOn, defaultValue: false) var isCoverTrafficEnabled
     @KeyObject(.pushNotifications, defaultValue: false) var pushNotifications
     @KeyObject(.askedDummyTrafficOnce, defaultValue: false) var offeredCoverTraffic
 
@@ -25,8 +24,7 @@ final class SearchContainerViewModel {
     }
 
     func didEnableCoverTraffic() {
-        isCoverTrafficEnabled = true
-        session.setDummyTraffic(status: true)
+        try! dummyTrafficManager.setStatus(true)
     }
 
     private func verifyCoverTraffic() {
diff --git a/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift b/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift
index 6f708401cc71d12838efcc64ca594818ecf2ae42..d608dc01c95d17aad9ba18d08b6f0161d502840a 100644
--- a/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift
+++ b/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift
@@ -3,11 +3,15 @@ import UIKit
 import Shared
 import Combine
 import XXModels
+import XXClient
 import Defaults
 import Countries
-import Integration
+import Models
+import Defaults
+import CustomDump
 import NetworkMonitor
 import ReportingFeature
+import CombineSchedulers
 import DependencyInjection
 
 typealias SearchSnapshot = NSDiffableDataSourceSnapshot<SearchSection, SearchItem>
@@ -20,10 +24,18 @@ struct SearchLeftViewState {
 }
 
 final class SearchLeftViewModel {
-    @Dependency var session: SessionType
+    @Dependency var e2e: E2E
+    @Dependency var database: Database
+    @Dependency var userDiscovery: UserDiscovery
     @Dependency var reportingStatus: ReportingStatus
     @Dependency var networkMonitor: NetworkMonitoring
 
+    @KeyObject(.username, defaultValue: nil) var username: String?
+
+    var myId: Data {
+        try! GetIdFromContact.live(userDiscovery.getContact())
+    }
+
     var hudPublisher: AnyPublisher<HUDStatus, Never> {
         hudSubject.eraseToAnyPublisher()
     }
@@ -36,6 +48,8 @@ final class SearchLeftViewModel {
         stateSubject.eraseToAnyPublisher()
     }
 
+    var backgroundScheduler: AnySchedulerOf<DispatchQueue> = DispatchQueue.global().eraseToAnyScheduler()
+
     private var invitation: String?
     private var searchCancellables = Set<AnyCancellable>()
     private let successSubject = PassthroughSubject<Contact, Never>()
@@ -99,47 +113,107 @@ final class SearchLeftViewModel {
             content += stateSubject.value.country.code
         }
 
-        session.search(fact: "\(prefix)\(content)")
-            .sink { [unowned self] in
-                if case .failure(let error) = $0 {
-                    self.appendToLocalSearch(nil)
-                    self.hudSubject.send(.error(.init(with: error)))
-                }
-            } receiveValue: { contact in
-                self.hudSubject.send(.none)
-                self.appendToLocalSearch(contact)
-            }.store(in: &searchCancellables)
+//        backgroundScheduler.schedule { [weak self] in
+//            guard let self = self else { return }
+
+            do {
+                let report = try SearchUD.live(
+                    e2eId: self.e2e.getId(),
+                    udContact: self.userDiscovery.getContact(),
+                    facts: [Fact(fact: "teste", type: 0)],
+                    callback: .init(handle: {
+                        switch $0 {
+                        case .success(let dataArray):
+                            print("^^^ \(#file):\(#line) \(dataArray.map { $0.base64EncodedString() })")
+
+                            // self.hudSubject.send(.none)
+                            // self.appendToLocalSearch(contact)
+
+                        case .failure(let error):
+                            print("^^^ \(#file):\(#line) error: \(error.localizedDescription)")
+                            self.appendToLocalSearch(nil)
+                            self.hudSubject.send(.error(.init(with: error)))
+                        }
+                    })
+                )
+
+                print(report)
+            } catch {
+                print("^^^ \(#file):\(#line) error: \(error.localizedDescription)")
+            }
+//        }
     }
 
     func didTapResend(contact: Contact) {
         hudSubject.send(.on)
 
-        do {
-            try self.session.retryRequest(contact)
-            hudSubject.send(.none)
-        } catch {
-            hudSubject.send(.error(.init(with: error)))
+        var contact = contact
+        contact.authStatus = .requesting
+
+        backgroundScheduler.schedule { [weak self] in
+            guard let self = self else { return }
+
+            do {
+                try self.database.saveContact(contact)
+
+                var myFacts = try self.userDiscovery.getFacts()
+                myFacts.append(Fact(fact: self.username!, type: FactType.username.rawValue))
+
+                let _ = try self.e2e.requestAuthenticatedChannel(
+                    partnerContact: contact.id,
+                    myFacts: myFacts
+                )
+
+                contact.authStatus = .requested
+                contact = try self.database.saveContact(contact)
+
+                self.hudSubject.send(.none)
+            } catch {
+                contact.authStatus = .requestFailed
+                _ = try? self.database.saveContact(contact)
+                self.hudSubject.send(.error(.init(with: error)))
+            }
         }
     }
 
     func didTapRequest(contact: Contact) {
         hudSubject.send(.on)
+
         var contact = contact
         contact.nickname = contact.username
+        contact.authStatus = .requesting
+
+        backgroundScheduler.schedule { [weak self] in
+            guard let self = self else { return }
 
-        do {
-            try self.session.add(contact)
-            hudSubject.send(.none)
-            successSubject.send(contact)
-        } catch {
-            hudSubject.send(.error(.init(with: error)))
+            do {
+                try self.database.saveContact(contact)
+
+                var myFacts = try self.userDiscovery.getFacts()
+                myFacts.append(Fact(fact: self.username!, type: FactType.username.rawValue))
+
+                let _ = try self.e2e.requestAuthenticatedChannel(
+                    partnerContact: contact.marshaled!,
+                    myFacts: myFacts
+                )
+
+                contact.authStatus = .requested
+                contact = try self.database.saveContact(contact)
+
+                self.hudSubject.send(.none)
+                self.successSubject.send(contact)
+            } catch {
+                contact.authStatus = .requestFailed
+                _ = try? self.database.saveContact(contact)
+                self.hudSubject.send(.error(.init(with: error)))
+            }
         }
     }
 
     func didSet(nickname: String, for contact: Contact) {
-        if var contact = try? session.dbManager.fetchContacts(.init(id: [contact.id])).first {
+        if var contact = try? database.fetchContacts(.init(id: [contact.id])).first {
             contact.nickname = nickname
-            _ = try? session.dbManager.saveContact(contact)
+            _ = try? database.saveContact(contact)
         }
     }
 
@@ -147,7 +221,7 @@ final class SearchLeftViewModel {
         var snapshot = SearchSnapshot()
 
         if var user = user {
-            if let contact = try! session.dbManager.fetchContacts(.init(id: [user.id])).first {
+            if let contact = try? database.fetchContacts(.init(id: [user.id])).first {
                 user.isBanned = contact.isBanned
                 user.isBlocked = contact.isBlocked
                 user.authStatus = contact.authStatus
@@ -169,7 +243,7 @@ final class SearchLeftViewModel {
             isBanned: reportingStatus.isEnabled() ? false : nil
         )
 
-        if let locals = try? session.dbManager.fetchContacts(localsQuery),
+        if let locals = try? database.fetchContacts(localsQuery),
            let localsWithoutMe = removeMyself(from: locals),
            localsWithoutMe.isEmpty == false {
             snapshot.appendSections([.connections])
@@ -183,6 +257,6 @@ final class SearchLeftViewModel {
     }
 
     private func removeMyself(from collection: [Contact]) -> [Contact]? {
-        collection.filter { $0.id != session.myId }
+        collection.filter { $0.id != myId }
     }
 }
diff --git a/Sources/SearchFeature/ViewModels/SearchRightViewModel.swift b/Sources/SearchFeature/ViewModels/SearchRightViewModel.swift
index db977528e9a65491ada83947cdad167897532982..671e340d5a0d32062d1f1be423ce1afd23cc9b2d 100644
--- a/Sources/SearchFeature/ViewModels/SearchRightViewModel.swift
+++ b/Sources/SearchFeature/ViewModels/SearchRightViewModel.swift
@@ -1,10 +1,11 @@
 import Shared
+import Models
 import Combine
 import XXModels
 import Defaults
+import XXClient
 import Foundation
 import Permissions
-import Integration
 import ReportingFeature
 import DependencyInjection
 
@@ -23,9 +24,10 @@ enum ScanningError: Equatable {
 }
 
 final class SearchRightViewModel {
-    @Dependency var session: SessionType
+    @Dependency var database: Database
     @Dependency var permissions: PermissionHandling
     @Dependency var reportingStatus: ReportingStatus
+    @Dependency var getFactsFromContact: GetFactsFromContact
 
     var foundPublisher: AnyPublisher<Contact, Never> {
         foundSubject.eraseToAnyPublisher()
@@ -70,8 +72,11 @@ final class SearchRightViewModel {
         /// Whatever got scanned, needs to have id and username
         /// otherwise is just noise or an unknown qr code
         ///
-        guard let userId = session.getId(from: data),
-              let username = try? session.extract(fact: .username, from: data) else {
+        let userId = try? GetIdFromContact.live(data)
+        let facts = try? getFactsFromContact(contact: data)
+        let username = facts?.first(where: { $0.type == FactType.username.rawValue })?.fact
+
+        guard let userId = userId, let username = username else {
             let errorTitle = Localized.Scan.Error.invalid
             statusSubject.send(.failed(.unknown(errorTitle)))
             return
@@ -80,7 +85,7 @@ final class SearchRightViewModel {
         /// Make sure we are not processing a contact
         /// that we already have
         ///
-        if let alreadyContact = try? session.dbManager.fetchContacts(.init(id: [userId])).first {
+        if let alreadyContact = try? database.fetchContacts(.init(id: [userId])).first {
             if alreadyContact.isBlocked, reportingStatus.isEnabled() {
                 statusSubject.send(.failed(.unknown("You previously blocked this user.")))
                 return
@@ -108,12 +113,20 @@ final class SearchRightViewModel {
         statusSubject.send(.success)
         cameraSemaphoreSubject.send(false)
 
+        let email = try? GetFactsFromContact.live(contact: data)
+            .first(where: { $0.type == FactType.email.rawValue })
+            .map(\.fact)
+
+        let phone = try? GetFactsFromContact.live(contact: data)
+            .first(where: { $0.type == FactType.phone.rawValue })
+            .map(\.fact)
+
         foundSubject.send(.init(
             id: userId,
             marshaled: data,
             username: username,
-            email: try? session.extract(fact: .email, from: data),
-            phone: try? session.extract(fact: .phone, from: data),
+            email: email,
+            phone: phone,
             nickname: nil,
             photo: nil,
             authStatus: .stranger,
diff --git a/Sources/SettingsFeature/ViewModels/AccountDeleteViewModel.swift b/Sources/SettingsFeature/ViewModels/AccountDeleteViewModel.swift
index db7e64016a317b8fe74fa496102437c771f500db..ea8dd26ddfda1dc94f22991a81817d50d71d4bc6 100644
--- a/Sources/SettingsFeature/ViewModels/AccountDeleteViewModel.swift
+++ b/Sources/SettingsFeature/ViewModels/AccountDeleteViewModel.swift
@@ -1,12 +1,9 @@
 import HUD
 import Combine
-import Integration
 import Foundation
 import DependencyInjection
 
 final class AccountDeleteViewModel {
-    @Dependency private var session: SessionType
-
     var deleting = false
 
     var hud: AnyPublisher<HUDStatus, Never> { hudRelay.eraseToAnyPublisher() }
@@ -21,9 +18,6 @@ final class AccountDeleteViewModel {
         }
 
         do {
-            try session.deleteMyself()
-            DependencyInjection.Container.shared.unregister(SessionType.self)
-
             DispatchQueue.main.async { [weak self] in
                 self?.hudRelay.send(.error(.init(
                     content: "Now kill the app and re-open",
diff --git a/Sources/SettingsFeature/ViewModels/SettingsViewModel.swift b/Sources/SettingsFeature/ViewModels/SettingsViewModel.swift
index 9b985922329599ac17010bdd2d16c43dec81a454..b44c37d85ccbaa03cb46559dc40b42494b1ae174 100644
--- a/Sources/SettingsFeature/ViewModels/SettingsViewModel.swift
+++ b/Sources/SettingsFeature/ViewModels/SettingsViewModel.swift
@@ -4,8 +4,8 @@ import Shared
 import Combine
 import Defaults
 import Permissions
-import Integration
 import PushFeature
+import XXClient
 import UserNotifications
 import CombineSchedulers
 import DependencyInjection
@@ -21,11 +21,10 @@ struct SettingsViewState: Equatable {
 }
 
 final class SettingsViewModel {
-    @Dependency private var session: SessionType
+    @Dependency var dummyTrafficManager: DummyTraffic
     @Dependency private var pushHandler: PushHandling
     @Dependency private var permissions: PermissionHandling
 
-    @KeyObject(.dummyTrafficOn, defaultValue: false) var isDummyTrafficOn: Bool
     @KeyObject(.biometrics, defaultValue: false) private var biometrics
     @KeyObject(.hideAppList, defaultValue: false) private var hideAppList
     @KeyObject(.icognitoKeyboard, defaultValue: false) private var icognitoKeyboard
@@ -47,7 +46,7 @@ final class SettingsViewModel {
         stateRelay.value.isPushNotification = pushNotifications
         stateRelay.value.isInAppNotification = inAppNotifications
         stateRelay.value.isBiometricsPossible = permissions.isBiometricsAvailable
-        stateRelay.value.isDummyTrafficOn = isDummyTrafficOn
+        stateRelay.value.isDummyTrafficOn = dummyTrafficManager.getStatus()
     }
 
     func didToggleBiometrics() {
@@ -64,9 +63,9 @@ final class SettingsViewModel {
     }
 
     func didToggleDummyTraffic() {
-        isDummyTrafficOn.toggle()
-        stateRelay.value.isDummyTrafficOn = isDummyTrafficOn
-        session.setDummyTraffic(status: isDummyTrafficOn)
+        let currently = dummyTrafficManager.getStatus()
+        try! dummyTrafficManager.setStatus(!currently)
+        stateRelay.value.isDummyTrafficOn = !currently
     }
 
     func didToggleHideActiveApps() {
@@ -134,7 +133,7 @@ final class SettingsViewModel {
                 guard let self = self else { return }
 
                 do {
-                    try self.session.unregisterNotifications()
+                    fatalError(">>> Missing API for notifications")
                     self.hudRelay.send(.none)
                 } catch {
                     self.hudRelay.send(.error(.init(with: error)))
diff --git a/Sources/Integration/FeedbackPlayer.swift b/Sources/Shared/FeedbackPlayer.swift
similarity index 100%
rename from Sources/Integration/FeedbackPlayer.swift
rename to Sources/Shared/FeedbackPlayer.swift
diff --git a/Tests/SearchFeatureTests/Coordinator/SearchCoordinatorSpec.swift b/Tests/SearchFeatureTests/Coordinator/SearchCoordinatorSpec.swift
index 7bb3736b612f2659be50ca77cf72199987ead3fa..cb8056fc51c485738266260cbb0b8a6a7c08036a 100644
--- a/Tests/SearchFeatureTests/Coordinator/SearchCoordinatorSpec.swift
+++ b/Tests/SearchFeatureTests/Coordinator/SearchCoordinatorSpec.swift
@@ -1,7 +1,6 @@
 import UIKit
 import Quick
 import Nimble
-import Integration
 import TestHelpers
 
 @testable import SearchFeature
diff --git a/client-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved b/client-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 2edfffa23ebd11df1784b06aa0e734df8c56269a..00c840d9f39aca3210d93689a0b71d708bdab65c 100644
--- a/client-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/client-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -5,8 +5,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/firebase/abseil-cpp-SwiftPM.git",
       "state" : {
-        "revision" : "fffc3c2729be5747390ad02d5100291a0d9ad26a",
-        "version" : "0.20200225.4"
+        "revision" : "583de9bd60f66b40e78d08599cc92036c2e7e4e1",
+        "version" : "0.20220203.2"
       }
     },
     {
@@ -14,8 +14,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/Alamofire/Alamofire.git",
       "state" : {
-        "revision" : "f82c23a8a7ef8dc1a49a8bfc6a96883e79121864",
-        "version" : "5.5.0"
+        "revision" : "8dd85aee02e39dd280c75eef88ffdb86eed4b07b",
+        "version" : "5.6.2"
       }
     },
     {
@@ -23,8 +23,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/openid/AppAuth-iOS.git",
       "state" : {
-        "revision" : "01131d68346c8ae552961c768d583c715fbe1410",
-        "version" : "1.4.0"
+        "revision" : "33660c271c961f8ce1084cc13f2ea8195e864f7d",
+        "version" : "1.5.0"
       }
     },
     {
@@ -41,8 +41,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/firebase/boringssl-SwiftPM.git",
       "state" : {
-        "revision" : "734a8247442fde37df4364c21f6a0085b6a36728",
-        "version" : "0.7.2"
+        "revision" : "dd3eda2b05a3f459fc3073695ad1b28659066eab",
+        "version" : "0.9.1"
       }
     },
     {
@@ -68,8 +68,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/pointfreeco/combine-schedulers",
       "state" : {
-        "revision" : "4cf088c29a20f52be0f2ca54992b492c54e0076b",
-        "version" : "0.5.3"
+        "revision" : "8fee20f993e64bbbf22bc3e3f444758ac2d05692",
+        "version" : "0.7.2"
       }
     },
     {
@@ -86,8 +86,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/mattgallagher/CwlPreconditionTesting.git",
       "state" : {
-        "revision" : "fb7a26374e8570ff5c68142e5c83406d6abae0d8",
-        "version" : "2.0.2"
+        "revision" : "c21f7bab5ca8eee0a9998bbd17ca1d0eb45d4688",
+        "version" : "2.1.0"
       }
     },
     {
@@ -95,8 +95,17 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/ra1028/DifferenceKit",
       "state" : {
-        "revision" : "62745d7780deef4a023a792a1f8f763ec7bf9705",
-        "version" : "1.2.0"
+        "revision" : "073b9671ce2b9b5b96398611427a1f929927e428",
+        "version" : "1.3.0"
+      }
+    },
+    {
+      "identity" : "elixxir-dapps-sdk-swift",
+      "kind" : "remoteSourceControl",
+      "location" : "https://git.xx.network/elixxir/elixxir-dapps-sdk-swift",
+      "state" : {
+        "branch" : "development",
+        "revision" : "e5088ee5e3a3aeb6d6887d2402df829acdb4f8c2"
       }
     },
     {
@@ -113,8 +122,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/firebase/firebase-ios-sdk.git",
       "state" : {
-        "revision" : "08686f04881483d2bc098b2696e674c0ba135e47",
-        "version" : "8.10.0"
+        "revision" : "111d8d6ad1a1afd6c8e9561d26e55ab1e74fcb42",
+        "version" : "8.15.0"
       }
     },
     {
@@ -122,8 +131,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/google/google-api-objectivec-client-for-rest",
       "state" : {
-        "revision" : "22e0bb02729d60db396e8b90d8189313cd86ba53",
-        "version" : "1.6.0"
+        "revision" : "3228334d0584cb9174796fecbe628a723be70452",
+        "version" : "1.7.0"
       }
     },
     {
@@ -131,8 +140,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/google/GoogleAppMeasurement.git",
       "state" : {
-        "revision" : "9b2f6aca5b4685c45f9f5481f19bee8e7982c538",
-        "version" : "8.9.1"
+        "revision" : "ef819db8c58657a6ca367322e73f3b6322afe0a2",
+        "version" : "8.15.0"
       }
     },
     {
@@ -140,8 +149,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/google/GoogleDataTransport.git",
       "state" : {
-        "revision" : "15ccdfd25ac55b9239b82809531ff26605e7556e",
-        "version" : "9.1.2"
+        "revision" : "5056b15c5acbb90cd214fe4d6138bdf5a740e5a8",
+        "version" : "9.2.0"
       }
     },
     {
@@ -149,8 +158,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/google/GoogleSignIn-iOS",
       "state" : {
-        "revision" : "60ca2bfd218ccb194a746a79b41d9d50eb7e3af0",
-        "version" : "6.1.0"
+        "revision" : "5ce850448e89500aca5b095af7247eb46dc0ca18",
+        "version" : "6.2.3"
       }
     },
     {
@@ -158,8 +167,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/google/GoogleUtilities.git",
       "state" : {
-        "revision" : "b3bb0c5551fb3f80ca939829639ab5b093edd14f",
-        "version" : "7.7.0"
+        "revision" : "f4abe56ce62a779e64b525eb133c8fc2a84bbc1f",
+        "version" : "7.7.1"
       }
     },
     {
@@ -172,12 +181,12 @@
       }
     },
     {
-      "identity" : "grpc-swiftpm",
+      "identity" : "grpc-ios",
       "kind" : "remoteSourceControl",
-      "location" : "https://github.com/firebase/grpc-SwiftPM.git",
+      "location" : "https://github.com/grpc/grpc-ios.git",
       "state" : {
-        "revision" : "fb405dd2c7901485f7e158b24e3a0a47e4efd8b5",
-        "version" : "1.28.4"
+        "revision" : "8440b914756e0d26d4f4d054a1c1581daedfc5b6",
+        "version" : "1.44.3-grpc"
       }
     },
     {
@@ -185,8 +194,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/google/gtm-session-fetcher.git",
       "state" : {
-        "revision" : "bc6a19702ac76ac4e488b68148710eb815f9bc56",
-        "version" : "1.7.0"
+        "revision" : "4e9bbf2808b8fee444e84a48f5f3c12641987d3e",
+        "version" : "1.7.2"
       }
     },
     {
@@ -194,8 +203,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/google/GTMAppAuth.git",
       "state" : {
-        "revision" : "40f4103fb52109032c05599a0c39ad43edbdf80a",
-        "version" : "1.2.2"
+        "revision" : "b9d1683be336ba8c8d1c6867bafeb056a5399700",
+        "version" : "1.3.0"
       }
     },
     {
@@ -248,8 +257,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/google/promises.git",
       "state" : {
-        "revision" : "611337c330350c9c1823ad6d671e7f936af5ee13",
-        "version" : "2.0.0"
+        "revision" : "3e4e743631e86c8c70dbc6efdc7beaa6e90fd3bb",
+        "version" : "2.1.1"
       }
     },
     {
@@ -275,8 +284,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/darrarski/ScrollViewController",
       "state" : {
-        "revision" : "9a52bb056504bb4766ddb5ac518097dd48736303",
-        "version" : "1.2.0"
+        "revision" : "288999c7b9b0246aee0cfe3b7a066546038fd4b8",
+        "version" : "1.3.0"
       }
     },
     {
@@ -292,8 +301,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/SnapKit/SnapKit",
       "state" : {
-        "revision" : "d458564516e5676af9c70b4f4b2a9178294f1bc6",
-        "version" : "5.0.1"
+        "revision" : "f222cbdf325885926566172f6f5f06af95473158",
+        "version" : "5.6.0"
       }
     },
     {
@@ -301,8 +310,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/pointfreeco/swift-case-paths",
       "state" : {
-        "revision" : "241301b67d8551c26d8f09bd2c0e52cc49f18007",
-        "version" : "0.8.0"
+        "revision" : "a09839348486db8866f85a727b8550be1d671c50",
+        "version" : "0.9.1"
       }
     },
     {
@@ -319,8 +328,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/pointfreeco/swift-composable-architecture.git",
       "state" : {
-        "revision" : "313dd217dcd1d0478118ec5d15225fd473c1564a",
-        "version" : "0.32.0"
+        "revision" : "108e3a536fcebb16c4f247ef92c2d7326baf9fe3",
+        "version" : "0.39.0"
       }
     },
     {
@@ -337,8 +346,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/pointfreeco/swift-identified-collections",
       "state" : {
-        "revision" : "680bf440178a78a627b1c2c64c0855f6523ad5b9",
-        "version" : "0.3.2"
+        "revision" : "2d6b7ffcc67afd9077fac5e5a29bcd6d39b71076",
+        "version" : "0.4.0"
       }
     },
     {
@@ -346,8 +355,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/apple/swift-protobuf",
       "state" : {
-        "revision" : "7e2c5f3cbbeea68e004915e3a8961e20bd11d824",
-        "version" : "1.18.0"
+        "revision" : "fa0fcd43f272a260e7f734f23e6dc55e16fcae0a",
+        "version" : "1.19.1"
       }
     },
     {
@@ -364,8 +373,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/SwiftyBeaver/SwiftyBeaver.git",
       "state" : {
-        "revision" : "2c039501d6eeb4d4cd4aec4a8d884ad28862e044",
-        "version" : "1.9.5"
+        "revision" : "12b5acf96d98f91d50de447369bd18df74600f1a",
+        "version" : "1.9.6"
       }
     },
     {
@@ -373,8 +382,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/dropbox/SwiftyDropbox.git",
       "state" : {
-        "revision" : "7af87d903be1cf0af0e76e0394d992943055894e",
-        "version" : "8.2.1"
+        "revision" : "9df3d4997127f1f17ed295e5f373ab676419df08",
+        "version" : "8.3.0"
       }
     },
     {
@@ -382,8 +391,8 @@
       "kind" : "remoteSourceControl",
       "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay",
       "state" : {
-        "revision" : "ef8e14e7ce1c0c304c644c6ba365d06c468ded6b",
-        "version" : "0.3.3"
+        "revision" : "38bc9242e4388b80bd23ddfdf3071428859e3260",
+        "version" : "0.4.0"
       }
     }
   ],