From 331462fc9aefbaeb9d80589d0c47c85999c9b233 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Sat, 20 Aug 2022 13:00:57 +0100
Subject: [PATCH 01/27] Add XXMessengerClient library

---
 .../xcschemes/XXMessengerClient.xcscheme      | 78 +++++++++++++++++++
 .../elixxir-dapps-sdk-swift.xcscheme          | 24 ++++++
 Package.swift                                 | 17 ++++
 README.md                                     |  5 +-
 Sources/XXMessengerClient/Unimplemented.swift |  1 +
 .../XXMessengerClientTests.swift              |  8 ++
 6 files changed, 131 insertions(+), 2 deletions(-)
 create mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/XXMessengerClient.xcscheme
 create mode 100644 Sources/XXMessengerClient/Unimplemented.swift
 create mode 100644 Tests/XXMessengerClientTests/XXMessengerClientTests.swift

diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/XXMessengerClient.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/XXMessengerClient.xcscheme
new file mode 100644
index 00000000..665c4644
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/XXMessengerClient.xcscheme
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1340"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "XXMessengerClient"
+               BuildableName = "XXMessengerClient"
+               BlueprintName = "XXMessengerClient"
+               ReferencedContainer = "container:">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      codeCoverageEnabled = "YES">
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "XXMessengerClientTests"
+               BuildableName = "XXMessengerClientTests"
+               BlueprintName = "XXMessengerClientTests"
+               ReferencedContainer = "container:">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "XXMessengerClient"
+            BuildableName = "XXMessengerClient"
+            BlueprintName = "XXMessengerClient"
+            ReferencedContainer = "container:">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/elixxir-dapps-sdk-swift.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/elixxir-dapps-sdk-swift.xcscheme
index c0fcfabe..223297f5 100644
--- a/.swiftpm/xcode/xcshareddata/xcschemes/elixxir-dapps-sdk-swift.xcscheme
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/elixxir-dapps-sdk-swift.xcscheme
@@ -20,6 +20,20 @@
                ReferencedContainer = "container:">
             </BuildableReference>
          </BuildActionEntry>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "XXMessengerClient"
+               BuildableName = "XXMessengerClient"
+               BlueprintName = "XXMessengerClient"
+               ReferencedContainer = "container:">
+            </BuildableReference>
+         </BuildActionEntry>
       </BuildActionEntries>
    </BuildAction>
    <TestAction
@@ -39,6 +53,16 @@
                ReferencedContainer = "container:">
             </BuildableReference>
          </TestableReference>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "XXMessengerClientTests"
+               BuildableName = "XXMessengerClientTests"
+               BlueprintName = "XXMessengerClientTests"
+               ReferencedContainer = "container:">
+            </BuildableReference>
+         </TestableReference>
       </Testables>
    </TestAction>
    <LaunchAction
diff --git a/Package.swift b/Package.swift
index dc48fcd5..4f06554e 100644
--- a/Package.swift
+++ b/Package.swift
@@ -20,6 +20,7 @@ let package = Package(
   ],
   products: [
     .library(name: "XXClient", targets: ["XXClient"]),
+    .library(name: "XXMessengerClient", targets: ["XXMessengerClient"]),
   ],
   dependencies: [
     .package(
@@ -48,6 +49,22 @@ let package = Package(
       ],
       swiftSettings: swiftSettings
     ),
+    .target(
+      name: "XXMessengerClient",
+      dependencies: [
+        .target(name: "XXClient"),
+        .product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"),
+      ],
+      swiftSettings: swiftSettings
+    ),
+    .testTarget(
+      name: "XXMessengerClientTests",
+      dependencies: [
+        .target(name: "XXMessengerClient"),
+        .product(name: "CustomDump", package: "swift-custom-dump"),
+      ],
+      swiftSettings: swiftSettings
+    ),
     .binaryTarget(
       name: "Bindings",
       path: "Frameworks/Bindings.xcframework"
diff --git a/README.md b/README.md
index 5c0f3d59..738012cd 100644
--- a/README.md
+++ b/README.md
@@ -139,7 +139,8 @@ Open `ElixxirDAppsSDK.xcworkspace` in Xcode (≥13.4).
 ```
 ElixxirDAppsSDK [Xcode Workspace]
  ├─ elixxir-dapps-sdk-swift [Swift Package]
- |   └─ XXClient [Library]
+ |   ├─ XXClient [Library]
+ |   └─ XXMessengerClient [Library]
  └─ Example [Xcode Project]
      ├─ ExampleApp (iOS) [iOS App Target]
      ├─ example-app [Swift Package]
@@ -157,7 +158,7 @@ ElixxirDAppsSDK [Xcode Workspace]
 - Use `example-app` scheme to build and test the example app package with all contained libraries.
 - Use `ExampleAppIcon` scheme with macOS target to build and preview the example app icon.
 - Use `example-app-icon-export` scheme with macOS target to build and update the example app icon.
-- Use other schemes, like `AppFeature`, for building and testing individual libraries in isolation.
+- Use other schemes, like `XXClient`, for building and testing individual libraries in isolation.
 
 ## 📄 License
 
diff --git a/Sources/XXMessengerClient/Unimplemented.swift b/Sources/XXMessengerClient/Unimplemented.swift
new file mode 100644
index 00000000..9454b9d7
--- /dev/null
+++ b/Sources/XXMessengerClient/Unimplemented.swift
@@ -0,0 +1 @@
+private enum Unimplemented {}
diff --git a/Tests/XXMessengerClientTests/XXMessengerClientTests.swift b/Tests/XXMessengerClientTests/XXMessengerClientTests.swift
new file mode 100644
index 00000000..11caac7a
--- /dev/null
+++ b/Tests/XXMessengerClientTests/XXMessengerClientTests.swift
@@ -0,0 +1,8 @@
+import XCTest
+@testable import XXMessengerClient
+
+final class XXMessengerClientTests: XCTestCase {
+  func testExample() {
+    XCTAssert(true)
+  }
+}
-- 
GitLab


From 9077cdefdc4d073493b70a4468da7d4aaf660d1c Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Sat, 20 Aug 2022 13:01:02 +0100
Subject: [PATCH 02/27] Fix typo

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 738012cd..5a2eadd5 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
 
 ## 📱 Demo
 
-Refer to this [demo](https://git.xx.network/elixxir/shielded-help-demo/elixxir-dapp-demo) to see an example of how to build an app with the SDK to send `E2E` messages and send `RestLike` messsage.
+Refer to this [demo](https://git.xx.network/elixxir/shielded-help-demo/elixxir-dapp-demo) to see an example of how to build an app with the SDK to send `E2E` messages and send `RestLike` message.
 
 Also you can checkout included example iOS application.
 
-- 
GitLab


From cd98797a2992e2539282ddd8ab84329ab6a5ce1c Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Sat, 20 Aug 2022 18:46:31 +0100
Subject: [PATCH 03/27] Rename Environment to NDFEnvironment

---
 Sources/XXClient/CMixManager/CMixManager.swift      |  6 +++---
 .../CMixManager/Functors/CMixManagerCreate.swift    |  4 ++--
 .../CMixManager/Functors/CMixManagerRestore.swift   |  4 ++--
 .../Functors/DownloadAndVerifySignedNdf.swift       |  4 ++--
 .../{Environment.swift => NDFEnvironment.swift}     | 13 ++++++++++---
 5 files changed, 19 insertions(+), 12 deletions(-)
 rename Sources/XXClient/Models/{Environment.swift => NDFEnvironment.swift} (90%)

diff --git a/Sources/XXClient/CMixManager/CMixManager.swift b/Sources/XXClient/CMixManager/CMixManager.swift
index 1e1b38e5..a0df95ff 100644
--- a/Sources/XXClient/CMixManager/CMixManager.swift
+++ b/Sources/XXClient/CMixManager/CMixManager.swift
@@ -16,7 +16,7 @@ extension CMixManager {
       .appendingPathComponent("xx.network.client")
       .path,
     fileManager: FileManager = .default,
-    environment: Environment = .mainnet,
+    ndfEnvironment: NDFEnvironment = .mainnet,
     downloadNDF: DownloadAndVerifySignedNdf = .live,
     generateSecret: GenerateSecret = .live,
     passwordStorage: PasswordStorage,
@@ -31,7 +31,7 @@ extension CMixManager {
         fileManager: fileManager
       ),
       create: .live(
-        environment: environment,
+        ndfEnvironment: ndfEnvironment,
         downloadNDF: downloadNDF,
         generateSecret: generateSecret,
         passwordStorage: passwordStorage,
@@ -42,7 +42,7 @@ extension CMixManager {
         loadCMix: loadCMix
       ),
       restore: .live(
-        environment: environment,
+        ndfEnvironment: ndfEnvironment,
         downloadNDF: downloadNDF,
         generateSecret: generateSecret,
         passwordStorage: passwordStorage,
diff --git a/Sources/XXClient/CMixManager/Functors/CMixManagerCreate.swift b/Sources/XXClient/CMixManager/Functors/CMixManagerCreate.swift
index a0d543f8..0dc49467 100644
--- a/Sources/XXClient/CMixManager/Functors/CMixManagerCreate.swift
+++ b/Sources/XXClient/CMixManager/Functors/CMixManagerCreate.swift
@@ -11,7 +11,7 @@ public struct CMixManagerCreate {
 
 extension CMixManagerCreate {
   public static func live(
-    environment: Environment,
+    ndfEnvironment: NDFEnvironment,
     downloadNDF: DownloadAndVerifySignedNdf,
     generateSecret: GenerateSecret,
     passwordStorage: PasswordStorage,
@@ -22,7 +22,7 @@ extension CMixManagerCreate {
     loadCMix: LoadCMix
   ) -> CMixManagerCreate {
     CMixManagerCreate {
-      let ndfData = try downloadNDF(environment)
+      let ndfData = try downloadNDF(ndfEnvironment)
       let password = generateSecret()
       try passwordStorage.save(password)
       try? fileManager.removeItem(atPath: directoryPath)
diff --git a/Sources/XXClient/CMixManager/Functors/CMixManagerRestore.swift b/Sources/XXClient/CMixManager/Functors/CMixManagerRestore.swift
index 466684b8..de8b6e1a 100644
--- a/Sources/XXClient/CMixManager/Functors/CMixManagerRestore.swift
+++ b/Sources/XXClient/CMixManager/Functors/CMixManagerRestore.swift
@@ -14,7 +14,7 @@ public struct CMixManagerRestore {
 
 extension CMixManagerRestore {
   public static func live(
-    environment: Environment,
+    ndfEnvironment: NDFEnvironment,
     downloadNDF: DownloadAndVerifySignedNdf,
     generateSecret: GenerateSecret,
     passwordStorage: PasswordStorage,
@@ -23,7 +23,7 @@ extension CMixManagerRestore {
     newCMixFromBackup: NewCMixFromBackup
   ) -> CMixManagerRestore {
     CMixManagerRestore { backup, passphrase in
-      let ndfData = try downloadNDF(environment)
+      let ndfData = try downloadNDF(ndfEnvironment)
       let password = generateSecret()
       try passwordStorage.save(password)
       try? fileManager.removeItem(atPath: directoryPath)
diff --git a/Sources/XXClient/Functors/DownloadAndVerifySignedNdf.swift b/Sources/XXClient/Functors/DownloadAndVerifySignedNdf.swift
index 2c6ba075..c5395780 100644
--- a/Sources/XXClient/Functors/DownloadAndVerifySignedNdf.swift
+++ b/Sources/XXClient/Functors/DownloadAndVerifySignedNdf.swift
@@ -2,9 +2,9 @@ import Bindings
 import XCTestDynamicOverlay
 
 public struct DownloadAndVerifySignedNdf {
-  public var run: (Environment) throws -> Data
+  public var run: (NDFEnvironment) throws -> Data
 
-  public func callAsFunction(_ env: Environment) throws -> Data {
+  public func callAsFunction(_ env: NDFEnvironment) throws -> Data {
     try run(env)
   }
 }
diff --git a/Sources/XXClient/Models/Environment.swift b/Sources/XXClient/Models/NDFEnvironment.swift
similarity index 90%
rename from Sources/XXClient/Models/Environment.swift
rename to Sources/XXClient/Models/NDFEnvironment.swift
index 92df7275..701a144c 100644
--- a/Sources/XXClient/Models/Environment.swift
+++ b/Sources/XXClient/Models/NDFEnvironment.swift
@@ -1,6 +1,6 @@
 import Foundation
 
-public struct Environment: Equatable {
+public struct NDFEnvironment: Equatable {
   public init(url: URL, cert: String) {
     self.url = url
     self.cert = cert
@@ -10,8 +10,8 @@ public struct Environment: Equatable {
   public var cert: String
 }
 
-extension Environment {
-  public static let mainnet = Environment(
+extension NDFEnvironment {
+  public static let mainnet = NDFEnvironment(
     url: URL(string: "https://elixxir-bins.s3.us-west-1.amazonaws.com/ndf/mainnet.json")!,
     cert: """
       -----BEGIN CERTIFICATE-----
@@ -50,3 +50,10 @@ extension Environment {
       """
   )
 }
+
+extension NDFEnvironment {
+  public static let unimplemented = NDFEnvironment(
+    url: URL(fileURLWithPath: "unimplemented"),
+    cert: "unimplemented"
+  )
+}
-- 
GitLab


From 8f8fa1171d6ea35ec1cbc40663899601030899cd Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Sat, 20 Aug 2022 18:47:11 +0100
Subject: [PATCH 04/27] Update example all build scheme

Add tests
---
 .../xcschemes/ExampleApp (iOS).xcscheme       | 43 ++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/Example/Example.xcodeproj/xcshareddata/xcschemes/ExampleApp (iOS).xcscheme b/Example/Example.xcodeproj/xcshareddata/xcschemes/ExampleApp (iOS).xcscheme
index 57df4eaa..6ae359a9 100644
--- a/Example/Example.xcodeproj/xcshareddata/xcschemes/ExampleApp (iOS).xcscheme	
+++ b/Example/Example.xcodeproj/xcshareddata/xcschemes/ExampleApp (iOS).xcscheme	
@@ -26,8 +26,49 @@
       buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
-      shouldUseLaunchSchemeArgsEnv = "YES">
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      codeCoverageEnabled = "YES">
       <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "AppFeatureTests"
+               BuildableName = "AppFeatureTests"
+               BlueprintName = "AppFeatureTests"
+               ReferencedContainer = "container:example-app">
+            </BuildableReference>
+         </TestableReference>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "ErrorFeatureTests"
+               BuildableName = "ErrorFeatureTests"
+               BlueprintName = "ErrorFeatureTests"
+               ReferencedContainer = "container:example-app">
+            </BuildableReference>
+         </TestableReference>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "LandingFeatureTests"
+               BuildableName = "LandingFeatureTests"
+               BlueprintName = "LandingFeatureTests"
+               ReferencedContainer = "container:example-app">
+            </BuildableReference>
+         </TestableReference>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "SessionFeatureTests"
+               BuildableName = "SessionFeatureTests"
+               BlueprintName = "SessionFeatureTests"
+               ReferencedContainer = "container:example-app">
+            </BuildableReference>
+         </TestableReference>
       </Testables>
    </TestAction>
    <LaunchAction
-- 
GitLab


From bf7562001795a5d8525c9d37823dfadc9ce3698b Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 12:27:21 +0100
Subject: [PATCH 05/27] Update NewOrLoadUd functor params

---
 Sources/XXClient/Functors/NewOrLoadUd.swift | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/Sources/XXClient/Functors/NewOrLoadUd.swift b/Sources/XXClient/Functors/NewOrLoadUd.swift
index 3b159975..cdb7f011 100644
--- a/Sources/XXClient/Functors/NewOrLoadUd.swift
+++ b/Sources/XXClient/Functors/NewOrLoadUd.swift
@@ -2,10 +2,9 @@ import Bindings
 import XCTestDynamicOverlay
 
 public struct NewOrLoadUd {
-  public struct Params {
+  public struct Params: Equatable {
     public init(
       e2eId: Int,
-      follower: UdNetworkStatus,
       username: String?,
       registrationValidationSignature: Data?,
       cert: Data,
@@ -13,7 +12,6 @@ public struct NewOrLoadUd {
       address: String
     ) {
       self.e2eId = e2eId
-      self.follower = follower
       self.username = username
       self.registrationValidationSignature = registrationValidationSignature
       self.cert = cert
@@ -22,7 +20,6 @@ public struct NewOrLoadUd {
     }
 
     public var e2eId: Int
-    public var follower: UdNetworkStatus
     public var username: String?
     public var registrationValidationSignature: Data?
     public var cert: Data
@@ -30,19 +27,22 @@ public struct NewOrLoadUd {
     public var address: String
   }
 
-  public var run: (Params) throws -> UserDiscovery
+  public var run: (Params, UdNetworkStatus) throws -> UserDiscovery
 
-  public func callAsFunction(_ params: Params) throws -> UserDiscovery {
-    try run(params)
+  public func callAsFunction(
+    params: Params,
+    follower: UdNetworkStatus
+  ) throws -> UserDiscovery {
+    try run(params, follower)
   }
 }
 
 extension NewOrLoadUd {
-  public static let live = NewOrLoadUd { params in
+  public static let live = NewOrLoadUd { params, follower in
     var error: NSError?
     let bindingsUD = BindingsNewOrLoadUd(
       params.e2eId,
-      params.follower.makeBindingsUdNetworkStatus(),
+      follower.makeBindingsUdNetworkStatus(),
       params.username,
       params.registrationValidationSignature,
       params.cert,
-- 
GitLab


From d826d7a04eb2ceff988a4b7d7517ef5bfe3a89cd Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 12:34:14 +0100
Subject: [PATCH 06/27] Implement messenger client

---
 Package.swift                                 |   5 +
 .../Messenger/Functors/MessengerConnect.swift |  35 ++++
 .../Messenger/Functors/MessengerCreate.swift  |  35 ++++
 .../Functors/MessengerIsConnected.swift       |  25 +++
 .../Functors/MessengerIsCreated.swift         |  24 +++
 .../Functors/MessengerIsLoaded.swift          |  24 +++
 .../Functors/MessengerIsLoggedIn.swift        |  24 +++
 .../Functors/MessengerIsRegistered.swift      |  31 +++
 .../Messenger/Functors/MessengerLoad.swift    |  28 +++
 .../Messenger/Functors/MessengerLogIn.swift   |  50 +++++
 .../Functors/MessengerRegister.swift          |  52 +++++
 .../Messenger/Messenger.swift                 |  46 +++++
 .../Messenger/MessengerContext.swift          |  17 ++
 .../Messenger/MessengerEnvironment.swift      |  73 +++++++
 Sources/XXMessengerClient/Unimplemented.swift |   1 -
 .../Utils/MessengerFileManager.swift          |  40 ++++
 .../Utils/PasswordStorage+Keychain.swift      |  21 ++
 .../Functors/MessengerConnectTests.swift      | 107 ++++++++++
 .../Functors/MessengerCreateTests.swift       | 159 +++++++++++++++
 .../Functors/MessengerIsConnectedTests.swift  |  20 ++
 .../Functors/MessengerIsCreatedTests.swift    |  37 ++++
 .../Functors/MessengerIsLoadedTests.swift     |  20 ++
 .../Functors/MessengerIsLoggedInTests.swift   |  20 ++
 .../Functors/MessengerIsRegisteredTests.swift |  58 ++++++
 .../Functors/MessengerLoadTests.swift         |  77 +++++++
 .../Functors/MessengerLogInTests.swift        | 171 ++++++++++++++++
 .../Functors/MessengerRegisterTests.swift     | 188 ++++++++++++++++++
 .../XXMessengerClientTests.swift              |   8 -
 28 files changed, 1387 insertions(+), 9 deletions(-)
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Messenger.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/MessengerContext.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
 delete mode 100644 Sources/XXMessengerClient/Unimplemented.swift
 create mode 100644 Sources/XXMessengerClient/Utils/MessengerFileManager.swift
 create mode 100644 Sources/XXMessengerClient/Utils/PasswordStorage+Keychain.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
 delete mode 100644 Tests/XXMessengerClientTests/XXMessengerClientTests.swift

diff --git a/Package.swift b/Package.swift
index 4f06554e..0024dab5 100644
--- a/Package.swift
+++ b/Package.swift
@@ -31,6 +31,10 @@ let package = Package(
       url: "https://github.com/pointfreeco/xctest-dynamic-overlay.git",
       .upToNextMajor(from: "0.4.0")
     ),
+    .package(
+      url: "https://github.com/kishikawakatsumi/KeychainAccess.git",
+      .upToNextMajor(from: "4.2.2")
+    ),
   ],
   targets: [
     .target(
@@ -53,6 +57,7 @@ let package = Package(
       name: "XXMessengerClient",
       dependencies: [
         .target(name: "XXClient"),
+        .product(name: "KeychainAccess", package: "KeychainAccess"),
         .product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"),
       ],
       swiftSettings: swiftSettings
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
new file mode 100644
index 00000000..fa24b8eb
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
@@ -0,0 +1,35 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerConnect {
+  public enum Error: Swift.Error, Equatable {
+    case notLoaded
+  }
+
+  public var run: () throws -> Void
+
+  public func callAsFunction() throws {
+    try run()
+  }
+}
+
+extension MessengerConnect {
+  public static func live(_ env: MessengerEnvironment) -> MessengerConnect {
+    MessengerConnect {
+      guard let cMix = env.ctx.cMix else {
+        throw Error.notLoaded
+      }
+      env.ctx.e2e = try env.login(
+        cMixId: cMix.getId(),
+        identity: try cMix.makeLegacyReceptionIdentity(),
+        e2eParamsJSON: env.getE2EParams()
+      )
+    }
+  }
+}
+
+extension MessengerConnect {
+  public static let unimplemented = MessengerConnect(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift
new file mode 100644
index 00000000..a3514141
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift
@@ -0,0 +1,35 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerCreate {
+  public var run: () throws -> Void
+
+  public func callAsFunction() throws {
+    try run()
+  }
+}
+
+extension MessengerCreate {
+  public static func live(_ env: MessengerEnvironment) -> MessengerCreate {
+    MessengerCreate {
+      let ndfData = try env.downloadNDF(env.ndfEnvironment)
+      let password = env.generateSecret()
+      try env.passwordStorage.save(password)
+      let storageDir = env.storageDir()
+      try env.fileManager.removeDirectory(storageDir)
+      try env.fileManager.createDirectory(storageDir)
+      try env.newCMix(
+        ndfJSON: String(data: ndfData, encoding: .utf8)!,
+        storageDir: storageDir,
+        password: password,
+        registrationCode: nil
+      )
+    }
+  }
+}
+
+extension MessengerCreate {
+  public static let unimplemented = MessengerCreate(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
new file mode 100644
index 00000000..6a790dd5
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
@@ -0,0 +1,25 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerIsConnected {
+  public var run: () -> Bool
+
+  public func callAsFunction() -> Bool {
+    run()
+  }
+}
+
+extension MessengerIsConnected {
+  public static func live(_ env: MessengerEnvironment) -> MessengerIsConnected {
+    MessengerIsConnected {
+      env.ctx.e2e != nil
+    }
+  }
+}
+
+extension MessengerIsConnected {
+  public static let unimplemented = MessengerIsConnected(
+    run: XCTUnimplemented()
+  )
+}
+
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift
new file mode 100644
index 00000000..cf7f5a4f
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift
@@ -0,0 +1,24 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerIsCreated {
+  public var run: () -> Bool
+
+  public func callAsFunction() -> Bool {
+    run()
+  }
+}
+
+extension MessengerIsCreated {
+  public static func live(_ env: MessengerEnvironment) -> MessengerIsCreated {
+    MessengerIsCreated {
+      env.fileManager.isDirectoryEmpty(env.storageDir()) == false
+    }
+  }
+}
+
+extension MessengerIsCreated {
+  public static let unimplemented = MessengerIsCreated(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
new file mode 100644
index 00000000..88750885
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
@@ -0,0 +1,24 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerIsLoaded {
+  public var run: () -> Bool
+
+  public func callAsFunction() -> Bool {
+    run()
+  }
+}
+
+extension MessengerIsLoaded {
+  public static func live(_ env: MessengerEnvironment) -> MessengerIsLoaded {
+    MessengerIsLoaded {
+      env.ctx.cMix != nil
+    }
+  }
+}
+
+extension MessengerIsLoaded {
+  public static let unimplemented = MessengerIsLoaded(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
new file mode 100644
index 00000000..7f886bef
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
@@ -0,0 +1,24 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerIsLoggedIn {
+  public var run: () -> Bool
+
+  public func callAsFunction() -> Bool {
+    run()
+  }
+}
+
+extension MessengerIsLoggedIn {
+  public static func live(_ env: MessengerEnvironment) -> MessengerIsLoggedIn {
+    MessengerIsLoggedIn {
+      env.ctx.ud != nil
+    }
+  }
+}
+
+extension MessengerIsLoggedIn {
+  public static let unimplemented = MessengerIsLoggedIn(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
new file mode 100644
index 00000000..c91db5ac
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
@@ -0,0 +1,31 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerIsRegistered {
+  public enum Error: Swift.Error, Equatable {
+    case notConnected
+  }
+
+  public var run: () throws -> Bool
+
+  public func callAsFunction() throws -> Bool {
+    try run()
+  }
+}
+
+extension MessengerIsRegistered {
+  public static func live(_ env: MessengerEnvironment) -> MessengerIsRegistered {
+    MessengerIsRegistered {
+      guard let e2e = env.ctx.e2e else {
+        throw Error.notConnected
+      }
+      return try env.isRegisteredWithUD(e2eId: e2e.getId())
+    }
+  }
+}
+
+extension MessengerIsRegistered {
+  public static let unimplemented = MessengerIsRegistered(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
new file mode 100644
index 00000000..9b0454a4
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
@@ -0,0 +1,28 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerLoad {
+  public var run: () throws -> Void
+
+  public func callAsFunction() throws {
+    try run()
+  }
+}
+
+extension MessengerLoad {
+  public static func live(_ env: MessengerEnvironment) -> MessengerLoad {
+    MessengerLoad {
+      env.ctx.cMix = try env.loadCMix(
+        storageDir: env.storageDir(),
+        password: try env.passwordStorage.load(),
+        cMixParamsJSON: env.getCMixParams()
+      )
+    }
+  }
+}
+
+extension MessengerLoad {
+  public static let unimplemented = MessengerLoad(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
new file mode 100644
index 00000000..4b43a56b
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
@@ -0,0 +1,50 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerLogIn {
+  public enum Error: Swift.Error, Equatable {
+    case notLoaded
+    case notConnected
+  }
+
+  public var run: () throws -> Void
+
+  public func callAsFunction() throws {
+    try run()
+  }
+}
+
+extension MessengerLogIn {
+  public static func live(_ env: MessengerEnvironment) -> MessengerLogIn {
+    MessengerLogIn {
+      guard let cMix = env.ctx.cMix else {
+        throw Error.notLoaded
+      }
+      guard let e2e = env.ctx.e2e else {
+        throw Error.notConnected
+      }
+      if cMix.networkFollowerStatus() != .running {
+        try cMix.startNetworkFollower(timeoutMS: 30_000)
+      }
+      env.ctx.ud = try env.newOrLoadUd(
+        params: .init(
+          e2eId: e2e.getId(),
+          username: nil,
+          registrationValidationSignature: nil,
+          cert: env.udCert() ?? e2e.getUdCertFromNdf(),
+          contactFile: env.udContact() ?? (try e2e.getUdContactFromNdf()),
+          address: env.udAddress() ?? e2e.getUdAddressFromNdf()
+        ),
+        follower: .init {
+          cMix.networkFollowerStatus().rawValue
+        }
+      )
+    }
+  }
+}
+
+extension MessengerLogIn {
+  public static let unimplemented = MessengerLogIn(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
new file mode 100644
index 00000000..1440dd43
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
@@ -0,0 +1,52 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerRegister {
+  public enum Error: Swift.Error, Equatable {
+    case notLoaded
+    case notConnected
+  }
+
+  public var run: (String) throws -> Void
+
+  public func callAsFunction(
+    username: String
+  ) throws {
+    try run(username)
+  }
+}
+
+extension MessengerRegister {
+  public static func live(_ env: MessengerEnvironment) -> MessengerRegister {
+    MessengerRegister { username in
+      guard let cMix = env.ctx.cMix else {
+        throw Error.notLoaded
+      }
+      guard let e2e = env.ctx.e2e else {
+        throw Error.notConnected
+      }
+      if cMix.networkFollowerStatus() != .running {
+        try cMix.startNetworkFollower(timeoutMS: 30_000)
+      }
+      env.ctx.ud = try env.newOrLoadUd(
+        params: .init(
+          e2eId: e2e.getId(),
+          username: username,
+          registrationValidationSignature: cMix.getReceptionRegistrationValidationSignature(),
+          cert: env.udCert() ?? e2e.getUdCertFromNdf(),
+          contactFile: env.udContact() ?? (try e2e.getUdContactFromNdf()),
+          address: env.udAddress() ?? e2e.getUdAddressFromNdf()
+        ),
+        follower: .init {
+          cMix.networkFollowerStatus().rawValue
+        }
+      )
+    }
+  }
+}
+
+extension MessengerRegister {
+  public static let unimplemented = MessengerRegister(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
new file mode 100644
index 00000000..a477f7cc
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -0,0 +1,46 @@
+import XXClient
+
+public struct Messenger {
+  public var isCreated: MessengerIsCreated
+  public var create: MessengerCreate
+  public var isLoaded: MessengerIsLoaded
+  public var load: MessengerLoad
+  public var isConnected: MessengerIsConnected
+  public var connect: MessengerConnect
+  public var isRegistered: MessengerIsRegistered
+  public var register: MessengerRegister
+  public var isLoggedIn: MessengerIsLoggedIn
+  public var logIn: MessengerLogIn
+}
+
+extension Messenger {
+  public static func live(_ env: MessengerEnvironment) -> Messenger {
+    Messenger(
+      isCreated: .live(env),
+      create: .live(env),
+      isLoaded: .live(env),
+      load: .live(env),
+      isConnected: .live(env),
+      connect: .live(env),
+      isRegistered: .live(env),
+      register: .live(env),
+      isLoggedIn: .live(env),
+      logIn: .live(env)
+    )
+  }
+}
+
+extension Messenger {
+  public static let unimplemented = Messenger(
+    isCreated: .unimplemented,
+    create: .unimplemented,
+    isLoaded: .unimplemented,
+    load: .unimplemented,
+    isConnected: .unimplemented,
+    connect: .unimplemented,
+    isRegistered: .unimplemented,
+    register: .unimplemented,
+    isLoggedIn: .unimplemented,
+    logIn: .unimplemented
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/MessengerContext.swift b/Sources/XXMessengerClient/Messenger/MessengerContext.swift
new file mode 100644
index 00000000..ba67ed2b
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/MessengerContext.swift
@@ -0,0 +1,17 @@
+import XXClient
+
+public class MessengerContext {
+  public init(
+    cMix: CMix? = nil,
+    e2e: E2E? = nil,
+    ud: UserDiscovery? = nil
+  ) {
+    self.cMix = cMix
+    self.e2e = e2e
+    self.ud = ud
+  }
+
+  public var cMix: CMix?
+  public var e2e: E2E?
+  public var ud: UserDiscovery?
+}
diff --git a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
new file mode 100644
index 00000000..dfa7dfcd
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
@@ -0,0 +1,73 @@
+import Foundation
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerEnvironment {
+  public var ctx: MessengerContext
+  public var downloadNDF: DownloadAndVerifySignedNdf
+  public var fileManager: MessengerFileManager
+  public var generateSecret: GenerateSecret
+  public var getCMixParams: GetCMixParams
+  public var getE2EParams: GetE2EParams
+  public var isRegisteredWithUD: IsRegisteredWithUD
+  public var loadCMix: LoadCMix
+  public var login: Login
+  public var ndfEnvironment: NDFEnvironment
+  public var newCMix: NewCMix
+  public var newOrLoadUd: NewOrLoadUd
+  public var passwordStorage: PasswordStorage
+  public var storageDir: () -> String
+  public var udAddress: () -> String?
+  public var udCert: () -> Data?
+  public var udContact: () -> Data?
+}
+
+extension MessengerEnvironment {
+  public static let defaultStorageDir = FileManager.default
+    .urls(for: .applicationSupportDirectory, in: .userDomainMask)
+    .first!
+    .appendingPathComponent("xx.network.client")
+    .path
+
+  public static let live = MessengerEnvironment(
+    ctx: .init(),
+    downloadNDF: .live,
+    fileManager: .live(),
+    generateSecret: .live,
+    getCMixParams: .liveDefault,
+    getE2EParams: .liveDefault,
+    isRegisteredWithUD: .live,
+    loadCMix: .live,
+    login: .live,
+    ndfEnvironment: .mainnet,
+    newCMix: .live,
+    newOrLoadUd: .live,
+    passwordStorage: .keychain,
+    storageDir: { MessengerEnvironment.defaultStorageDir },
+    udAddress: { nil },
+    udCert: { nil },
+    udContact: { nil }
+  )
+}
+
+extension MessengerEnvironment {
+  public static let unimplemented = MessengerEnvironment(
+    ctx: .init(),
+    downloadNDF: .unimplemented,
+    fileManager: .unimplemented,
+    generateSecret: .unimplemented,
+    getCMixParams: .unimplemented,
+    getE2EParams: .unimplemented,
+    isRegisteredWithUD: .unimplemented,
+    loadCMix: .unimplemented,
+    login: .unimplemented,
+    ndfEnvironment: .unimplemented,
+    newCMix: .unimplemented,
+    newOrLoadUd: .unimplemented,
+    passwordStorage: .unimplemented,
+    storageDir: XCTUnimplemented("\(Self.self).storageDir", placeholder: ""),
+    udAddress: XCTUnimplemented("\(Self.self).udAddress", placeholder: nil),
+    udCert: XCTUnimplemented("\(Self.self).udCert", placeholder: nil),
+    udContact: XCTUnimplemented("\(Self.self).udContact", placeholder: nil)
+  )
+}
diff --git a/Sources/XXMessengerClient/Unimplemented.swift b/Sources/XXMessengerClient/Unimplemented.swift
deleted file mode 100644
index 9454b9d7..00000000
--- a/Sources/XXMessengerClient/Unimplemented.swift
+++ /dev/null
@@ -1 +0,0 @@
-private enum Unimplemented {}
diff --git a/Sources/XXMessengerClient/Utils/MessengerFileManager.swift b/Sources/XXMessengerClient/Utils/MessengerFileManager.swift
new file mode 100644
index 00000000..4ff49c5f
--- /dev/null
+++ b/Sources/XXMessengerClient/Utils/MessengerFileManager.swift
@@ -0,0 +1,40 @@
+import Foundation
+import XCTestDynamicOverlay
+
+public struct MessengerFileManager {
+  public var isDirectoryEmpty: (String) -> Bool
+  public var removeDirectory: (String) throws -> Void
+  public var createDirectory: (String) throws -> Void
+}
+
+extension MessengerFileManager {
+  public static func live(
+    fileManager: FileManager = .default
+  ) -> MessengerFileManager {
+    MessengerFileManager(
+      isDirectoryEmpty: { path in
+        let contents = try? fileManager.contentsOfDirectory(atPath: path)
+        return contents?.isEmpty ?? true
+      },
+      removeDirectory: { path in
+        if fileManager.fileExists(atPath: path) {
+          try fileManager.removeItem(atPath: path)
+        }
+      },
+      createDirectory: { path in
+        try fileManager.createDirectory(
+          atPath: path,
+          withIntermediateDirectories: true
+        )
+      }
+    )
+  }
+}
+
+extension MessengerFileManager {
+  public static let unimplemented = MessengerFileManager(
+    isDirectoryEmpty: XCTUnimplemented("\(Self.self).isDirectoryEmpty"),
+    removeDirectory: XCTUnimplemented("\(Self.self).removeDirectory"),
+    createDirectory: XCTUnimplemented("\(Self.self).createDirectory")
+  )
+}
diff --git a/Sources/XXMessengerClient/Utils/PasswordStorage+Keychain.swift b/Sources/XXMessengerClient/Utils/PasswordStorage+Keychain.swift
new file mode 100644
index 00000000..0a062cc6
--- /dev/null
+++ b/Sources/XXMessengerClient/Utils/PasswordStorage+Keychain.swift
@@ -0,0 +1,21 @@
+import KeychainAccess
+import XXClient
+
+extension PasswordStorage {
+  public static let keychain: PasswordStorage = {
+    let keychain = KeychainAccess.Keychain(
+      service: "xx.network.client.messenger"
+    )
+    return PasswordStorage(
+      save: { password in
+        keychain[data: "password"] = password
+      },
+      load: {
+        guard let password = keychain[data: "password"] else {
+          throw MissingPasswordError()
+        }
+        return password
+      }
+    )
+  }()
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
new file mode 100644
index 00000000..c44b4907
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
@@ -0,0 +1,107 @@
+import CustomDump
+import XXClient
+import XCTest
+@testable import XXMessengerClient
+
+final class MessengerConnectTests: XCTestCase {
+  func testConnect() throws {
+    struct DidLogIn: Equatable {
+      var ephemeral: Bool
+      var cMixId: Int
+      var authCallbacksProvided: Bool
+      var identity: ReceptionIdentity
+      var e2eParamsJSON: Data
+    }
+    var didLogIn: [DidLogIn] = []
+
+    let cMixId = 1234
+    let receptionId = ReceptionIdentity.stub
+    let e2eParams = "e2e-params".data(using: .utf8)!
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.cMix!.getId.run = { cMixId }
+    env.ctx.cMix!.makeLegacyReceptionIdentity.run = { receptionId }
+    env.getE2EParams.run = { e2eParams }
+    env.login.run = { ephemeral, cMixId, authCallbacks, identity, e2eParamsJSON in
+      didLogIn.append(.init(
+        ephemeral: ephemeral,
+        cMixId: cMixId,
+        authCallbacksProvided: authCallbacks != nil,
+        identity: identity,
+        e2eParamsJSON: e2eParamsJSON
+      ))
+      return .unimplemented
+    }
+    let connect: MessengerConnect = .live(env)
+
+    try connect()
+
+    XCTAssertNoDifference(didLogIn, [
+      DidLogIn(
+        ephemeral: false,
+        cMixId: 1234,
+        authCallbacksProvided: false,
+        identity: .stub,
+        e2eParamsJSON: e2eParams
+      )
+    ])
+
+    XCTAssertNotNil(env.ctx.e2e)
+  }
+
+  func testConnectWithoutCMix() {
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = nil
+    let connect: MessengerConnect = .live(env)
+
+    XCTAssertThrowsError(try connect()) { error in
+      XCTAssertEqual(
+        error as? MessengerConnect.Error,
+        MessengerConnect.Error.notLoaded
+      )
+    }
+  }
+
+  func testMakeLegacyReceptionIdentityFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.cMix!.getId.run = { 1234 }
+    env.ctx.cMix!.makeLegacyReceptionIdentity.run = { throw error }
+    let connect: MessengerConnect = .live(env)
+
+    XCTAssertThrowsError(try connect()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+
+  func testLoginFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.cMix!.getId.run = { 1234 }
+    env.ctx.cMix!.makeLegacyReceptionIdentity.run = { .stub }
+    env.getE2EParams.run = { "e2e-params".data(using: .utf8)! }
+    env.login.run = { _, _, _, _, _ in throw error }
+    let connect: MessengerConnect = .live(env)
+
+    XCTAssertThrowsError(try connect()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+}
+
+private extension ReceptionIdentity {
+  static let stub = ReceptionIdentity(
+    id: "id".data(using: .utf8)!,
+    rsaPrivatePem: "rsaPrivatePem".data(using: .utf8)!,
+    salt: "salt".data(using: .utf8)!,
+    dhKeyPrivate: "dhKeyPrivate".data(using: .utf8)!,
+    e2eGrp: "e2eGrp".data(using: .utf8)!
+  )
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
new file mode 100644
index 00000000..5db87012
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
@@ -0,0 +1,159 @@
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+import CustomDump
+
+final class MessengerCreateTests: XCTestCase {
+  func testCreate() throws {
+    struct DidNewCMix: Equatable {
+      var ndfJSON: String
+      var storageDir: String
+      var password: Data
+      var registrationCode: String?
+    }
+
+    var didDownloadNDF: [NDFEnvironment] = []
+    var didGenerateSecret: [Int] = []
+    var didSavePassword: [Data] = []
+    var didRemoveDirectory: [String] = []
+    var didCreateDirectory: [String] = []
+    var didNewCMix: [DidNewCMix] = []
+
+    let ndf = "ndf".data(using: .utf8)!
+    let password = "password".data(using: .utf8)!
+    let storageDir = "storage-dir"
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ndfEnvironment = .unimplemented
+    env.downloadNDF.run = { ndfEnvironment in
+      didDownloadNDF.append(ndfEnvironment)
+      return ndf
+    }
+    env.generateSecret.run = { numBytes in
+      didGenerateSecret.append(numBytes)
+      return password
+    }
+    env.passwordStorage.save = { password in
+      didSavePassword.append(password)
+    }
+    env.storageDir = {
+      storageDir
+    }
+    env.fileManager.removeDirectory = { path in
+      didRemoveDirectory.append(path)
+    }
+    env.fileManager.createDirectory = { path in
+      didCreateDirectory.append(path)
+    }
+    env.newCMix.run = { ndfJSON, storageDir, password, registrationCode in
+      didNewCMix.append(.init(
+        ndfJSON: ndfJSON,
+        storageDir: storageDir,
+        password: password,
+        registrationCode: registrationCode
+      ))
+    }
+    let create: MessengerCreate = .live(env)
+
+    try create()
+
+    XCTAssertNoDifference(didDownloadNDF, [.unimplemented])
+    XCTAssertNoDifference(didGenerateSecret, [32])
+    XCTAssertNoDifference(didSavePassword, [password])
+    XCTAssertNoDifference(didRemoveDirectory, [storageDir])
+    XCTAssertNoDifference(didCreateDirectory, [storageDir])
+    XCTAssertNoDifference(didNewCMix, [.init(
+      ndfJSON: String(data: ndf, encoding: .utf8)!,
+      storageDir: storageDir,
+      password: password,
+      registrationCode: nil
+    )])
+  }
+
+  func testDownloadNDFFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ndfEnvironment = .unimplemented
+    env.downloadNDF.run = { _ in throw error }
+    let create: MessengerCreate = .live(env)
+
+    XCTAssertThrowsError(try create()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+
+  func testSavePasswordFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ndfEnvironment = .unimplemented
+    env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
+    env.generateSecret.run = { _ in "password".data(using: .utf8)! }
+    env.passwordStorage.save = { _ in throw error }
+    let create: MessengerCreate = .live(env)
+
+    XCTAssertThrowsError(try create()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+
+  func testRemoveDirectoryFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ndfEnvironment = .unimplemented
+    env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
+    env.generateSecret.run = { _ in "password".data(using: .utf8)! }
+    env.passwordStorage.save = { _ in }
+    env.storageDir = { "storage-dir" }
+    env.fileManager.removeDirectory = { _ in throw error }
+    let create: MessengerCreate = .live(env)
+
+    XCTAssertThrowsError(try create()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+
+  func testCreateDirectoryFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ndfEnvironment = .unimplemented
+    env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
+    env.generateSecret.run = { _ in "password".data(using: .utf8)! }
+    env.passwordStorage.save = { _ in }
+    env.storageDir = { "storage-dir" }
+    env.fileManager.removeDirectory = { _ in }
+    env.fileManager.createDirectory = { _ in throw error }
+    let create: MessengerCreate = .live(env)
+
+    XCTAssertThrowsError(try create()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+
+  func testNewCMixFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ndfEnvironment = .unimplemented
+    env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
+    env.generateSecret.run = { _ in "password".data(using: .utf8)! }
+    env.passwordStorage.save = { _ in }
+    env.storageDir = { "storage-dir" }
+    env.fileManager.removeDirectory = { _ in }
+    env.fileManager.createDirectory = { _ in }
+    env.newCMix.run = { _, _, _, _ in throw error }
+    let create: MessengerCreate = .live(env)
+
+    XCTAssertThrowsError(try create()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
new file mode 100644
index 00000000..e207e8a5
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
@@ -0,0 +1,20 @@
+import XCTest
+@testable import XXMessengerClient
+
+final class MessengerIsConnectedTests: XCTestCase {
+  func testWithE2E() {
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.e2e = .unimplemented
+    let isConnected: MessengerIsConnected = .live(env)
+
+    XCTAssertTrue(isConnected())
+  }
+
+  func testWithoutE2E() {
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.e2e = nil
+    let isConnected: MessengerIsConnected = .live(env)
+
+    XCTAssertFalse(isConnected())
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift
new file mode 100644
index 00000000..a96c8a60
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift
@@ -0,0 +1,37 @@
+import CustomDump
+import XCTest
+@testable import XXMessengerClient
+
+final class MessengerIsCreatedTests: XCTestCase {
+  func testStorageDirNotEmpty() {
+    var didIsDirectoryEmpty: [String] = []
+    let storageDir = "storage-dir"
+
+    var env: MessengerEnvironment = .unimplemented
+    env.storageDir = { storageDir }
+    env.fileManager.isDirectoryEmpty = { path in
+      didIsDirectoryEmpty.append(path)
+      return false
+    }
+    let isCreated: MessengerIsCreated = .live(env)
+
+    XCTAssertTrue(isCreated())
+    XCTAssertNoDifference(didIsDirectoryEmpty, [storageDir])
+  }
+
+  func testStorageDirEmpty() {
+    var didIsDirectoryEmpty: [String] = []
+    let storageDir = "storage-dir"
+
+    var env: MessengerEnvironment = .unimplemented
+    env.storageDir = { storageDir }
+    env.fileManager.isDirectoryEmpty = { path in
+      didIsDirectoryEmpty.append(path)
+      return true
+    }
+    let isCreated: MessengerIsCreated = .live(env)
+
+    XCTAssertFalse(isCreated())
+    XCTAssertNoDifference(didIsDirectoryEmpty, [storageDir])
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
new file mode 100644
index 00000000..c83dc523
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
@@ -0,0 +1,20 @@
+import XCTest
+@testable import XXMessengerClient
+
+final class MessengerIsLoadedTests: XCTestCase {
+  func testWithCMix() {
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    let isLoaded: MessengerIsLoaded = .live(env)
+
+    XCTAssertTrue(isLoaded())
+  }
+
+  func testWithoutCMix() {
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = nil
+    let isLoaded: MessengerIsLoaded = .live(env)
+
+    XCTAssertFalse(isLoaded())
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
new file mode 100644
index 00000000..6b5b7903
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
@@ -0,0 +1,20 @@
+import XCTest
+@testable import XXMessengerClient
+
+final class MessengerIsLoggedInTests: XCTestCase {
+  func testWithUD() {
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.ud = .unimplemented
+    let isLoggedIn: MessengerIsLoggedIn = .live(env)
+
+    XCTAssertTrue(isLoggedIn())
+  }
+
+  func testWithoutUD() {
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.ud = nil
+    let isLoggedIn: MessengerIsLoggedIn = .live(env)
+
+    XCTAssertFalse(isLoggedIn())
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
new file mode 100644
index 00000000..250fdad8
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
@@ -0,0 +1,58 @@
+import XCTest
+@testable import XXMessengerClient
+
+final class MessengerIsRegisteredTests: XCTestCase {
+  func testRegistered() throws {
+    var didIsRegisteredWithUD: [Int] = []
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.e2e = .unimplemented
+    env.ctx.e2e!.getId.run = { 1234 }
+    env.isRegisteredWithUD.run = { e2eId in
+      didIsRegisteredWithUD.append(e2eId)
+      return true
+    }
+    let isRegistered: MessengerIsRegistered = .live(env)
+
+    XCTAssertTrue(try isRegistered())
+    XCTAssertEqual(didIsRegisteredWithUD, [1234])
+  }
+
+  func testNotRegistered() throws {
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.e2e = .unimplemented
+    env.ctx.e2e!.getId.run = { 1234 }
+    env.isRegisteredWithUD.run = { _ in false }
+    let isRegistered: MessengerIsRegistered = .live(env)
+
+    XCTAssertFalse(try isRegistered())
+  }
+
+  func testWithoutE2E() {
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.e2e = nil
+    let isRegistered: MessengerIsRegistered = .live(env)
+
+    XCTAssertThrowsError(try isRegistered()) { err in
+      XCTAssertEqual(
+        err as? MessengerIsRegistered.Error,
+        MessengerIsRegistered.Error.notConnected
+      )
+    }
+  }
+
+  func testIsRegisteredWithUDFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.e2e = .unimplemented
+    env.ctx.e2e!.getId.run = { 1234 }
+    env.isRegisteredWithUD.run = { _ in throw error }
+    let isRegistered: MessengerIsRegistered = .live(env)
+
+    XCTAssertThrowsError(try isRegistered()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
new file mode 100644
index 00000000..ef5694c2
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
@@ -0,0 +1,77 @@
+import CustomDump
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+
+final class MessengerLoadTests: XCTestCase {
+  func testLoad() throws {
+    struct DidLoadCMix: Equatable {
+      var storageDir: String
+      var password: Data
+      var cMixParamsJSON: Data
+    }
+    var didLoadCMix: [DidLoadCMix] = []
+
+    let storageDir = "test-storage-dir"
+    let password = "password".data(using: .utf8)!
+    let cMixParams = "cmix-params".data(using: .utf8)!
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = nil
+    env.storageDir = { storageDir }
+    env.passwordStorage.load = { password }
+    env.getCMixParams.run = { cMixParams }
+    env.loadCMix.run = { storageDir, password, cMixParamsJSON in
+      didLoadCMix.append(.init(
+        storageDir: storageDir,
+        password: password,
+        cMixParamsJSON: cMixParamsJSON
+      ))
+      return .unimplemented
+    }
+    let load: MessengerLoad = .live(env)
+
+    try load()
+
+    XCTAssertNoDifference(didLoadCMix, [
+      DidLoadCMix(
+        storageDir: storageDir,
+        password: password,
+        cMixParamsJSON: cMixParams
+      )
+    ])
+    XCTAssertNotNil(env.ctx.cMix)
+  }
+
+  func testMissingPassword() {
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = nil
+    env.storageDir = { "storage-dir" }
+    env.passwordStorage.load = { throw PasswordStorage.MissingPasswordError() }
+    let load: MessengerLoad = .live(env)
+
+    XCTAssertThrowsError(try load()) { err in
+      XCTAssertEqual(
+        err as? PasswordStorage.MissingPasswordError,
+        PasswordStorage.MissingPasswordError()
+      )
+    }
+  }
+
+  func testLoadCMixFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = nil
+    env.storageDir = { "storage-dir" }
+    env.passwordStorage.load = { "password".data(using: .utf8)! }
+    env.getCMixParams.run = { "cmix-params".data(using: .utf8)! }
+    env.loadCMix.run = { _, _, _ in throw error }
+    let load: MessengerLoad = .live(env)
+
+    XCTAssertThrowsError(try load()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
new file mode 100644
index 00000000..92e511f2
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
@@ -0,0 +1,171 @@
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+import CustomDump
+
+final class MessengerLogInTests: XCTestCase {
+  func testLogin() throws {
+    var didStartNetworkFollower: [Int] = []
+    var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
+    var didNewOrLoadUDWithFollower: [UdNetworkStatus] = []
+
+    let e2eId = 1234
+    let networkFollowerStatus: NetworkFollowerStatus = .stopped
+    let udCertFromNDF = "ndf-ud-cert".data(using: .utf8)!
+    let udContactFromNDF = "ndf-ud-contact".data(using: .utf8)!
+    let udAddressFromNDF = "ndf-ud-address"
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.cMix!.networkFollowerStatus.run = { networkFollowerStatus }
+    env.ctx.cMix!.startNetworkFollower.run = { timeout in
+      didStartNetworkFollower.append(timeout)
+    }
+    env.ctx.e2e = .unimplemented
+    env.ctx.e2e!.getId.run = { e2eId }
+    env.udCert = { nil }
+    env.udContact = { nil }
+    env.udAddress = { nil }
+    env.ctx.e2e!.getUdCertFromNdf.run = { udCertFromNDF }
+    env.ctx.e2e!.getUdContactFromNdf.run = { udContactFromNDF }
+    env.ctx.e2e!.getUdAddressFromNdf.run = { udAddressFromNDF }
+    env.newOrLoadUd.run = { params, follower in
+      didNewOrLoadUDWithParams.append(params)
+      didNewOrLoadUDWithFollower.append(follower)
+      return .unimplemented
+    }
+    let logIn: MessengerLogIn = .live(env)
+    try logIn()
+
+    XCTAssertEqual(didStartNetworkFollower, [30_000])
+    XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
+      e2eId: e2eId,
+      username: nil,
+      registrationValidationSignature: nil,
+      cert: udCertFromNDF,
+      contactFile: udContactFromNDF,
+      address: udAddressFromNDF
+    )])
+    XCTAssertEqual(didNewOrLoadUDWithFollower.count, 1)
+    XCTAssertEqual(
+      didNewOrLoadUDWithFollower.first?.handle(),
+      networkFollowerStatus.rawValue
+    )
+    XCTAssertNotNil(env.ctx.ud)
+  }
+
+  func testLoginWithAlternativeUD() throws {
+    var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
+    let e2eId = 1234
+    let altUdCert = "alt-ud-cert".data(using: .utf8)!
+    let altUdContact = "alt-ud-contact".data(using: .utf8)!
+    let altUdAddress = "alt-ud-address"
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.cMix!.networkFollowerStatus.run = { .running }
+    env.ctx.e2e = .unimplemented
+    env.ctx.e2e!.getId.run = { e2eId }
+    env.udCert = { altUdCert }
+    env.udContact = { altUdContact }
+    env.udAddress = { altUdAddress }
+    env.newOrLoadUd.run = { params, _ in
+      didNewOrLoadUDWithParams.append(params)
+      return .unimplemented
+    }
+    let logIn: MessengerLogIn = .live(env)
+    try logIn()
+
+    XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
+      e2eId: e2eId,
+      username: nil,
+      registrationValidationSignature: nil,
+      cert: altUdCert,
+      contactFile: altUdContact,
+      address: altUdAddress
+    )])
+    XCTAssertNotNil(env.ctx.ud)
+  }
+
+  func testLoginWithoutCMix() {
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = nil
+    let logIn: MessengerLogIn = .live(env)
+
+    XCTAssertThrowsError(try logIn()) { error in
+      XCTAssertEqual(
+        error as? MessengerLogIn.Error,
+        MessengerLogIn.Error.notLoaded
+      )
+    }
+  }
+
+  func testLoginWithoutE2E() {
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.e2e = nil
+    let logIn: MessengerLogIn = .live(env)
+
+    XCTAssertThrowsError(try logIn()) { error in
+      XCTAssertEqual(
+        error as? MessengerLogIn.Error,
+        MessengerLogIn.Error.notConnected
+      )
+    }
+  }
+
+  func testStartNetworkFollowerFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.cMix!.networkFollowerStatus.run = { .stopped }
+    env.ctx.cMix!.startNetworkFollower.run = { _ in throw error }
+    let logIn: MessengerLogIn = .live(env)
+
+    XCTAssertThrowsError(try logIn()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+
+  func testGetUdContactFromNdfFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.cMix!.networkFollowerStatus.run = { .running }
+    env.ctx.e2e = .unimplemented
+    env.ctx.e2e!.getId.run = { 1234 }
+    env.udCert = { nil }
+    env.udContact = { nil }
+    env.ctx.e2e!.getUdCertFromNdf.run = { "ndf-ud-cert".data(using: .utf8)! }
+    env.ctx.e2e!.getUdContactFromNdf.run = { throw error }
+    let logIn: MessengerLogIn = .live(env)
+
+    XCTAssertThrowsError(try logIn()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+
+  func testNewOrLoadUdFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.cMix!.networkFollowerStatus.run = { .running }
+    env.ctx.e2e = .unimplemented
+    env.ctx.e2e!.getId.run = { 1234 }
+    env.udCert = { "ud-cert".data(using: .utf8)! }
+    env.udContact = { "ud-contact".data(using: .utf8)! }
+    env.udAddress = { "ud-address" }
+    env.newOrLoadUd.run = { _, _ in throw error }
+    let logIn: MessengerLogIn = .live(env)
+
+    XCTAssertThrowsError(try logIn()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
new file mode 100644
index 00000000..deb6a8dc
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
@@ -0,0 +1,188 @@
+import CustomDump
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+
+final class MessengerRegisterTests: XCTestCase {
+  func testRegister() throws {
+    var didStartNetworkFollower: [Int] = []
+    var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
+    var didNewOrLoadUDWithFollower: [UdNetworkStatus] = []
+
+    let e2eId = 1234
+    let networkFollowerStatus: NetworkFollowerStatus = .stopped
+    let registrationSignature = "registration-signature".data(using: .utf8)!
+    let udCertFromNDF = "ndf-ud-cert".data(using: .utf8)!
+    let udContactFromNDF = "ndf-ud-contact".data(using: .utf8)!
+    let udAddressFromNDF = "ndf-ud-address"
+    let username = "new-user-name"
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.cMix!.networkFollowerStatus.run = { networkFollowerStatus }
+    env.ctx.cMix!.startNetworkFollower.run = { timeout in
+      didStartNetworkFollower.append(timeout)
+    }
+    env.ctx.cMix!.getReceptionRegistrationValidationSignature.run = {
+      registrationSignature
+    }
+    env.ctx.e2e = .unimplemented
+    env.ctx.e2e!.getId.run = { e2eId }
+    env.udCert = { nil }
+    env.udContact = { nil }
+    env.udAddress = { nil }
+    env.ctx.e2e!.getUdCertFromNdf.run = { udCertFromNDF }
+    env.ctx.e2e!.getUdContactFromNdf.run = { udContactFromNDF }
+    env.ctx.e2e!.getUdAddressFromNdf.run = { udAddressFromNDF }
+    env.newOrLoadUd.run = { params, follower in
+      didNewOrLoadUDWithParams.append(params)
+      didNewOrLoadUDWithFollower.append(follower)
+      return .unimplemented
+    }
+    let register: MessengerRegister = .live(env)
+    try register(username: username)
+
+    XCTAssertEqual(didStartNetworkFollower, [30_000])
+    XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
+      e2eId: e2eId,
+      username: username,
+      registrationValidationSignature: registrationSignature,
+      cert: udCertFromNDF,
+      contactFile: udContactFromNDF,
+      address: udAddressFromNDF
+    )])
+    XCTAssertEqual(didNewOrLoadUDWithFollower.count, 1)
+    XCTAssertEqual(
+      didNewOrLoadUDWithFollower.first?.handle(),
+      networkFollowerStatus.rawValue
+    )
+    XCTAssertNotNil(env.ctx.ud)
+  }
+
+  func testRegisterWithAlternativeUD() throws {
+    var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
+    let e2eId = 1234
+    let registrationSignature = "registration-signature".data(using: .utf8)!
+    let altUdCert = "alt-ud-cert".data(using: .utf8)!
+    let altUdContact = "alt-ud-contact".data(using: .utf8)!
+    let altUdAddress = "alt-ud-address"
+    let username = "new-user-name"
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.cMix!.networkFollowerStatus.run = { .running }
+    env.ctx.cMix!.getReceptionRegistrationValidationSignature.run = {
+      registrationSignature
+    }
+    env.ctx.e2e = .unimplemented
+    env.ctx.e2e!.getId.run = { e2eId }
+    env.udCert = { altUdCert }
+    env.udContact = { altUdContact }
+    env.udAddress = { altUdAddress }
+    env.newOrLoadUd.run = { params, _ in
+      didNewOrLoadUDWithParams.append(params)
+      return .unimplemented
+    }
+    let register: MessengerRegister = .live(env)
+    try register(username: username)
+
+    XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
+      e2eId: e2eId,
+      username: username,
+      registrationValidationSignature: registrationSignature,
+      cert: altUdCert,
+      contactFile: altUdContact,
+      address: altUdAddress
+    )])
+    XCTAssertNotNil(env.ctx.ud)
+  }
+
+  func testRegisterWithoutCMix() {
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = nil
+    let register: MessengerRegister = .live(env)
+
+    XCTAssertThrowsError(try register(username: "new-user-name")) { error in
+      XCTAssertEqual(
+        error as? MessengerRegister.Error,
+        MessengerRegister.Error.notLoaded
+      )
+    }
+  }
+
+  func testRegisterWithoutE2E() {
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.e2e = nil
+    let register: MessengerRegister = .live(env)
+
+    XCTAssertThrowsError(try register(username: "new-user-name")) { error in
+      XCTAssertEqual(
+        error as? MessengerRegister.Error,
+        MessengerRegister.Error.notConnected
+      )
+    }
+  }
+
+  func testStartNetworkFollowerFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    let env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.cMix!.networkFollowerStatus.run = { .stopped }
+    env.ctx.cMix!.startNetworkFollower.run = { _ in throw error }
+    env.ctx.e2e = .unimplemented
+    let register: MessengerRegister = .live(env)
+
+    XCTAssertThrowsError(try register(username: "new-user-name")) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+
+  func testGetUdContactFromNdfFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.cMix!.networkFollowerStatus.run = { .running }
+    env.ctx.cMix!.getReceptionRegistrationValidationSignature.run = {
+      "registration-signature".data(using: .utf8)!
+    }
+    env.ctx.e2e = .unimplemented
+    env.ctx.e2e!.getId.run = { 1234 }
+    env.udCert = { nil }
+    env.udContact = { nil }
+    env.ctx.e2e!.getUdCertFromNdf.run = { "ndf-ud-cert".data(using: .utf8)! }
+    env.ctx.e2e!.getUdContactFromNdf.run = { throw error }
+    let register: MessengerRegister = .live(env)
+
+    XCTAssertThrowsError(try register(username: "new-user-name")) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+
+  func testNewOrLoadUdFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.cMix = .unimplemented
+    env.ctx.cMix!.networkFollowerStatus.run = { .running }
+    env.ctx.cMix!.getReceptionRegistrationValidationSignature.run = {
+      "registration-signature".data(using: .utf8)!
+    }
+    env.ctx.e2e = .unimplemented
+    env.ctx.e2e!.getId.run = { 1234 }
+    env.udCert = { "ud-cert".data(using: .utf8)! }
+    env.udContact = { "ud-contact".data(using: .utf8)! }
+    env.udAddress = { "ud-address" }
+    env.newOrLoadUd.run = { _, _ in throw error }
+    let register: MessengerRegister = .live(env)
+
+    XCTAssertThrowsError(try register(username: "new-user-name")) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+}
diff --git a/Tests/XXMessengerClientTests/XXMessengerClientTests.swift b/Tests/XXMessengerClientTests/XXMessengerClientTests.swift
deleted file mode 100644
index 11caac7a..00000000
--- a/Tests/XXMessengerClientTests/XXMessengerClientTests.swift
+++ /dev/null
@@ -1,8 +0,0 @@
-import XCTest
-@testable import XXMessengerClient
-
-final class XXMessengerClientTests: XCTestCase {
-  func testExample() {
-    XCTAssert(true)
-  }
-}
-- 
GitLab


From 68af8800b5f2ee98c3a7647f39cacb830901bf43 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 12:34:44 +0100
Subject: [PATCH 07/27] Refactor MessengerEnvironment

---
 .../Messenger/Functors/MessengerCreate.swift  |  2 +-
 .../Functors/MessengerIsCreated.swift         |  2 +-
 .../Messenger/Functors/MessengerLoad.swift    |  2 +-
 .../Messenger/Functors/MessengerLogIn.swift   |  6 ++---
 .../Functors/MessengerRegister.swift          |  6 ++---
 .../Messenger/MessengerEnvironment.swift      | 24 +++++++++----------
 .../Functors/MessengerCreateTests.swift       | 10 ++++----
 .../Functors/MessengerIsCreatedTests.swift    |  4 ++--
 .../Functors/MessengerLoadTests.swift         |  6 ++---
 .../Functors/MessengerLogInTests.swift        | 22 ++++++++---------
 .../Functors/MessengerRegisterTests.swift     | 22 ++++++++---------
 11 files changed, 52 insertions(+), 54 deletions(-)

diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift
index a3514141..b36b55b4 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift
@@ -15,7 +15,7 @@ extension MessengerCreate {
       let ndfData = try env.downloadNDF(env.ndfEnvironment)
       let password = env.generateSecret()
       try env.passwordStorage.save(password)
-      let storageDir = env.storageDir()
+      let storageDir = env.storageDir
       try env.fileManager.removeDirectory(storageDir)
       try env.fileManager.createDirectory(storageDir)
       try env.newCMix(
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift
index cf7f5a4f..c848518c 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift
@@ -12,7 +12,7 @@ public struct MessengerIsCreated {
 extension MessengerIsCreated {
   public static func live(_ env: MessengerEnvironment) -> MessengerIsCreated {
     MessengerIsCreated {
-      env.fileManager.isDirectoryEmpty(env.storageDir()) == false
+      env.fileManager.isDirectoryEmpty(env.storageDir) == false
     }
   }
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
index 9b0454a4..a8a6be31 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
@@ -13,7 +13,7 @@ extension MessengerLoad {
   public static func live(_ env: MessengerEnvironment) -> MessengerLoad {
     MessengerLoad {
       env.ctx.cMix = try env.loadCMix(
-        storageDir: env.storageDir(),
+        storageDir: env.storageDir,
         password: try env.passwordStorage.load(),
         cMixParamsJSON: env.getCMixParams()
       )
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
index 4b43a56b..70df78ac 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
@@ -31,9 +31,9 @@ extension MessengerLogIn {
           e2eId: e2e.getId(),
           username: nil,
           registrationValidationSignature: nil,
-          cert: env.udCert() ?? e2e.getUdCertFromNdf(),
-          contactFile: env.udContact() ?? (try e2e.getUdContactFromNdf()),
-          address: env.udAddress() ?? e2e.getUdAddressFromNdf()
+          cert: env.udCert ?? e2e.getUdCertFromNdf(),
+          contactFile: env.udContact ?? (try e2e.getUdContactFromNdf()),
+          address: env.udAddress ?? e2e.getUdAddressFromNdf()
         ),
         follower: .init {
           cMix.networkFollowerStatus().rawValue
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
index 1440dd43..75fce252 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
@@ -33,9 +33,9 @@ extension MessengerRegister {
           e2eId: e2e.getId(),
           username: username,
           registrationValidationSignature: cMix.getReceptionRegistrationValidationSignature(),
-          cert: env.udCert() ?? e2e.getUdCertFromNdf(),
-          contactFile: env.udContact() ?? (try e2e.getUdContactFromNdf()),
-          address: env.udAddress() ?? e2e.getUdAddressFromNdf()
+          cert: env.udCert ?? e2e.getUdCertFromNdf(),
+          contactFile: env.udContact ?? (try e2e.getUdContactFromNdf()),
+          address: env.udAddress ?? e2e.getUdAddressFromNdf()
         ),
         follower: .init {
           cMix.networkFollowerStatus().rawValue
diff --git a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
index dfa7dfcd..29391b20 100644
--- a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
+++ b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
@@ -16,10 +16,10 @@ public struct MessengerEnvironment {
   public var newCMix: NewCMix
   public var newOrLoadUd: NewOrLoadUd
   public var passwordStorage: PasswordStorage
-  public var storageDir: () -> String
-  public var udAddress: () -> String?
-  public var udCert: () -> Data?
-  public var udContact: () -> Data?
+  public var storageDir: String
+  public var udAddress: String?
+  public var udCert: Data?
+  public var udContact: Data?
 }
 
 extension MessengerEnvironment {
@@ -43,10 +43,10 @@ extension MessengerEnvironment {
     newCMix: .live,
     newOrLoadUd: .live,
     passwordStorage: .keychain,
-    storageDir: { MessengerEnvironment.defaultStorageDir },
-    udAddress: { nil },
-    udCert: { nil },
-    udContact: { nil }
+    storageDir: MessengerEnvironment.defaultStorageDir,
+    udAddress: nil,
+    udCert: nil,
+    udContact: nil
   )
 }
 
@@ -65,9 +65,9 @@ extension MessengerEnvironment {
     newCMix: .unimplemented,
     newOrLoadUd: .unimplemented,
     passwordStorage: .unimplemented,
-    storageDir: XCTUnimplemented("\(Self.self).storageDir", placeholder: ""),
-    udAddress: XCTUnimplemented("\(Self.self).udAddress", placeholder: nil),
-    udCert: XCTUnimplemented("\(Self.self).udCert", placeholder: nil),
-    udContact: XCTUnimplemented("\(Self.self).udContact", placeholder: nil)
+    storageDir: "unimplemented",
+    udAddress: nil,
+    udCert: nil,
+    udContact: nil
   )
 }
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
index 5db87012..ee178d28 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
@@ -36,9 +36,7 @@ final class MessengerCreateTests: XCTestCase {
     env.passwordStorage.save = { password in
       didSavePassword.append(password)
     }
-    env.storageDir = {
-      storageDir
-    }
+    env.storageDir = storageDir
     env.fileManager.removeDirectory = { path in
       didRemoveDirectory.append(path)
     }
@@ -109,7 +107,7 @@ final class MessengerCreateTests: XCTestCase {
     env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
     env.generateSecret.run = { _ in "password".data(using: .utf8)! }
     env.passwordStorage.save = { _ in }
-    env.storageDir = { "storage-dir" }
+    env.storageDir = "storage-dir"
     env.fileManager.removeDirectory = { _ in throw error }
     let create: MessengerCreate = .live(env)
 
@@ -127,7 +125,7 @@ final class MessengerCreateTests: XCTestCase {
     env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
     env.generateSecret.run = { _ in "password".data(using: .utf8)! }
     env.passwordStorage.save = { _ in }
-    env.storageDir = { "storage-dir" }
+    env.storageDir = "storage-dir"
     env.fileManager.removeDirectory = { _ in }
     env.fileManager.createDirectory = { _ in throw error }
     let create: MessengerCreate = .live(env)
@@ -146,7 +144,7 @@ final class MessengerCreateTests: XCTestCase {
     env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
     env.generateSecret.run = { _ in "password".data(using: .utf8)! }
     env.passwordStorage.save = { _ in }
-    env.storageDir = { "storage-dir" }
+    env.storageDir = "storage-dir"
     env.fileManager.removeDirectory = { _ in }
     env.fileManager.createDirectory = { _ in }
     env.newCMix.run = { _, _, _, _ in throw error }
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift
index a96c8a60..246be9d3 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift
@@ -8,7 +8,7 @@ final class MessengerIsCreatedTests: XCTestCase {
     let storageDir = "storage-dir"
 
     var env: MessengerEnvironment = .unimplemented
-    env.storageDir = { storageDir }
+    env.storageDir = storageDir
     env.fileManager.isDirectoryEmpty = { path in
       didIsDirectoryEmpty.append(path)
       return false
@@ -24,7 +24,7 @@ final class MessengerIsCreatedTests: XCTestCase {
     let storageDir = "storage-dir"
 
     var env: MessengerEnvironment = .unimplemented
-    env.storageDir = { storageDir }
+    env.storageDir = storageDir
     env.fileManager.isDirectoryEmpty = { path in
       didIsDirectoryEmpty.append(path)
       return true
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
index ef5694c2..1d8ae5f2 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
@@ -18,7 +18,7 @@ final class MessengerLoadTests: XCTestCase {
 
     var env: MessengerEnvironment = .unimplemented
     env.ctx.cMix = nil
-    env.storageDir = { storageDir }
+    env.storageDir = storageDir
     env.passwordStorage.load = { password }
     env.getCMixParams.run = { cMixParams }
     env.loadCMix.run = { storageDir, password, cMixParamsJSON in
@@ -46,7 +46,7 @@ final class MessengerLoadTests: XCTestCase {
   func testMissingPassword() {
     var env: MessengerEnvironment = .unimplemented
     env.ctx.cMix = nil
-    env.storageDir = { "storage-dir" }
+    env.storageDir = "storage-dir"
     env.passwordStorage.load = { throw PasswordStorage.MissingPasswordError() }
     let load: MessengerLoad = .live(env)
 
@@ -64,7 +64,7 @@ final class MessengerLoadTests: XCTestCase {
 
     var env: MessengerEnvironment = .unimplemented
     env.ctx.cMix = nil
-    env.storageDir = { "storage-dir" }
+    env.storageDir = "storage-dir"
     env.passwordStorage.load = { "password".data(using: .utf8)! }
     env.getCMixParams.run = { "cmix-params".data(using: .utf8)! }
     env.loadCMix.run = { _, _, _ in throw error }
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
index 92e511f2..b11f8c8f 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
@@ -23,9 +23,9 @@ final class MessengerLogInTests: XCTestCase {
     }
     env.ctx.e2e = .unimplemented
     env.ctx.e2e!.getId.run = { e2eId }
-    env.udCert = { nil }
-    env.udContact = { nil }
-    env.udAddress = { nil }
+    env.udCert = nil
+    env.udContact = nil
+    env.udAddress = nil
     env.ctx.e2e!.getUdCertFromNdf.run = { udCertFromNDF }
     env.ctx.e2e!.getUdContactFromNdf.run = { udContactFromNDF }
     env.ctx.e2e!.getUdAddressFromNdf.run = { udAddressFromNDF }
@@ -66,9 +66,9 @@ final class MessengerLogInTests: XCTestCase {
     env.ctx.cMix!.networkFollowerStatus.run = { .running }
     env.ctx.e2e = .unimplemented
     env.ctx.e2e!.getId.run = { e2eId }
-    env.udCert = { altUdCert }
-    env.udContact = { altUdContact }
-    env.udAddress = { altUdAddress }
+    env.udCert = altUdCert
+    env.udContact = altUdContact
+    env.udAddress = altUdAddress
     env.newOrLoadUd.run = { params, _ in
       didNewOrLoadUDWithParams.append(params)
       return .unimplemented
@@ -138,8 +138,8 @@ final class MessengerLogInTests: XCTestCase {
     env.ctx.cMix!.networkFollowerStatus.run = { .running }
     env.ctx.e2e = .unimplemented
     env.ctx.e2e!.getId.run = { 1234 }
-    env.udCert = { nil }
-    env.udContact = { nil }
+    env.udCert = nil
+    env.udContact = nil
     env.ctx.e2e!.getUdCertFromNdf.run = { "ndf-ud-cert".data(using: .utf8)! }
     env.ctx.e2e!.getUdContactFromNdf.run = { throw error }
     let logIn: MessengerLogIn = .live(env)
@@ -158,9 +158,9 @@ final class MessengerLogInTests: XCTestCase {
     env.ctx.cMix!.networkFollowerStatus.run = { .running }
     env.ctx.e2e = .unimplemented
     env.ctx.e2e!.getId.run = { 1234 }
-    env.udCert = { "ud-cert".data(using: .utf8)! }
-    env.udContact = { "ud-contact".data(using: .utf8)! }
-    env.udAddress = { "ud-address" }
+    env.udCert = "ud-cert".data(using: .utf8)!
+    env.udContact = "ud-contact".data(using: .utf8)!
+    env.udAddress = "ud-address"
     env.newOrLoadUd.run = { _, _ in throw error }
     let logIn: MessengerLogIn = .live(env)
 
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
index deb6a8dc..861df63e 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
@@ -28,9 +28,9 @@ final class MessengerRegisterTests: XCTestCase {
     }
     env.ctx.e2e = .unimplemented
     env.ctx.e2e!.getId.run = { e2eId }
-    env.udCert = { nil }
-    env.udContact = { nil }
-    env.udAddress = { nil }
+    env.udCert = nil
+    env.udContact = nil
+    env.udAddress = nil
     env.ctx.e2e!.getUdCertFromNdf.run = { udCertFromNDF }
     env.ctx.e2e!.getUdContactFromNdf.run = { udContactFromNDF }
     env.ctx.e2e!.getUdAddressFromNdf.run = { udAddressFromNDF }
@@ -76,9 +76,9 @@ final class MessengerRegisterTests: XCTestCase {
     }
     env.ctx.e2e = .unimplemented
     env.ctx.e2e!.getId.run = { e2eId }
-    env.udCert = { altUdCert }
-    env.udContact = { altUdContact }
-    env.udAddress = { altUdAddress }
+    env.udCert = altUdCert
+    env.udContact = altUdContact
+    env.udAddress = altUdAddress
     env.newOrLoadUd.run = { params, _ in
       didNewOrLoadUDWithParams.append(params)
       return .unimplemented
@@ -152,8 +152,8 @@ final class MessengerRegisterTests: XCTestCase {
     }
     env.ctx.e2e = .unimplemented
     env.ctx.e2e!.getId.run = { 1234 }
-    env.udCert = { nil }
-    env.udContact = { nil }
+    env.udCert = nil
+    env.udContact = nil
     env.ctx.e2e!.getUdCertFromNdf.run = { "ndf-ud-cert".data(using: .utf8)! }
     env.ctx.e2e!.getUdContactFromNdf.run = { throw error }
     let register: MessengerRegister = .live(env)
@@ -175,9 +175,9 @@ final class MessengerRegisterTests: XCTestCase {
     }
     env.ctx.e2e = .unimplemented
     env.ctx.e2e!.getId.run = { 1234 }
-    env.udCert = { "ud-cert".data(using: .utf8)! }
-    env.udContact = { "ud-contact".data(using: .utf8)! }
-    env.udAddress = { "ud-address" }
+    env.udCert = "ud-cert".data(using: .utf8)!
+    env.udContact = "ud-contact".data(using: .utf8)!
+    env.udAddress = "ud-address"
     env.newOrLoadUd.run = { _, _ in throw error }
     let register: MessengerRegister = .live(env)
 
-- 
GitLab


From ada8d82a3c35f7a02af1119ddbbcdbb2a7efb397 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 13:02:53 +0100
Subject: [PATCH 08/27] Update MessengerContext

---
 .../Messenger/Functors/MessengerConnect.swift |   6 +-
 .../Functors/MessengerIsConnected.swift       |   2 +-
 .../Functors/MessengerIsLoaded.swift          |   2 +-
 .../Functors/MessengerIsLoggedIn.swift        |   2 +-
 .../Functors/MessengerIsRegistered.swift      |   2 +-
 .../Messenger/Functors/MessengerLoad.swift    |   4 +-
 .../Messenger/Functors/MessengerLogIn.swift   |   8 +-
 .../Functors/MessengerRegister.swift          |   8 +-
 .../Messenger/MessengerContext.swift          |  49 ++++++--
 .../Messenger/MessengerEnvironment.swift      |  42 ++++---
 .../Functors/MessengerConnectTests.swift      |  39 +++---
 .../Functors/MessengerIsConnectedTests.swift  |   8 +-
 .../Functors/MessengerIsLoadedTests.swift     |   8 +-
 .../Functors/MessengerIsLoggedInTests.swift   |   8 +-
 .../Functors/MessengerIsRegisteredTests.swift |  26 ++--
 .../Functors/MessengerLoadTests.swift         |   7 +-
 .../Functors/MessengerLogInTests.swift        | 101 ++++++++++-----
 .../Functors/MessengerRegisterTests.swift     | 118 +++++++++++-------
 18 files changed, 276 insertions(+), 164 deletions(-)

diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
index fa24b8eb..97e399ab 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
@@ -16,14 +16,14 @@ public struct MessengerConnect {
 extension MessengerConnect {
   public static func live(_ env: MessengerEnvironment) -> MessengerConnect {
     MessengerConnect {
-      guard let cMix = env.ctx.cMix else {
+      guard let cMix = env.ctx.getCMix() else {
         throw Error.notLoaded
       }
-      env.ctx.e2e = try env.login(
+      env.ctx.setE2E(try env.login(
         cMixId: cMix.getId(),
         identity: try cMix.makeLegacyReceptionIdentity(),
         e2eParamsJSON: env.getE2EParams()
-      )
+      ))
     }
   }
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
index 6a790dd5..81017429 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
@@ -12,7 +12,7 @@ public struct MessengerIsConnected {
 extension MessengerIsConnected {
   public static func live(_ env: MessengerEnvironment) -> MessengerIsConnected {
     MessengerIsConnected {
-      env.ctx.e2e != nil
+      env.ctx.getE2E() != nil
     }
   }
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
index 88750885..8931d2b4 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
@@ -12,7 +12,7 @@ public struct MessengerIsLoaded {
 extension MessengerIsLoaded {
   public static func live(_ env: MessengerEnvironment) -> MessengerIsLoaded {
     MessengerIsLoaded {
-      env.ctx.cMix != nil
+      env.ctx.getCMix() != nil
     }
   }
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
index 7f886bef..04aaa338 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
@@ -12,7 +12,7 @@ public struct MessengerIsLoggedIn {
 extension MessengerIsLoggedIn {
   public static func live(_ env: MessengerEnvironment) -> MessengerIsLoggedIn {
     MessengerIsLoggedIn {
-      env.ctx.ud != nil
+      env.ctx.getUD() != nil
     }
   }
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
index c91db5ac..cbf02c8a 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
@@ -16,7 +16,7 @@ public struct MessengerIsRegistered {
 extension MessengerIsRegistered {
   public static func live(_ env: MessengerEnvironment) -> MessengerIsRegistered {
     MessengerIsRegistered {
-      guard let e2e = env.ctx.e2e else {
+      guard let e2e = env.ctx.getE2E() else {
         throw Error.notConnected
       }
       return try env.isRegisteredWithUD(e2eId: e2e.getId())
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
index a8a6be31..c57d7a5a 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
@@ -12,11 +12,11 @@ public struct MessengerLoad {
 extension MessengerLoad {
   public static func live(_ env: MessengerEnvironment) -> MessengerLoad {
     MessengerLoad {
-      env.ctx.cMix = try env.loadCMix(
+      env.ctx.setCMix(try env.loadCMix(
         storageDir: env.storageDir,
         password: try env.passwordStorage.load(),
         cMixParamsJSON: env.getCMixParams()
-      )
+      ))
     }
   }
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
index 70df78ac..31323e9f 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
@@ -17,16 +17,16 @@ public struct MessengerLogIn {
 extension MessengerLogIn {
   public static func live(_ env: MessengerEnvironment) -> MessengerLogIn {
     MessengerLogIn {
-      guard let cMix = env.ctx.cMix else {
+      guard let cMix = env.ctx.getCMix() else {
         throw Error.notLoaded
       }
-      guard let e2e = env.ctx.e2e else {
+      guard let e2e = env.ctx.getE2E() else {
         throw Error.notConnected
       }
       if cMix.networkFollowerStatus() != .running {
         try cMix.startNetworkFollower(timeoutMS: 30_000)
       }
-      env.ctx.ud = try env.newOrLoadUd(
+      env.ctx.setUD(try env.newOrLoadUd(
         params: .init(
           e2eId: e2e.getId(),
           username: nil,
@@ -38,7 +38,7 @@ extension MessengerLogIn {
         follower: .init {
           cMix.networkFollowerStatus().rawValue
         }
-      )
+      ))
     }
   }
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
index 75fce252..0fdddac8 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
@@ -19,16 +19,16 @@ public struct MessengerRegister {
 extension MessengerRegister {
   public static func live(_ env: MessengerEnvironment) -> MessengerRegister {
     MessengerRegister { username in
-      guard let cMix = env.ctx.cMix else {
+      guard let cMix = env.ctx.getCMix() else {
         throw Error.notLoaded
       }
-      guard let e2e = env.ctx.e2e else {
+      guard let e2e = env.ctx.getE2E() else {
         throw Error.notConnected
       }
       if cMix.networkFollowerStatus() != .running {
         try cMix.startNetworkFollower(timeoutMS: 30_000)
       }
-      env.ctx.ud = try env.newOrLoadUd(
+      env.ctx.setUD(try env.newOrLoadUd(
         params: .init(
           e2eId: e2e.getId(),
           username: username,
@@ -40,7 +40,7 @@ extension MessengerRegister {
         follower: .init {
           cMix.networkFollowerStatus().rawValue
         }
-      )
+      ))
     }
   }
 }
diff --git a/Sources/XXMessengerClient/Messenger/MessengerContext.swift b/Sources/XXMessengerClient/Messenger/MessengerContext.swift
index ba67ed2b..c98523f2 100644
--- a/Sources/XXMessengerClient/Messenger/MessengerContext.swift
+++ b/Sources/XXMessengerClient/Messenger/MessengerContext.swift
@@ -1,17 +1,42 @@
 import XXClient
+import XCTestDynamicOverlay
 
-public class MessengerContext {
-  public init(
-    cMix: CMix? = nil,
-    e2e: E2E? = nil,
-    ud: UserDiscovery? = nil
-  ) {
-    self.cMix = cMix
-    self.e2e = e2e
-    self.ud = ud
+public struct MessengerContext {
+  public var getCMix: () -> CMix?
+  public var setCMix: (CMix?) -> Void
+  public var getE2E: () -> E2E?
+  public var setE2E: (E2E?) -> Void
+  public var getUD: () -> UserDiscovery?
+  public var setUD: (UserDiscovery?) -> Void
+}
+
+extension MessengerContext {
+  public static func live() -> MessengerContext {
+    class Container {
+      var cMix: CMix?
+      var e2e: E2E?
+      var ud: UserDiscovery?
+    }
+    let container = Container()
+
+    return MessengerContext(
+      getCMix: { container.cMix },
+      setCMix: { container.cMix = $0 },
+      getE2E: { container.e2e },
+      setE2E: { container.e2e = $0 },
+      getUD: { container.ud },
+      setUD: { container.ud = $0 }
+    )
   }
+}
 
-  public var cMix: CMix?
-  public var e2e: E2E?
-  public var ud: UserDiscovery?
+extension MessengerContext {
+  public static let unimplemented = MessengerContext(
+    getCMix: XCTUnimplemented("\(Self.self).getCMix"),
+    setCMix: XCTUnimplemented("\(Self.self).setCMix"),
+    getE2E: XCTUnimplemented("\(Self.self).getE2E"),
+    setE2E: XCTUnimplemented("\(Self.self).setE2E"),
+    getUD: XCTUnimplemented("\(Self.self).getUD"),
+    setUD: XCTUnimplemented("\(Self.self).setUD")
+  )
 }
diff --git a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
index 29391b20..b3009ae0 100644
--- a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
+++ b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
@@ -29,30 +29,32 @@ extension MessengerEnvironment {
     .appendingPathComponent("xx.network.client")
     .path
 
-  public static let live = MessengerEnvironment(
-    ctx: .init(),
-    downloadNDF: .live,
-    fileManager: .live(),
-    generateSecret: .live,
-    getCMixParams: .liveDefault,
-    getE2EParams: .liveDefault,
-    isRegisteredWithUD: .live,
-    loadCMix: .live,
-    login: .live,
-    ndfEnvironment: .mainnet,
-    newCMix: .live,
-    newOrLoadUd: .live,
-    passwordStorage: .keychain,
-    storageDir: MessengerEnvironment.defaultStorageDir,
-    udAddress: nil,
-    udCert: nil,
-    udContact: nil
-  )
+  public static func live() -> MessengerEnvironment {
+    MessengerEnvironment(
+      ctx: .live(),
+      downloadNDF: .live,
+      fileManager: .live(),
+      generateSecret: .live,
+      getCMixParams: .liveDefault,
+      getE2EParams: .liveDefault,
+      isRegisteredWithUD: .live,
+      loadCMix: .live,
+      login: .live,
+      ndfEnvironment: .mainnet,
+      newCMix: .live,
+      newOrLoadUd: .live,
+      passwordStorage: .keychain,
+      storageDir: MessengerEnvironment.defaultStorageDir,
+      udAddress: nil,
+      udCert: nil,
+      udContact: nil
+    )
+  }
 }
 
 extension MessengerEnvironment {
   public static let unimplemented = MessengerEnvironment(
-    ctx: .init(),
+    ctx: .unimplemented,
     downloadNDF: .unimplemented,
     fileManager: .unimplemented,
     generateSecret: .unimplemented,
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
index c44b4907..c93e403e 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
@@ -12,16 +12,22 @@ final class MessengerConnectTests: XCTestCase {
       var identity: ReceptionIdentity
       var e2eParamsJSON: Data
     }
+
     var didLogIn: [DidLogIn] = []
+    var didSetE2E: [E2E?] = []
 
     let cMixId = 1234
     let receptionId = ReceptionIdentity.stub
     let e2eParams = "e2e-params".data(using: .utf8)!
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.cMix!.getId.run = { cMixId }
-    env.ctx.cMix!.makeLegacyReceptionIdentity.run = { receptionId }
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.getId.run = { cMixId }
+      cMix.makeLegacyReceptionIdentity.run = { receptionId }
+      return cMix
+    }
+    env.ctx.setE2E = { didSetE2E.append($0) }
     env.getE2EParams.run = { e2eParams }
     env.login.run = { ephemeral, cMixId, authCallbacks, identity, e2eParamsJSON in
       didLogIn.append(.init(
@@ -46,13 +52,12 @@ final class MessengerConnectTests: XCTestCase {
         e2eParamsJSON: e2eParams
       )
     ])
-
-    XCTAssertNotNil(env.ctx.e2e)
+    XCTAssertEqual(didSetE2E.compactMap { $0 }.count, 1)
   }
 
   func testConnectWithoutCMix() {
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = nil
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = { nil }
     let connect: MessengerConnect = .live(env)
 
     XCTAssertThrowsError(try connect()) { error in
@@ -67,10 +72,13 @@ final class MessengerConnectTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.cMix!.getId.run = { 1234 }
-    env.ctx.cMix!.makeLegacyReceptionIdentity.run = { throw error }
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.getId.run = { 1234 }
+      cMix.makeLegacyReceptionIdentity.run = { throw error }
+      return cMix
+    }
     let connect: MessengerConnect = .live(env)
 
     XCTAssertThrowsError(try connect()) { err in
@@ -83,9 +91,12 @@ final class MessengerConnectTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.cMix!.getId.run = { 1234 }
-    env.ctx.cMix!.makeLegacyReceptionIdentity.run = { .stub }
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.getId.run = { 1234 }
+      cMix.makeLegacyReceptionIdentity.run = { .stub }
+      return cMix
+    }
     env.getE2EParams.run = { "e2e-params".data(using: .utf8)! }
     env.login.run = { _, _, _, _, _ in throw error }
     let connect: MessengerConnect = .live(env)
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
index e207e8a5..b361170c 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
@@ -3,16 +3,16 @@ import XCTest
 
 final class MessengerIsConnectedTests: XCTestCase {
   func testWithE2E() {
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.e2e = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getE2E = { .unimplemented }
     let isConnected: MessengerIsConnected = .live(env)
 
     XCTAssertTrue(isConnected())
   }
 
   func testWithoutE2E() {
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.e2e = nil
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getE2E = { nil }
     let isConnected: MessengerIsConnected = .live(env)
 
     XCTAssertFalse(isConnected())
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
index c83dc523..a88a1148 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
@@ -3,16 +3,16 @@ import XCTest
 
 final class MessengerIsLoadedTests: XCTestCase {
   func testWithCMix() {
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = { .unimplemented }
     let isLoaded: MessengerIsLoaded = .live(env)
 
     XCTAssertTrue(isLoaded())
   }
 
   func testWithoutCMix() {
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = nil
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = { nil }
     let isLoaded: MessengerIsLoaded = .live(env)
 
     XCTAssertFalse(isLoaded())
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
index 6b5b7903..0bbd8867 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
@@ -3,16 +3,16 @@ import XCTest
 
 final class MessengerIsLoggedInTests: XCTestCase {
   func testWithUD() {
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.ud = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getUD = { .unimplemented }
     let isLoggedIn: MessengerIsLoggedIn = .live(env)
 
     XCTAssertTrue(isLoggedIn())
   }
 
   func testWithoutUD() {
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.ud = nil
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getUD = { nil }
     let isLoggedIn: MessengerIsLoggedIn = .live(env)
 
     XCTAssertFalse(isLoggedIn())
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
index 250fdad8..b11bfbc6 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
@@ -1,4 +1,5 @@
 import XCTest
+import XXClient
 @testable import XXMessengerClient
 
 final class MessengerIsRegisteredTests: XCTestCase {
@@ -6,8 +7,11 @@ final class MessengerIsRegisteredTests: XCTestCase {
     var didIsRegisteredWithUD: [Int] = []
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.e2e = .unimplemented
-    env.ctx.e2e!.getId.run = { 1234 }
+    env.ctx.getE2E = {
+      var e2e: E2E = .unimplemented
+      e2e.getId.run = { 1234 }
+      return e2e
+    }
     env.isRegisteredWithUD.run = { e2eId in
       didIsRegisteredWithUD.append(e2eId)
       return true
@@ -20,8 +24,11 @@ final class MessengerIsRegisteredTests: XCTestCase {
 
   func testNotRegistered() throws {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.e2e = .unimplemented
-    env.ctx.e2e!.getId.run = { 1234 }
+    env.ctx.getE2E = {
+      var e2e: E2E = .unimplemented
+      e2e.getId.run = { 1234 }
+      return e2e
+    }
     env.isRegisteredWithUD.run = { _ in false }
     let isRegistered: MessengerIsRegistered = .live(env)
 
@@ -29,8 +36,8 @@ final class MessengerIsRegisteredTests: XCTestCase {
   }
 
   func testWithoutE2E() {
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.e2e = nil
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getE2E = { nil }
     let isRegistered: MessengerIsRegistered = .live(env)
 
     XCTAssertThrowsError(try isRegistered()) { err in
@@ -46,8 +53,11 @@ final class MessengerIsRegisteredTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.e2e = .unimplemented
-    env.ctx.e2e!.getId.run = { 1234 }
+    env.ctx.getE2E = {
+      var e2e: E2E = .unimplemented
+      e2e.getId.run = { 1234 }
+      return e2e
+    }
     env.isRegisteredWithUD.run = { _ in throw error }
     let isRegistered: MessengerIsRegistered = .live(env)
 
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
index 1d8ae5f2..eecdca12 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
@@ -11,13 +11,14 @@ final class MessengerLoadTests: XCTestCase {
       var cMixParamsJSON: Data
     }
     var didLoadCMix: [DidLoadCMix] = []
+    var didSetCMix: [CMix?] = []
 
     let storageDir = "test-storage-dir"
     let password = "password".data(using: .utf8)!
     let cMixParams = "cmix-params".data(using: .utf8)!
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = nil
+    env.ctx.setCMix = { didSetCMix.append($0) }
     env.storageDir = storageDir
     env.passwordStorage.load = { password }
     env.getCMixParams.run = { cMixParams }
@@ -40,12 +41,11 @@ final class MessengerLoadTests: XCTestCase {
         cMixParamsJSON: cMixParams
       )
     ])
-    XCTAssertNotNil(env.ctx.cMix)
+    XCTAssertEqual(didSetCMix.compactMap{ $0 }.count, 1)
   }
 
   func testMissingPassword() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = nil
     env.storageDir = "storage-dir"
     env.passwordStorage.load = { throw PasswordStorage.MissingPasswordError() }
     let load: MessengerLoad = .live(env)
@@ -63,7 +63,6 @@ final class MessengerLoadTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = nil
     env.storageDir = "storage-dir"
     env.passwordStorage.load = { "password".data(using: .utf8)! }
     env.getCMixParams.run = { "cmix-params".data(using: .utf8)! }
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
index b11f8c8f..791c28ff 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
@@ -8,6 +8,7 @@ final class MessengerLogInTests: XCTestCase {
     var didStartNetworkFollower: [Int] = []
     var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
     var didNewOrLoadUDWithFollower: [UdNetworkStatus] = []
+    var didSetUD: [UserDiscovery?] = []
 
     let e2eId = 1234
     let networkFollowerStatus: NetworkFollowerStatus = .stopped
@@ -16,19 +17,26 @@ final class MessengerLogInTests: XCTestCase {
     let udAddressFromNDF = "ndf-ud-address"
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.cMix!.networkFollowerStatus.run = { networkFollowerStatus }
-    env.ctx.cMix!.startNetworkFollower.run = { timeout in
-      didStartNetworkFollower.append(timeout)
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.networkFollowerStatus.run = { networkFollowerStatus }
+      cMix.startNetworkFollower.run = { timeout in
+        didStartNetworkFollower.append(timeout)
+      }
+      return cMix
     }
-    env.ctx.e2e = .unimplemented
-    env.ctx.e2e!.getId.run = { e2eId }
+    env.ctx.getE2E = {
+      var e2e: E2E = .unimplemented
+      e2e.getId.run = { e2eId }
+      e2e.getUdCertFromNdf.run = { udCertFromNDF }
+      e2e.getUdContactFromNdf.run = { udContactFromNDF }
+      e2e.getUdAddressFromNdf.run = { udAddressFromNDF }
+      return e2e
+    }
+    env.ctx.setUD = { didSetUD.append($0) }
     env.udCert = nil
     env.udContact = nil
     env.udAddress = nil
-    env.ctx.e2e!.getUdCertFromNdf.run = { udCertFromNDF }
-    env.ctx.e2e!.getUdContactFromNdf.run = { udContactFromNDF }
-    env.ctx.e2e!.getUdAddressFromNdf.run = { udAddressFromNDF }
     env.newOrLoadUd.run = { params, follower in
       didNewOrLoadUDWithParams.append(params)
       didNewOrLoadUDWithFollower.append(follower)
@@ -51,21 +59,30 @@ final class MessengerLogInTests: XCTestCase {
       didNewOrLoadUDWithFollower.first?.handle(),
       networkFollowerStatus.rawValue
     )
-    XCTAssertNotNil(env.ctx.ud)
+    XCTAssertEqual(didSetUD.compactMap { $0 }.count, 1)
   }
 
   func testLoginWithAlternativeUD() throws {
     var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
+    var didSetUD: [UserDiscovery?] = []
+
     let e2eId = 1234
     let altUdCert = "alt-ud-cert".data(using: .utf8)!
     let altUdContact = "alt-ud-contact".data(using: .utf8)!
     let altUdAddress = "alt-ud-address"
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.cMix!.networkFollowerStatus.run = { .running }
-    env.ctx.e2e = .unimplemented
-    env.ctx.e2e!.getId.run = { e2eId }
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.networkFollowerStatus.run = { .running }
+      return cMix
+    }
+    env.ctx.getE2E = {
+      var e2e: E2E = .unimplemented
+      e2e.getId.run = { e2eId }
+      return e2e
+    }
+    env.ctx.setUD = { didSetUD.append($0) }
     env.udCert = altUdCert
     env.udContact = altUdContact
     env.udAddress = altUdAddress
@@ -84,12 +101,12 @@ final class MessengerLogInTests: XCTestCase {
       contactFile: altUdContact,
       address: altUdAddress
     )])
-    XCTAssertNotNil(env.ctx.ud)
+    XCTAssertEqual(didSetUD.compactMap { $0 }.count, 1)
   }
 
   func testLoginWithoutCMix() {
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = nil
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = { nil }
     let logIn: MessengerLogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { error in
@@ -101,9 +118,9 @@ final class MessengerLogInTests: XCTestCase {
   }
 
   func testLoginWithoutE2E() {
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.e2e = nil
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = { .unimplemented }
+    env.ctx.getE2E = { nil }
     let logIn: MessengerLogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { error in
@@ -118,10 +135,14 @@ final class MessengerLogInTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.cMix!.networkFollowerStatus.run = { .stopped }
-    env.ctx.cMix!.startNetworkFollower.run = { _ in throw error }
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.networkFollowerStatus.run = { .stopped }
+      cMix.startNetworkFollower.run = { _ in throw error }
+      return cMix
+    }
+    env.ctx.getE2E = { .unimplemented }
     let logIn: MessengerLogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { err in
@@ -134,14 +155,20 @@ final class MessengerLogInTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.cMix!.networkFollowerStatus.run = { .running }
-    env.ctx.e2e = .unimplemented
-    env.ctx.e2e!.getId.run = { 1234 }
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.networkFollowerStatus.run = { .running }
+      return cMix
+    }
+    env.ctx.getE2E = {
+      var e2e: E2E = .unimplemented
+      e2e.getId.run = { 1234 }
+      e2e.getUdCertFromNdf.run = { "ndf-ud-cert".data(using: .utf8)! }
+      e2e.getUdContactFromNdf.run = { throw error }
+      return e2e
+    }
     env.udCert = nil
     env.udContact = nil
-    env.ctx.e2e!.getUdCertFromNdf.run = { "ndf-ud-cert".data(using: .utf8)! }
-    env.ctx.e2e!.getUdContactFromNdf.run = { throw error }
     let logIn: MessengerLogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { err in
@@ -154,10 +181,16 @@ final class MessengerLogInTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.cMix!.networkFollowerStatus.run = { .running }
-    env.ctx.e2e = .unimplemented
-    env.ctx.e2e!.getId.run = { 1234 }
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.networkFollowerStatus.run = { .running }
+      return cMix
+    }
+    env.ctx.getE2E = {
+      var e2e: E2E = .unimplemented
+      e2e.getId.run = { 1234 }
+      return e2e
+    }
     env.udCert = "ud-cert".data(using: .utf8)!
     env.udContact = "ud-contact".data(using: .utf8)!
     env.udAddress = "ud-address"
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
index 861df63e..8feb8a7c 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
@@ -8,6 +8,7 @@ final class MessengerRegisterTests: XCTestCase {
     var didStartNetworkFollower: [Int] = []
     var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
     var didNewOrLoadUDWithFollower: [UdNetworkStatus] = []
+    var didSetUD: [UserDiscovery?] = []
 
     let e2eId = 1234
     let networkFollowerStatus: NetworkFollowerStatus = .stopped
@@ -18,22 +19,29 @@ final class MessengerRegisterTests: XCTestCase {
     let username = "new-user-name"
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.cMix!.networkFollowerStatus.run = { networkFollowerStatus }
-    env.ctx.cMix!.startNetworkFollower.run = { timeout in
-      didStartNetworkFollower.append(timeout)
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.networkFollowerStatus.run = { networkFollowerStatus }
+      cMix.startNetworkFollower.run = { timeout in
+        didStartNetworkFollower.append(timeout)
+      }
+      cMix.getReceptionRegistrationValidationSignature.run = {
+        registrationSignature
+      }
+      return cMix
     }
-    env.ctx.cMix!.getReceptionRegistrationValidationSignature.run = {
-      registrationSignature
+    env.ctx.getE2E = {
+      var e2e: E2E = .unimplemented
+      e2e.getId.run = { e2eId }
+      e2e.getUdCertFromNdf.run = { udCertFromNDF }
+      e2e.getUdContactFromNdf.run = { udContactFromNDF }
+      e2e.getUdAddressFromNdf.run = { udAddressFromNDF }
+      return e2e
     }
-    env.ctx.e2e = .unimplemented
-    env.ctx.e2e!.getId.run = { e2eId }
+    env.ctx.setUD = { didSetUD.append($0) }
     env.udCert = nil
     env.udContact = nil
     env.udAddress = nil
-    env.ctx.e2e!.getUdCertFromNdf.run = { udCertFromNDF }
-    env.ctx.e2e!.getUdContactFromNdf.run = { udContactFromNDF }
-    env.ctx.e2e!.getUdAddressFromNdf.run = { udAddressFromNDF }
     env.newOrLoadUd.run = { params, follower in
       didNewOrLoadUDWithParams.append(params)
       didNewOrLoadUDWithFollower.append(follower)
@@ -56,11 +64,13 @@ final class MessengerRegisterTests: XCTestCase {
       didNewOrLoadUDWithFollower.first?.handle(),
       networkFollowerStatus.rawValue
     )
-    XCTAssertNotNil(env.ctx.ud)
+    XCTAssertEqual(didSetUD.compactMap { $0 }.count, 1)
   }
 
   func testRegisterWithAlternativeUD() throws {
     var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
+    var didSetUD: [UserDiscovery?] = []
+
     let e2eId = 1234
     let registrationSignature = "registration-signature".data(using: .utf8)!
     let altUdCert = "alt-ud-cert".data(using: .utf8)!
@@ -69,13 +79,20 @@ final class MessengerRegisterTests: XCTestCase {
     let username = "new-user-name"
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.cMix!.networkFollowerStatus.run = { .running }
-    env.ctx.cMix!.getReceptionRegistrationValidationSignature.run = {
-      registrationSignature
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.networkFollowerStatus.run = { .running }
+      cMix.getReceptionRegistrationValidationSignature.run = {
+        registrationSignature
+      }
+      return cMix
+    }
+    env.ctx.getE2E = {
+      var e2e: E2E = .unimplemented
+      e2e.getId.run = { e2eId }
+      return e2e
     }
-    env.ctx.e2e = .unimplemented
-    env.ctx.e2e!.getId.run = { e2eId }
+    env.ctx.setUD = { didSetUD.append($0) }
     env.udCert = altUdCert
     env.udContact = altUdContact
     env.udAddress = altUdAddress
@@ -94,12 +111,12 @@ final class MessengerRegisterTests: XCTestCase {
       contactFile: altUdContact,
       address: altUdAddress
     )])
-    XCTAssertNotNil(env.ctx.ud)
+    XCTAssertEqual(didSetUD.compactMap { $0 }.count, 1)
   }
 
   func testRegisterWithoutCMix() {
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = nil
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = { nil }
     let register: MessengerRegister = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { error in
@@ -111,9 +128,9 @@ final class MessengerRegisterTests: XCTestCase {
   }
 
   func testRegisterWithoutE2E() {
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.e2e = nil
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = { .unimplemented }
+    env.ctx.getE2E = { nil }
     let register: MessengerRegister = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { error in
@@ -128,11 +145,14 @@ final class MessengerRegisterTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    let env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.cMix!.networkFollowerStatus.run = { .stopped }
-    env.ctx.cMix!.startNetworkFollower.run = { _ in throw error }
-    env.ctx.e2e = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.networkFollowerStatus.run = { .stopped }
+      cMix.startNetworkFollower.run = { _ in throw error }
+      return cMix
+    }
+    env.ctx.getE2E = { .unimplemented }
     let register: MessengerRegister = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { err in
@@ -145,17 +165,23 @@ final class MessengerRegisterTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.cMix!.networkFollowerStatus.run = { .running }
-    env.ctx.cMix!.getReceptionRegistrationValidationSignature.run = {
-      "registration-signature".data(using: .utf8)!
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.networkFollowerStatus.run = { .running }
+      cMix.getReceptionRegistrationValidationSignature.run = {
+        "registration-signature".data(using: .utf8)!
+      }
+      return cMix
+    }
+    env.ctx.getE2E = {
+      var e2e: E2E = .unimplemented
+      e2e.getId.run = { 1234 }
+      e2e.getUdCertFromNdf.run = { "ndf-ud-cert".data(using: .utf8)! }
+      e2e.getUdContactFromNdf.run = { throw error }
+      return e2e
     }
-    env.ctx.e2e = .unimplemented
-    env.ctx.e2e!.getId.run = { 1234 }
     env.udCert = nil
     env.udContact = nil
-    env.ctx.e2e!.getUdCertFromNdf.run = { "ndf-ud-cert".data(using: .utf8)! }
-    env.ctx.e2e!.getUdContactFromNdf.run = { throw error }
     let register: MessengerRegister = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { err in
@@ -168,13 +194,19 @@ final class MessengerRegisterTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.cMix = .unimplemented
-    env.ctx.cMix!.networkFollowerStatus.run = { .running }
-    env.ctx.cMix!.getReceptionRegistrationValidationSignature.run = {
-      "registration-signature".data(using: .utf8)!
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.networkFollowerStatus.run = { .running }
+      cMix.getReceptionRegistrationValidationSignature.run = {
+        "registration-signature".data(using: .utf8)!
+      }
+      return cMix
+    }
+    env.ctx.getE2E = {
+      var e2e: E2E = .unimplemented
+      e2e.getId.run = { 1234 }
+      return e2e
     }
-    env.ctx.e2e = .unimplemented
-    env.ctx.e2e!.getId.run = { 1234 }
     env.udCert = "ud-cert".data(using: .utf8)!
     env.udContact = "ud-contact".data(using: .utf8)!
     env.udAddress = "ud-address"
-- 
GitLab


From 7d19bb67d577a50d6771f8983a951ba8026dc570 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 13:45:09 +0100
Subject: [PATCH 09/27] Add XXMessengerClient quick start documentation

---
 Docs/XXMessengerClient.md | 60 +++++++++++++++++++++++++++++++++++++++
 README.md                 |  2 ++
 2 files changed, 62 insertions(+)
 create mode 100644 Docs/XXMessengerClient.md

diff --git a/Docs/XXMessengerClient.md b/Docs/XXMessengerClient.md
new file mode 100644
index 00000000..d4a634a9
--- /dev/null
+++ b/Docs/XXMessengerClient.md
@@ -0,0 +1,60 @@
+# XXMessengerClient
+
+`XXMessengerClient` is a client wrapper library for use in xx-messenger application.
+
+## 🛠 Instantiate messenger
+
+Example:
+
+```swift
+// setup environment:
+var environment: MessengerEnvironment = .live()
+
+// change cMix NDF environment if needed:
+environment.ndfEnvironment = ...
+
+// use alternative user-discovery if needed:
+environment.udAddress = ...
+environment.udCert = ...
+environment.udContact = ...
+
+// instantiate messenger:
+let messenger: Messenger = .live(environment)
+```
+
+## 🚀 Start messenger
+
+Example:
+
+```
+func start(messenger: Messenger) throws {
+  // check if messenger is loaded:
+  if messenger.isLoaded() == false {
+    // check if messenger is created and stored on disk:
+    if messenger.isCreated() == false {
+      // create new messenger and store it on disk:
+      try messenger.create()
+    }
+    // load messenger stored on disk:
+    try messenger.load()
+  }
+
+  // check if messenger is connected:
+  if messenger.isConnected() == false {
+    // start end-to-end connection:
+    try messenger.connect()
+  }
+
+  // check if messenger is logged in with user-discovery:
+  if messenger.isLoggedIn() == false {
+    // check if messenger is registered with user-discovery:
+    if try messenger.isRegistered() == false {
+      // register new user with user-discovery:
+      try messenger.register(username: "new-username")
+    } else {
+      // login previously registered user with user-discovery:
+      try messenger.logIn()
+    }
+  }
+}
+```
\ No newline at end of file
diff --git a/README.md b/README.md
index 5a2eadd5..539d24b3 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,8 @@ Also you can checkout included example iOS application.
 
 You can find full documentation with step by step guide [here](https://xxdk-dev.xx.network/mobile%20docs/ios-sdk)
 
+- [XXMessengerClient](Docs/XXMessengerClient.md)
+
 ## 🚀 Quick Start
 
 Add `XXClient` library as a dependency to your project using Swift Package Manager.
-- 
GitLab


From 06f3b09325de75566eea18f64cf94ff2f855305b Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 13:49:58 +0100
Subject: [PATCH 10/27] Reorganize documentation

---
 Docs/XXClient-quick-start-guide.md | 116 ++++++++++++++++++++++++++
 README.md                          | 126 +----------------------------
 2 files changed, 119 insertions(+), 123 deletions(-)
 create mode 100644 Docs/XXClient-quick-start-guide.md

diff --git a/Docs/XXClient-quick-start-guide.md b/Docs/XXClient-quick-start-guide.md
new file mode 100644
index 00000000..503bc2d0
--- /dev/null
+++ b/Docs/XXClient-quick-start-guide.md
@@ -0,0 +1,116 @@
+# XXClient Quick Start Guide
+
+Add `XXClient` library as a dependency to your project using Swift Package Manager.
+
+## ▶️ Instantiating cMix
+
+You can use a convenient `CMixManager` wrapper to manage cMix stored on disk:
+
+```swift
+let cMixManager: CMixManager = .live(
+  passwordStorage: .init(
+    save: { password in
+      // securely save provided password
+    },
+    load: {
+      // load securely stored password
+    }
+  )
+)
+
+let cMix: CMix
+if cMixManager.hasStorage() {
+  cMix = try cMixManager.load()
+} else {
+  cMix = try cMixManager.create()
+}
+```
+
+Check out included example iOS application for the `PasswordStorage` implementation that uses the iOS keychain.
+
+## ▶️ Connecting to the network
+
+Start network follower:
+
+```swift
+try cMix.startNetworkFollower(timeoutMS: 10_000)
+```
+
+Wait until connected:
+
+```swift
+let isNetworkHealthy = try cMix.waitForNetwork(timeoutMS: 30_000)
+```
+
+## ▶️ Making a new reception identity
+
+Use the cMix to make a new reception identity:
+
+```swift
+let myIdentity = try cMix.makeReceptionIdentity()
+```
+
+## ▶️ Create new E2E
+
+```swift
+let login: Login = .live
+let e2e = try login(
+  cMixId: cMix.getId(),
+  identity: myIdentity
+)
+```
+
+## ▶️ Connecting to remote
+
+Perform auth key negotiation with the given recipient to get the `Connection`:
+
+```swift
+let connection = try cMix.connect(
+  withAuthentication: false,
+  e2eId: e2e.getId(),
+  recipientContact: ...
+)
+```
+
+Pass `true` for the `withAuthentication` parameter if you want to prove id ownership to remote as well.
+
+## ▶️ Sending messages
+
+Send a message to the connection's partner:
+
+```swift
+let sendReport = try connection.send(
+  messageType: 1,
+  payload: ...
+)
+```
+
+Check if the round succeeded:
+
+```swift
+try cMix.waitForRoundResult(
+  roundList: try sendReport.encode(),
+  timeoutMS: 30_000,
+  callback: .init { result in
+    switch result {
+    case .delivered(let roundResults):
+      ...
+    case .notDelivered(let timedOut):
+      ...
+    }
+  }
+)
+```
+
+## ▶️ Receiving messages
+
+Use connection's message listener to receive messages from partner:
+
+```swift
+try connection.registerListener(
+  messageType: 1,
+  listener: .init { message in
+    ...
+  }
+)
+```
\ No newline at end of file
diff --git a/README.md b/README.md
index 539d24b3..a311b580 100644
--- a/README.md
+++ b/README.md
@@ -3,134 +3,14 @@
 ![Swift 5.6](https://img.shields.io/badge/swift-5.6-orange.svg)
 ![platform iOS](https://img.shields.io/badge/platform-iOS-blue.svg)
 
-## 📱 Demo
-
-Refer to this [demo](https://git.xx.network/elixxir/shielded-help-demo/elixxir-dapp-demo) to see an example of how to build an app with the SDK to send `E2E` messages and send `RestLike` message.
-
-Also you can checkout included example iOS application.
-
 ## 📖 Documentation 
 
-You can find full documentation with step by step guide [here](https://xxdk-dev.xx.network/mobile%20docs/ios-sdk)
-
+- [XXClient Quick Start Guide](Docs/XXClient-quick-start-guide.md)
 - [XXMessengerClient](Docs/XXMessengerClient.md)
 
-## 🚀 Quick Start
-
-Add `XXClient` library as a dependency to your project using Swift Package Manager.
-
-### ▶️ Instantiating cMix
-
-You can use a convenient `CMixManager` wrapper to manage cMix stored on disk:
-
-```swift
-let cMixManager: CMixManager = .live(
-  passwordStorage: .init(
-    save: { password in
-      // securely save provided password
-    },
-    load: {
-      // load securely stored password
-    }
-  )
-)
-
-let cMix: CMix
-if cMixManager.hasStorage() {
-  cMix = try cMixManager.load()
-} else {
-  cMix = try cMixManager.create()
-}
-```
-
-Check out included example iOS application for the `PasswordStorage` implementation that uses the iOS keychain.
-
-### ▶️ Connecting to the network
-
-Start network follower:
-
-```swift
-try cMix.startNetworkFollower(timeoutMS: 10_000)
-```
-
-Wait until connected:
-
-```swift
-let isNetworkHealthy = try cMix.waitForNetwork(timeoutMS: 30_000)
-```
-
-### ▶️ Making a new reception identity
-
-Use the cMix to make a new reception identity:
-
-```swift
-let myIdentity = try cMix.makeReceptionIdentity()
-```
-
-### ▶️ Create new E2E
-
-```swift
-let login: Login = .live
-let e2e = try login(
-  cMixId: cMix.getId(),
-  identity: myIdentity
-)
-```
-
-### ▶️ Connecting to remote
-
-Perform auth key negotiation with the given recipient to get the `Connection`:
-
-```swift
-let connection = try cMix.connect(
-  withAuthentication: false,
-  e2eId: e2e.getId(),
-  recipientContact: ...
-)
-```
-
-Pass `true` for the `withAuthentication` parameter if you want to prove id ownership to remote as well.
-
-### ▶️ Sending messages
-
-Send a message to the connection's partner:
-
-```swift
-let sendReport = try connection.send(
-  messageType: 1,
-  payload: ...
-)
-```
-
-Check if the round succeeded:
-
-```swift
-try cMix.waitForRoundResult(
-  roundList: try sendReport.encode(),
-  timeoutMS: 30_000,
-  callback: .init { result in
-    switch result {
-    case .delivered(let roundResults):
-      ...
-    case .notDelivered(let timedOut):
-      ...
-    }
-  }
-)
-```
-
-### ▶️ Receiving messages
-
-Use connection's message listener to receive messages from partner:
+## 📱 Demo
 
-```swift
-try connection.registerListener(
-  messageType: 1,
-  listener: .init { message in
-    ...
-  }
-)
-```
+Checkout included example iOS application.
 
 ## 🛠 Development
 
-- 
GitLab


From 21869e9d4dbc1ae6d83bc0f2bca33e71c22a81e5 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 18:11:25 +0100
Subject: [PATCH 11/27] Add MessengerCMix, MessengerE2E, and MessengerUD

Functors for accessing XXClient components
---
 .../Messenger/Functors/MessengerCMix.swift    | 22 +++++++++++++++++++
 .../Messenger/Functors/MessengerE2E.swift     | 22 +++++++++++++++++++
 .../Messenger/Functors/MessengerUD.swift      | 22 +++++++++++++++++++
 .../Messenger/Messenger.swift                 |  9 ++++++++
 .../Functors/MessengerCMixTests.swift         | 21 ++++++++++++++++++
 .../Functors/MessengerE2ETests.swift          | 21 ++++++++++++++++++
 .../Messenger/Functors/MessengerUDTests.swift | 21 ++++++++++++++++++
 7 files changed, 138 insertions(+)
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerCMix.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerE2E.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerUD.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerCMixTests.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerE2ETests.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerUDTests.swift

diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerCMix.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerCMix.swift
new file mode 100644
index 00000000..5543c048
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerCMix.swift
@@ -0,0 +1,22 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerCMix {
+  public var run: () -> CMix?
+
+  public func callAsFunction() -> CMix? {
+    run()
+  }
+}
+
+extension MessengerCMix {
+  public static func live(_ env: MessengerEnvironment) -> MessengerCMix {
+    MessengerCMix(run: env.ctx.getCMix)
+  }
+}
+
+extension MessengerCMix {
+  public static let unimplemented = MessengerCMix(
+    run: XCTUnimplemented("\(Self.self)", placeholder: nil)
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerE2E.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerE2E.swift
new file mode 100644
index 00000000..cc1f8def
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerE2E.swift
@@ -0,0 +1,22 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerE2E {
+  public var run: () -> E2E?
+
+  public func callAsFunction() -> E2E? {
+    run()
+  }
+}
+
+extension MessengerE2E {
+  public static func live(_ env: MessengerEnvironment) -> MessengerE2E {
+    MessengerE2E(run: env.ctx.getE2E)
+  }
+}
+
+extension MessengerE2E {
+  public static let unimplemented = MessengerE2E(
+    run: XCTUnimplemented("\(Self.self)", placeholder: nil)
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerUD.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerUD.swift
new file mode 100644
index 00000000..c64ee6cf
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerUD.swift
@@ -0,0 +1,22 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerUD {
+  public var run: () -> UserDiscovery?
+
+  public func callAsFunction() -> UserDiscovery? {
+    run()
+  }
+}
+
+extension MessengerUD {
+  public static func live(_ env: MessengerEnvironment) -> MessengerUD {
+    MessengerUD(run: env.ctx.getUD)
+  }
+}
+
+extension MessengerUD {
+  public static let unimplemented = MessengerUD(
+    run: XCTUnimplemented("\(Self.self)", placeholder: nil)
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
index a477f7cc..12610bd6 100644
--- a/Sources/XXMessengerClient/Messenger/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -1,6 +1,9 @@
 import XXClient
 
 public struct Messenger {
+  public var cMix: MessengerCMix
+  public var e2e: MessengerE2E
+  public var ud: MessengerUD
   public var isCreated: MessengerIsCreated
   public var create: MessengerCreate
   public var isLoaded: MessengerIsLoaded
@@ -16,6 +19,9 @@ public struct Messenger {
 extension Messenger {
   public static func live(_ env: MessengerEnvironment) -> Messenger {
     Messenger(
+      cMix: .live(env),
+      e2e: .live(env),
+      ud: .live(env),
       isCreated: .live(env),
       create: .live(env),
       isLoaded: .live(env),
@@ -32,6 +38,9 @@ extension Messenger {
 
 extension Messenger {
   public static let unimplemented = Messenger(
+    cMix: .unimplemented,
+    e2e: .unimplemented,
+    ud: .unimplemented,
     isCreated: .unimplemented,
     create: .unimplemented,
     isLoaded: .unimplemented,
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCMixTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCMixTests.swift
new file mode 100644
index 00000000..f4327a08
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCMixTests.swift
@@ -0,0 +1,21 @@
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+
+final class MessengerCMixTests: XCTestCase {
+  func testCMix() throws {
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = { .unimplemented }
+    let cMix: MessengerCMix = .live(env)
+
+    XCTAssertNotNil(cMix())
+  }
+
+  func testCMixWhenNotSet() throws {
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = { nil }
+    let cMix: MessengerCMix = .live(env)
+
+    XCTAssertNil(cMix())
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerE2ETests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerE2ETests.swift
new file mode 100644
index 00000000..bb54fb78
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerE2ETests.swift
@@ -0,0 +1,21 @@
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+
+final class MessengerE2ETests: XCTestCase {
+  func testE2E() throws {
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getE2E = { .unimplemented }
+    let e2e: MessengerE2E = .live(env)
+
+    XCTAssertNotNil(e2e())
+  }
+
+  func testE2EWhenNotSet() throws {
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getE2E = { nil }
+    let e2e: MessengerE2E = .live(env)
+
+    XCTAssertNil(e2e())
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerUDTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerUDTests.swift
new file mode 100644
index 00000000..0166a8bb
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerUDTests.swift
@@ -0,0 +1,21 @@
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+
+final class MessengerUDTests: XCTestCase {
+  func testUD() throws {
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getE2E = { .unimplemented }
+    let e2e: MessengerE2E = .live(env)
+
+    XCTAssertNotNil(e2e())
+  }
+
+  func testE2EWhenNotSet() throws {
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getE2E = { nil }
+    let e2e: MessengerE2E = .live(env)
+
+    XCTAssertNil(e2e())
+  }
+}
-- 
GitLab


From 3e48ced0eee9ada01cb8ed21ae80262ab39f1c88 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 18:12:09 +0100
Subject: [PATCH 12/27] Sort imports

---
 .../Messenger/Functors/MessengerCreateTests.swift               | 2 +-
 .../Messenger/Functors/MessengerLogInTests.swift                | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
index ee178d28..2180dda3 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
@@ -1,7 +1,7 @@
+import CustomDump
 import XCTest
 import XXClient
 @testable import XXMessengerClient
-import CustomDump
 
 final class MessengerCreateTests: XCTestCase {
   func testCreate() throws {
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
index 791c28ff..77061ed5 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
@@ -1,7 +1,7 @@
+import CustomDump
 import XCTest
 import XXClient
 @testable import XXMessengerClient
-import CustomDump
 
 final class MessengerLogInTests: XCTestCase {
   func testLogin() throws {
-- 
GitLab


From bc420203f91ba1ea0524efac77f4348886d4fc2a Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 18:27:36 +0100
Subject: [PATCH 13/27] Add MessengerStart functor

---
 .../Messenger/Functors/MessengerStart.swift   | 36 ++++++++++
 .../Messenger/Messenger.swift                 |  3 +
 .../Functors/MessengerStartTests.swift        | 68 +++++++++++++++++++
 3 files changed, 107 insertions(+)
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift

diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift
new file mode 100644
index 00000000..224702b7
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift
@@ -0,0 +1,36 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerStart {
+  public enum Error: Swift.Error {
+    case notLoaded
+  }
+
+  public var run: (Int) throws -> Void
+
+  public func callAsFunction(
+    timeoutMS: Int = 30_000
+  ) throws {
+    try run(timeoutMS)
+  }
+}
+
+extension MessengerStart {
+  public static func live(_ env: MessengerEnvironment) -> MessengerStart {
+    MessengerStart { timeoutMS in
+      guard let cMix = env.ctx.getCMix() else {
+        throw Error.notLoaded
+      }
+      guard cMix.networkFollowerStatus() != .running else {
+        return
+      }
+      try cMix.startNetworkFollower(timeoutMS: timeoutMS)
+    }
+  }
+}
+
+extension MessengerStart {
+  public static let unimplemented = MessengerStart(
+    run: XCTUnimplemented("\(Self.self)")
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
index 12610bd6..5526c59c 100644
--- a/Sources/XXMessengerClient/Messenger/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -8,6 +8,7 @@ public struct Messenger {
   public var create: MessengerCreate
   public var isLoaded: MessengerIsLoaded
   public var load: MessengerLoad
+  public var start: MessengerStart
   public var isConnected: MessengerIsConnected
   public var connect: MessengerConnect
   public var isRegistered: MessengerIsRegistered
@@ -26,6 +27,7 @@ extension Messenger {
       create: .live(env),
       isLoaded: .live(env),
       load: .live(env),
+      start: .live(env),
       isConnected: .live(env),
       connect: .live(env),
       isRegistered: .live(env),
@@ -45,6 +47,7 @@ extension Messenger {
     create: .unimplemented,
     isLoaded: .unimplemented,
     load: .unimplemented,
+    start: .unimplemented,
     isConnected: .unimplemented,
     connect: .unimplemented,
     isRegistered: .unimplemented,
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift
new file mode 100644
index 00000000..1b0f11b4
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift
@@ -0,0 +1,68 @@
+import CustomDump
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+
+final class MessengerStartTests: XCTestCase {
+  func testStart() throws {
+    var didStartNetworkFollower: [Int] = []
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.networkFollowerStatus.run = { .stopped }
+      cMix.startNetworkFollower.run = { timeoutMS in
+        didStartNetworkFollower.append(timeoutMS)
+      }
+      return cMix
+    }
+    let start: MessengerStart = .live(env)
+
+    try start(timeoutMS: 123)
+
+    XCTAssertNoDifference(didStartNetworkFollower, [123])
+  }
+
+  func testStartWhenNotLoaded() {
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = { nil }
+    let start: MessengerStart = .live(env)
+
+    XCTAssertThrowsError(try start()) { error in
+      XCTAssertEqual(
+        error as? MessengerStart.Error,
+        MessengerStart.Error.notLoaded
+      )
+    }
+  }
+
+  func testStartWhenRunning() throws {
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.networkFollowerStatus.run = { .running }
+      return cMix
+    }
+    let start: MessengerStart = .live(env)
+
+    try start()
+  }
+
+  func testStartNetworkFollowerFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.networkFollowerStatus.run = { .stopped }
+      cMix.startNetworkFollower.run = { _ in throw error }
+      return cMix
+    }
+    let start: MessengerStart = .live(env)
+
+    XCTAssertThrowsError(try start()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+  }
+}
-- 
GitLab


From 50d75ed3360b8f95599ae7038b110516ba34910a Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 18:42:21 +0100
Subject: [PATCH 14/27] Add MessengerWaitForNetwork functor

---
 .../Functors/MessengerWaitForNetwork.swift    | 36 ++++++++++++
 .../Messenger/Messenger.swift                 |  7 ++-
 .../MessengerWaitForNetworkTests.swift        | 55 +++++++++++++++++++
 3 files changed, 96 insertions(+), 2 deletions(-)
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift

diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift
new file mode 100644
index 00000000..df8fea18
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift
@@ -0,0 +1,36 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerWaitForNetwork {
+  public enum Error: Swift.Error {
+    case notLoaded
+    case timeout
+  }
+
+  public var run: (Int) throws -> Void
+
+  public func callAsFunction(
+    timeoutMS: Int = 30_000
+  ) throws {
+    try run(timeoutMS)
+  }
+}
+
+extension MessengerWaitForNetwork {
+  public static func live(_ env: MessengerEnvironment) -> MessengerWaitForNetwork {
+    MessengerWaitForNetwork { timeoutMS in
+      guard let cMix = env.ctx.getCMix() else {
+        throw Error.notLoaded
+      }
+      guard cMix.waitForNetwork(timeoutMS: timeoutMS) else {
+        throw Error.timeout
+      }
+    }
+  }
+}
+
+extension MessengerWaitForNetwork {
+  public static let unimplemented = MessengerWaitForNetwork(
+    run: XCTUnimplemented("\(Self.self)")
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
index 5526c59c..959aff7f 100644
--- a/Sources/XXMessengerClient/Messenger/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -15,6 +15,7 @@ public struct Messenger {
   public var register: MessengerRegister
   public var isLoggedIn: MessengerIsLoggedIn
   public var logIn: MessengerLogIn
+  public var waitForNetwork: MessengerWaitForNetwork
 }
 
 extension Messenger {
@@ -33,7 +34,8 @@ extension Messenger {
       isRegistered: .live(env),
       register: .live(env),
       isLoggedIn: .live(env),
-      logIn: .live(env)
+      logIn: .live(env),
+      waitForNetwork: .live(env)
     )
   }
 }
@@ -53,6 +55,7 @@ extension Messenger {
     isRegistered: .unimplemented,
     register: .unimplemented,
     isLoggedIn: .unimplemented,
-    logIn: .unimplemented
+    logIn: .unimplemented,
+    waitForNetwork: .unimplemented
   )
 }
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift
new file mode 100644
index 00000000..9e489226
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift
@@ -0,0 +1,55 @@
+import CustomDump
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+
+final class MessengerWaitForNetworkTests: XCTestCase {
+  func testWaitSuccess() throws {
+    var didWaitForNetwork: [Int] = []
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.waitForNetwork.run = { timeoutMS in
+        didWaitForNetwork.append(timeoutMS)
+        return true
+      }
+      return cMix
+    }
+    let waitForNetwork: MessengerWaitForNetwork = .live(env)
+
+    try waitForNetwork(timeoutMS: 123)
+
+    XCTAssertNoDifference(didWaitForNetwork, [123])
+  }
+
+  func testWaitWhenNotLoaded() {
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = { nil }
+    let waitForNetwork: MessengerWaitForNetwork = .live(env)
+
+    XCTAssertThrowsError(try waitForNetwork()) { error in
+      XCTAssertEqual(
+        error as? MessengerWaitForNetwork.Error,
+        MessengerWaitForNetwork.Error.notLoaded
+      )
+    }
+  }
+
+  func testWaitTimeout() {
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.waitForNetwork.run = { _ in false }
+      return cMix
+    }
+    let waitForNetwork: MessengerWaitForNetwork = .live(env)
+
+    XCTAssertThrowsError(try waitForNetwork()) { error in
+      XCTAssertEqual(
+        error as? MessengerWaitForNetwork.Error,
+        MessengerWaitForNetwork.Error.timeout
+      )
+    }
+  }
+}
-- 
GitLab


From efb3ba76e4324c3caf2a960e3c48e23e4133df16 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 19:23:08 +0100
Subject: [PATCH 15/27] Add MessengerWaitForNodes functor

---
 .../Functors/MessengerWaitForNodes.swift      |  57 +++++++++
 .../Messenger/Messenger.swift                 |   7 +-
 .../Messenger/MessengerEnvironment.swift      |   3 +
 .../Functors/MessengerWaitForNodesTests.swift | 108 ++++++++++++++++++
 4 files changed, 173 insertions(+), 2 deletions(-)
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift

diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
new file mode 100644
index 00000000..39048a37
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
@@ -0,0 +1,57 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerWaitForNodes {
+  public typealias Progress = (Double) -> Void
+
+  public enum Error: Swift.Error {
+    case notLoaded
+    case timeout
+  }
+
+  public var run: (Double, Int, Int, @escaping Progress) throws -> Void
+
+  public func callAsFunction(
+    targetRatio: Double = 0.8,
+    sleepMS: Int = 1_000,
+    retries: Int = 10,
+    onProgress: @escaping Progress = { _ in }
+  ) throws {
+    try run(targetRatio, sleepMS, retries, onProgress)
+  }
+}
+
+extension MessengerWaitForNodes {
+  public static func live(_ env: MessengerEnvironment) -> MessengerWaitForNodes {
+    MessengerWaitForNodes { targetRatio, sleepMS, retries, onProgress in
+      guard let cMix = env.ctx.getCMix() else {
+        throw Error.notLoaded
+      }
+
+      func getProgress(_ report: NodeRegistrationReport) -> Double {
+        min(1, ((report.ratio / targetRatio) * 100).rounded() / 100)
+      }
+
+      var report = try cMix.getNodeRegistrationStatus()
+      var retries = retries
+      onProgress(getProgress(report))
+
+      while report.ratio < targetRatio && retries > 0 {
+        env.sleep(sleepMS)
+        retries -= 1
+        report = try cMix.getNodeRegistrationStatus()
+        onProgress(getProgress(report))
+      }
+
+      if report.ratio < targetRatio {
+        throw Error.timeout
+      }
+    }
+  }
+}
+
+extension MessengerWaitForNodes {
+  public static let unimplemented = MessengerWaitForNodes(
+    run: XCTUnimplemented("\(Self.self)")
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
index 959aff7f..5a442ac9 100644
--- a/Sources/XXMessengerClient/Messenger/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -16,6 +16,7 @@ public struct Messenger {
   public var isLoggedIn: MessengerIsLoggedIn
   public var logIn: MessengerLogIn
   public var waitForNetwork: MessengerWaitForNetwork
+  public var waitForNodes: MessengerWaitForNodes
 }
 
 extension Messenger {
@@ -35,7 +36,8 @@ extension Messenger {
       register: .live(env),
       isLoggedIn: .live(env),
       logIn: .live(env),
-      waitForNetwork: .live(env)
+      waitForNetwork: .live(env),
+      waitForNodes: .live(env)
     )
   }
 }
@@ -56,6 +58,7 @@ extension Messenger {
     register: .unimplemented,
     isLoggedIn: .unimplemented,
     logIn: .unimplemented,
-    waitForNetwork: .unimplemented
+    waitForNetwork: .unimplemented,
+    waitForNodes: .unimplemented
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
index b3009ae0..eb7646f3 100644
--- a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
+++ b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
@@ -16,6 +16,7 @@ public struct MessengerEnvironment {
   public var newCMix: NewCMix
   public var newOrLoadUd: NewOrLoadUd
   public var passwordStorage: PasswordStorage
+  public var sleep: (Int) -> Void
   public var storageDir: String
   public var udAddress: String?
   public var udCert: Data?
@@ -44,6 +45,7 @@ extension MessengerEnvironment {
       newCMix: .live,
       newOrLoadUd: .live,
       passwordStorage: .keychain,
+      sleep: { Foundation.sleep(UInt32($0)) },
       storageDir: MessengerEnvironment.defaultStorageDir,
       udAddress: nil,
       udCert: nil,
@@ -67,6 +69,7 @@ extension MessengerEnvironment {
     newCMix: .unimplemented,
     newOrLoadUd: .unimplemented,
     passwordStorage: .unimplemented,
+    sleep: XCTUnimplemented("\(Self.self).sleep"),
     storageDir: "unimplemented",
     udAddress: nil,
     udCert: nil,
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift
new file mode 100644
index 00000000..3154758f
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift
@@ -0,0 +1,108 @@
+import CustomDump
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+
+final class MessengerWaitForNodesTests: XCTestCase {
+  func testWaitWhenNotLoaded() {
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = { nil }
+    let waitForNodes: MessengerWaitForNodes = .live(env)
+
+    XCTAssertThrowsError(try waitForNodes()) { error in
+      XCTAssertEqual(
+        error as? MessengerWaitForNodes.Error,
+        MessengerWaitForNodes.Error.notLoaded
+      )
+    }
+  }
+
+  func testWaitWhenHasTargetRatio() throws {
+    var didProgress: [Double] = []
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.getNodeRegistrationStatus.run = {
+        NodeRegistrationReport(registered: 8, total: 10)
+      }
+      return cMix
+    }
+    let waitForNodes: MessengerWaitForNodes = .live(env)
+
+    try waitForNodes(
+      targetRatio: 0.7,
+      sleepMS: 123,
+      retries: 3,
+      onProgress: { didProgress.append($0) }
+    )
+
+    XCTAssertNoDifference(didProgress, [1])
+  }
+
+  func testWaitForTargetRatio() throws {
+    var didSleep: [Int] = []
+    var didProgress: [Double] = []
+
+    var reports: [NodeRegistrationReport] = [
+      .init(registered: 0, total: 10),
+      .init(registered: 3, total: 10),
+      .init(registered: 8, total: 10),
+    ]
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.getNodeRegistrationStatus.run = { reports.removeFirst() }
+      return cMix
+    }
+    env.sleep = { didSleep.append($0) }
+    let waitForNodes: MessengerWaitForNodes = .live(env)
+
+    try waitForNodes(
+      targetRatio: 0.7,
+      sleepMS: 123,
+      retries: 3,
+      onProgress: { didProgress.append($0) }
+    )
+
+    XCTAssertNoDifference(didSleep, [123, 123])
+    XCTAssertNoDifference(didProgress, [0, 0.43, 1])
+  }
+
+  func testWaitTimeout() {
+    var didSleep: [Int] = []
+    var didProgress: [Double] = []
+
+    var reports: [NodeRegistrationReport] = [
+      .init(registered: 0, total: 10),
+      .init(registered: 3, total: 10),
+      .init(registered: 5, total: 10),
+      .init(registered: 6, total: 10),
+    ]
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ctx.getCMix = {
+      var cMix: CMix = .unimplemented
+      cMix.getNodeRegistrationStatus.run = { reports.removeFirst() }
+      return cMix
+    }
+    env.sleep = { didSleep.append($0) }
+    let waitForNodes: MessengerWaitForNodes = .live(env)
+
+    XCTAssertThrowsError(try waitForNodes(
+      targetRatio: 0.7,
+      sleepMS: 123,
+      retries: 3,
+      onProgress: { didProgress.append($0) }
+    )) { error in
+      XCTAssertEqual(
+        error as? MessengerWaitForNodes.Error,
+        MessengerWaitForNodes.Error.timeout
+      )
+    }
+
+    XCTAssertNoDifference(didSleep, [123, 123, 123])
+    XCTAssertNoDifference(didProgress, [0, 0.43, 0.71, 0.86])
+  }
+}
-- 
GitLab


From 11d7fe882b1c3b89a15d2aa84718178ca1279073 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 19:24:18 +0100
Subject: [PATCH 16/27] Refactor

---
 Sources/XXMessengerClient/Messenger/Messenger.swift | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
index 5a442ac9..beab992d 100644
--- a/Sources/XXMessengerClient/Messenger/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -8,9 +8,9 @@ public struct Messenger {
   public var create: MessengerCreate
   public var isLoaded: MessengerIsLoaded
   public var load: MessengerLoad
-  public var start: MessengerStart
   public var isConnected: MessengerIsConnected
   public var connect: MessengerConnect
+  public var start: MessengerStart
   public var isRegistered: MessengerIsRegistered
   public var register: MessengerRegister
   public var isLoggedIn: MessengerIsLoggedIn
@@ -29,9 +29,9 @@ extension Messenger {
       create: .live(env),
       isLoaded: .live(env),
       load: .live(env),
-      start: .live(env),
       isConnected: .live(env),
       connect: .live(env),
+      start: .live(env),
       isRegistered: .live(env),
       register: .live(env),
       isLoggedIn: .live(env),
@@ -51,9 +51,9 @@ extension Messenger {
     create: .unimplemented,
     isLoaded: .unimplemented,
     load: .unimplemented,
-    start: .unimplemented,
     isConnected: .unimplemented,
     connect: .unimplemented,
+    start: .unimplemented,
     isRegistered: .unimplemented,
     register: .unimplemented,
     isLoggedIn: .unimplemented,
-- 
GitLab


From 4689bc1bc895c689d460eebc675a637e5ee17bd5 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 19:29:02 +0100
Subject: [PATCH 17/27] Don't start network follower on logIn/register

---
 .../Messenger/Functors/MessengerLogIn.swift   |  3 ---
 .../Functors/MessengerRegister.swift          |  3 ---
 .../Functors/MessengerLogInTests.swift        | 24 -------------------
 .../Functors/MessengerRegisterTests.swift     | 24 -------------------
 4 files changed, 54 deletions(-)

diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
index 31323e9f..51e970d5 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
@@ -23,9 +23,6 @@ extension MessengerLogIn {
       guard let e2e = env.ctx.getE2E() else {
         throw Error.notConnected
       }
-      if cMix.networkFollowerStatus() != .running {
-        try cMix.startNetworkFollower(timeoutMS: 30_000)
-      }
       env.ctx.setUD(try env.newOrLoadUd(
         params: .init(
           e2eId: e2e.getId(),
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
index 0fdddac8..35450762 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
@@ -25,9 +25,6 @@ extension MessengerRegister {
       guard let e2e = env.ctx.getE2E() else {
         throw Error.notConnected
       }
-      if cMix.networkFollowerStatus() != .running {
-        try cMix.startNetworkFollower(timeoutMS: 30_000)
-      }
       env.ctx.setUD(try env.newOrLoadUd(
         params: .init(
           e2eId: e2e.getId(),
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
index 77061ed5..3186d0ac 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
@@ -5,7 +5,6 @@ import XXClient
 
 final class MessengerLogInTests: XCTestCase {
   func testLogin() throws {
-    var didStartNetworkFollower: [Int] = []
     var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
     var didNewOrLoadUDWithFollower: [UdNetworkStatus] = []
     var didSetUD: [UserDiscovery?] = []
@@ -20,9 +19,6 @@ final class MessengerLogInTests: XCTestCase {
     env.ctx.getCMix = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { networkFollowerStatus }
-      cMix.startNetworkFollower.run = { timeout in
-        didStartNetworkFollower.append(timeout)
-      }
       return cMix
     }
     env.ctx.getE2E = {
@@ -45,7 +41,6 @@ final class MessengerLogInTests: XCTestCase {
     let logIn: MessengerLogIn = .live(env)
     try logIn()
 
-    XCTAssertEqual(didStartNetworkFollower, [30_000])
     XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
       e2eId: e2eId,
       username: nil,
@@ -131,25 +126,6 @@ final class MessengerLogInTests: XCTestCase {
     }
   }
 
-  func testStartNetworkFollowerFailure() {
-    struct Error: Swift.Error, Equatable {}
-    let error = Error()
-
-    var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
-      var cMix: CMix = .unimplemented
-      cMix.networkFollowerStatus.run = { .stopped }
-      cMix.startNetworkFollower.run = { _ in throw error }
-      return cMix
-    }
-    env.ctx.getE2E = { .unimplemented }
-    let logIn: MessengerLogIn = .live(env)
-
-    XCTAssertThrowsError(try logIn()) { err in
-      XCTAssertEqual(err as? Error, error)
-    }
-  }
-
   func testGetUdContactFromNdfFailure() {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
index 8feb8a7c..82f2527b 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
@@ -5,7 +5,6 @@ import XXClient
 
 final class MessengerRegisterTests: XCTestCase {
   func testRegister() throws {
-    var didStartNetworkFollower: [Int] = []
     var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
     var didNewOrLoadUDWithFollower: [UdNetworkStatus] = []
     var didSetUD: [UserDiscovery?] = []
@@ -22,9 +21,6 @@ final class MessengerRegisterTests: XCTestCase {
     env.ctx.getCMix = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { networkFollowerStatus }
-      cMix.startNetworkFollower.run = { timeout in
-        didStartNetworkFollower.append(timeout)
-      }
       cMix.getReceptionRegistrationValidationSignature.run = {
         registrationSignature
       }
@@ -50,7 +46,6 @@ final class MessengerRegisterTests: XCTestCase {
     let register: MessengerRegister = .live(env)
     try register(username: username)
 
-    XCTAssertEqual(didStartNetworkFollower, [30_000])
     XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
       e2eId: e2eId,
       username: username,
@@ -141,25 +136,6 @@ final class MessengerRegisterTests: XCTestCase {
     }
   }
 
-  func testStartNetworkFollowerFailure() {
-    struct Error: Swift.Error, Equatable {}
-    let error = Error()
-
-    var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
-      var cMix: CMix = .unimplemented
-      cMix.networkFollowerStatus.run = { .stopped }
-      cMix.startNetworkFollower.run = { _ in throw error }
-      return cMix
-    }
-    env.ctx.getE2E = { .unimplemented }
-    let register: MessengerRegister = .live(env)
-
-    XCTAssertThrowsError(try register(username: "new-user-name")) { err in
-      XCTAssertEqual(err as? Error, error)
-    }
-  }
-
   func testGetUdContactFromNdfFailure() {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
-- 
GitLab


From 1a3ada6c6ffd29af3268a98f11d77c86b9c05fb3 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 19:31:47 +0100
Subject: [PATCH 18/27] Refactor

---
 Sources/XXMessengerClient/Messenger/Messenger.swift | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
index beab992d..5a442ac9 100644
--- a/Sources/XXMessengerClient/Messenger/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -8,9 +8,9 @@ public struct Messenger {
   public var create: MessengerCreate
   public var isLoaded: MessengerIsLoaded
   public var load: MessengerLoad
+  public var start: MessengerStart
   public var isConnected: MessengerIsConnected
   public var connect: MessengerConnect
-  public var start: MessengerStart
   public var isRegistered: MessengerIsRegistered
   public var register: MessengerRegister
   public var isLoggedIn: MessengerIsLoggedIn
@@ -29,9 +29,9 @@ extension Messenger {
       create: .live(env),
       isLoaded: .live(env),
       load: .live(env),
+      start: .live(env),
       isConnected: .live(env),
       connect: .live(env),
-      start: .live(env),
       isRegistered: .live(env),
       register: .live(env),
       isLoggedIn: .live(env),
@@ -51,9 +51,9 @@ extension Messenger {
     create: .unimplemented,
     isLoaded: .unimplemented,
     load: .unimplemented,
+    start: .unimplemented,
     isConnected: .unimplemented,
     connect: .unimplemented,
-    start: .unimplemented,
     isRegistered: .unimplemented,
     register: .unimplemented,
     isLoggedIn: .unimplemented,
-- 
GitLab


From b5c764aea0b93497cd708f6a6e7e03604c41c7a8 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 19:32:01 +0100
Subject: [PATCH 19/27] Update docs

---
 Docs/XXMessengerClient.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Docs/XXMessengerClient.md b/Docs/XXMessengerClient.md
index d4a634a9..2dc19246 100644
--- a/Docs/XXMessengerClient.md
+++ b/Docs/XXMessengerClient.md
@@ -39,6 +39,9 @@ func start(messenger: Messenger) throws {
     try messenger.load()
   }
 
+  // start messenger's network follower:
+  try messenger.start()
+
   // check if messenger is connected:
   if messenger.isConnected() == false {
     // start end-to-end connection:
-- 
GitLab


From f3e9c45ed402429ba593b096eb8c3c459e953349 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 19:46:29 +0100
Subject: [PATCH 20/27] Update MessengerWaitForNodes.Progress callback

---
 .../Functors/MessengerWaitForNodes.swift      | 12 ++++------
 .../Functors/MessengerWaitForNodesTests.swift | 23 ++++++++++++++-----
 2 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
index 39048a37..8fc11899 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
@@ -2,7 +2,7 @@ import XXClient
 import XCTestDynamicOverlay
 
 public struct MessengerWaitForNodes {
-  public typealias Progress = (Double) -> Void
+  public typealias Progress = (NodeRegistrationReport) -> Void
 
   public enum Error: Swift.Error {
     case notLoaded
@@ -28,19 +28,15 @@ extension MessengerWaitForNodes {
         throw Error.notLoaded
       }
 
-      func getProgress(_ report: NodeRegistrationReport) -> Double {
-        min(1, ((report.ratio / targetRatio) * 100).rounded() / 100)
-      }
-
       var report = try cMix.getNodeRegistrationStatus()
       var retries = retries
-      onProgress(getProgress(report))
+      onProgress(report)
 
       while report.ratio < targetRatio && retries > 0 {
         env.sleep(sleepMS)
-        retries -= 1
         report = try cMix.getNodeRegistrationStatus()
-        onProgress(getProgress(report))
+        retries -= 1
+        onProgress(report)
       }
 
       if report.ratio < targetRatio {
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift
index 3154758f..ba1fd941 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift
@@ -18,7 +18,7 @@ final class MessengerWaitForNodesTests: XCTestCase {
   }
 
   func testWaitWhenHasTargetRatio() throws {
-    var didProgress: [Double] = []
+    var didProgress: [NodeRegistrationReport] = []
 
     var env: MessengerEnvironment = .unimplemented
     env.ctx.getCMix = {
@@ -37,12 +37,14 @@ final class MessengerWaitForNodesTests: XCTestCase {
       onProgress: { didProgress.append($0) }
     )
 
-    XCTAssertNoDifference(didProgress, [1])
+    XCTAssertNoDifference(didProgress, [
+      NodeRegistrationReport(registered: 8, total: 10)
+    ])
   }
 
   func testWaitForTargetRatio() throws {
     var didSleep: [Int] = []
-    var didProgress: [Double] = []
+    var didProgress: [NodeRegistrationReport] = []
 
     var reports: [NodeRegistrationReport] = [
       .init(registered: 0, total: 10),
@@ -67,12 +69,16 @@ final class MessengerWaitForNodesTests: XCTestCase {
     )
 
     XCTAssertNoDifference(didSleep, [123, 123])
-    XCTAssertNoDifference(didProgress, [0, 0.43, 1])
+    XCTAssertNoDifference(didProgress, [
+      NodeRegistrationReport(registered: 0, total: 10),
+      NodeRegistrationReport(registered: 3, total: 10),
+      NodeRegistrationReport(registered: 8, total: 10),
+    ])
   }
 
   func testWaitTimeout() {
     var didSleep: [Int] = []
-    var didProgress: [Double] = []
+    var didProgress: [NodeRegistrationReport] = []
 
     var reports: [NodeRegistrationReport] = [
       .init(registered: 0, total: 10),
@@ -103,6 +109,11 @@ final class MessengerWaitForNodesTests: XCTestCase {
     }
 
     XCTAssertNoDifference(didSleep, [123, 123, 123])
-    XCTAssertNoDifference(didProgress, [0, 0.43, 0.71, 0.86])
+    XCTAssertNoDifference(didProgress, [
+      NodeRegistrationReport(registered: 0, total: 10),
+      NodeRegistrationReport(registered: 3, total: 10),
+      NodeRegistrationReport(registered: 5, total: 10),
+      NodeRegistrationReport(registered: 6, total: 10),
+    ])
   }
 }
-- 
GitLab


From edf8b68aacf28ef139b0cbbb3177da228b669461 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Mon, 22 Aug 2022 21:33:09 +0100
Subject: [PATCH 21/27] Refactor

Remove MessengerContext
---
 .../Messenger/Functors/MessengerCMix.swift    | 17 +++++---
 .../Messenger/Functors/MessengerConnect.swift |  4 +-
 .../Messenger/Functors/MessengerE2E.swift     | 17 +++++---
 .../Functors/MessengerIsConnected.swift       |  2 +-
 .../Functors/MessengerIsLoaded.swift          |  2 +-
 .../Functors/MessengerIsLoggedIn.swift        |  2 +-
 .../Functors/MessengerIsRegistered.swift      |  2 +-
 .../Messenger/Functors/MessengerLoad.swift    |  2 +-
 .../Messenger/Functors/MessengerLogIn.swift   |  6 +--
 .../Functors/MessengerRegister.swift          |  6 +--
 .../Messenger/Functors/MessengerStart.swift   |  2 +-
 .../Messenger/Functors/MessengerUD.swift      | 17 +++++---
 .../Functors/MessengerWaitForNetwork.swift    |  2 +-
 .../Functors/MessengerWaitForNodes.swift      |  2 +-
 .../Messenger/Messenger.swift                 |  6 +--
 .../Messenger/MessengerContext.swift          | 42 -------------------
 .../Messenger/MessengerEnvironment.swift      | 12 ++++--
 .../Functors/MessengerCMixTests.swift         | 14 +++----
 .../Functors/MessengerConnectTests.swift      | 10 ++---
 .../Functors/MessengerE2ETests.swift          | 14 +++----
 .../Functors/MessengerIsConnectedTests.swift  |  4 +-
 .../Functors/MessengerIsLoadedTests.swift     |  4 +-
 .../Functors/MessengerIsLoggedInTests.swift   |  4 +-
 .../Functors/MessengerIsRegisteredTests.swift |  8 ++--
 .../Functors/MessengerLoadTests.swift         |  2 +-
 .../Functors/MessengerLogInTests.swift        | 26 ++++++------
 .../Functors/MessengerRegisterTests.swift     | 26 ++++++------
 .../Functors/MessengerStartTests.swift        |  8 ++--
 .../Messenger/Functors/MessengerUDTests.swift | 18 ++++----
 .../MessengerWaitForNetworkTests.swift        |  6 +--
 .../Functors/MessengerWaitForNodesTests.swift |  8 ++--
 31 files changed, 137 insertions(+), 158 deletions(-)
 delete mode 100644 Sources/XXMessengerClient/Messenger/MessengerContext.swift

diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerCMix.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerCMix.swift
index 5543c048..d3e062d2 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerCMix.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerCMix.swift
@@ -2,21 +2,28 @@ import XXClient
 import XCTestDynamicOverlay
 
 public struct MessengerCMix {
-  public var run: () -> CMix?
+  public var get: () -> CMix?
+  public var set: (CMix?) -> Void
 
   public func callAsFunction() -> CMix? {
-    run()
+    get()
   }
 }
 
 extension MessengerCMix {
-  public static func live(_ env: MessengerEnvironment) -> MessengerCMix {
-    MessengerCMix(run: env.ctx.getCMix)
+  public static func live() -> MessengerCMix {
+    class Storage { var value: CMix? }
+    let storage = Storage()
+    return MessengerCMix(
+      get: { storage.value },
+      set: { storage.value = $0 }
+    )
   }
 }
 
 extension MessengerCMix {
   public static let unimplemented = MessengerCMix(
-    run: XCTUnimplemented("\(Self.self)", placeholder: nil)
+    get: XCTUnimplemented("\(Self.self).get", placeholder: nil),
+    set: XCTUnimplemented("\(Self.self).set")
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
index 97e399ab..8cebb73a 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
@@ -16,10 +16,10 @@ public struct MessengerConnect {
 extension MessengerConnect {
   public static func live(_ env: MessengerEnvironment) -> MessengerConnect {
     MessengerConnect {
-      guard let cMix = env.ctx.getCMix() else {
+      guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
-      env.ctx.setE2E(try env.login(
+      env.e2e.set(try env.login(
         cMixId: cMix.getId(),
         identity: try cMix.makeLegacyReceptionIdentity(),
         e2eParamsJSON: env.getE2EParams()
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerE2E.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerE2E.swift
index cc1f8def..070a6b70 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerE2E.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerE2E.swift
@@ -2,21 +2,28 @@ import XXClient
 import XCTestDynamicOverlay
 
 public struct MessengerE2E {
-  public var run: () -> E2E?
+  public var get: () -> E2E?
+  public var set: (E2E?) -> Void
 
   public func callAsFunction() -> E2E? {
-    run()
+    get()
   }
 }
 
 extension MessengerE2E {
-  public static func live(_ env: MessengerEnvironment) -> MessengerE2E {
-    MessengerE2E(run: env.ctx.getE2E)
+  public static func live() -> MessengerE2E {
+    class Storage { var value: E2E? }
+    let storage = Storage()
+    return MessengerE2E(
+      get: { storage.value },
+      set: { storage.value = $0 }
+    )
   }
 }
 
 extension MessengerE2E {
   public static let unimplemented = MessengerE2E(
-    run: XCTUnimplemented("\(Self.self)", placeholder: nil)
+    get: XCTUnimplemented("\(Self.self).get", placeholder: nil),
+    set: XCTUnimplemented("\(Self.self).set")
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
index 81017429..c30437fa 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
@@ -12,7 +12,7 @@ public struct MessengerIsConnected {
 extension MessengerIsConnected {
   public static func live(_ env: MessengerEnvironment) -> MessengerIsConnected {
     MessengerIsConnected {
-      env.ctx.getE2E() != nil
+      env.e2e() != nil
     }
   }
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
index 8931d2b4..dc0b4216 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
@@ -12,7 +12,7 @@ public struct MessengerIsLoaded {
 extension MessengerIsLoaded {
   public static func live(_ env: MessengerEnvironment) -> MessengerIsLoaded {
     MessengerIsLoaded {
-      env.ctx.getCMix() != nil
+      env.cMix() != nil
     }
   }
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
index 04aaa338..7c54c578 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
@@ -12,7 +12,7 @@ public struct MessengerIsLoggedIn {
 extension MessengerIsLoggedIn {
   public static func live(_ env: MessengerEnvironment) -> MessengerIsLoggedIn {
     MessengerIsLoggedIn {
-      env.ctx.getUD() != nil
+      env.ud() != nil
     }
   }
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
index cbf02c8a..bf3cafa5 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
@@ -16,7 +16,7 @@ public struct MessengerIsRegistered {
 extension MessengerIsRegistered {
   public static func live(_ env: MessengerEnvironment) -> MessengerIsRegistered {
     MessengerIsRegistered {
-      guard let e2e = env.ctx.getE2E() else {
+      guard let e2e = env.e2e() else {
         throw Error.notConnected
       }
       return try env.isRegisteredWithUD(e2eId: e2e.getId())
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
index c57d7a5a..29f28168 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
@@ -12,7 +12,7 @@ public struct MessengerLoad {
 extension MessengerLoad {
   public static func live(_ env: MessengerEnvironment) -> MessengerLoad {
     MessengerLoad {
-      env.ctx.setCMix(try env.loadCMix(
+      env.cMix.set(try env.loadCMix(
         storageDir: env.storageDir,
         password: try env.passwordStorage.load(),
         cMixParamsJSON: env.getCMixParams()
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
index 51e970d5..d0f86d8b 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
@@ -17,13 +17,13 @@ public struct MessengerLogIn {
 extension MessengerLogIn {
   public static func live(_ env: MessengerEnvironment) -> MessengerLogIn {
     MessengerLogIn {
-      guard let cMix = env.ctx.getCMix() else {
+      guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
-      guard let e2e = env.ctx.getE2E() else {
+      guard let e2e = env.e2e() else {
         throw Error.notConnected
       }
-      env.ctx.setUD(try env.newOrLoadUd(
+      env.ud.set(try env.newOrLoadUd(
         params: .init(
           e2eId: e2e.getId(),
           username: nil,
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
index 35450762..6f429631 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
@@ -19,13 +19,13 @@ public struct MessengerRegister {
 extension MessengerRegister {
   public static func live(_ env: MessengerEnvironment) -> MessengerRegister {
     MessengerRegister { username in
-      guard let cMix = env.ctx.getCMix() else {
+      guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
-      guard let e2e = env.ctx.getE2E() else {
+      guard let e2e = env.e2e() else {
         throw Error.notConnected
       }
-      env.ctx.setUD(try env.newOrLoadUd(
+      env.ud.set(try env.newOrLoadUd(
         params: .init(
           e2eId: e2e.getId(),
           username: username,
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift
index 224702b7..cc3363ec 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift
@@ -18,7 +18,7 @@ public struct MessengerStart {
 extension MessengerStart {
   public static func live(_ env: MessengerEnvironment) -> MessengerStart {
     MessengerStart { timeoutMS in
-      guard let cMix = env.ctx.getCMix() else {
+      guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
       guard cMix.networkFollowerStatus() != .running else {
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerUD.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerUD.swift
index c64ee6cf..c871f6e0 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerUD.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerUD.swift
@@ -2,21 +2,28 @@ import XXClient
 import XCTestDynamicOverlay
 
 public struct MessengerUD {
-  public var run: () -> UserDiscovery?
+  public var get: () -> UserDiscovery?
+  public var set: (UserDiscovery?) -> Void
 
   public func callAsFunction() -> UserDiscovery? {
-    run()
+    get()
   }
 }
 
 extension MessengerUD {
-  public static func live(_ env: MessengerEnvironment) -> MessengerUD {
-    MessengerUD(run: env.ctx.getUD)
+  public static func live() -> MessengerUD {
+    class Storage { var value: UserDiscovery? }
+    let storage = Storage()
+    return MessengerUD(
+      get: { storage.value },
+      set: { storage.value = $0 }
+    )
   }
 }
 
 extension MessengerUD {
   public static let unimplemented = MessengerUD(
-    run: XCTUnimplemented("\(Self.self)", placeholder: nil)
+    get: XCTUnimplemented("\(Self.self).get", placeholder: nil),
+    set: XCTUnimplemented("\(Self.self).set")
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift
index df8fea18..8fe8cf3e 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift
@@ -19,7 +19,7 @@ public struct MessengerWaitForNetwork {
 extension MessengerWaitForNetwork {
   public static func live(_ env: MessengerEnvironment) -> MessengerWaitForNetwork {
     MessengerWaitForNetwork { timeoutMS in
-      guard let cMix = env.ctx.getCMix() else {
+      guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
       guard cMix.waitForNetwork(timeoutMS: timeoutMS) else {
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
index 8fc11899..b87acc2f 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
@@ -24,7 +24,7 @@ public struct MessengerWaitForNodes {
 extension MessengerWaitForNodes {
   public static func live(_ env: MessengerEnvironment) -> MessengerWaitForNodes {
     MessengerWaitForNodes { targetRatio, sleepMS, retries, onProgress in
-      guard let cMix = env.ctx.getCMix() else {
+      guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
 
diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
index 5a442ac9..397c8e84 100644
--- a/Sources/XXMessengerClient/Messenger/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -22,9 +22,9 @@ public struct Messenger {
 extension Messenger {
   public static func live(_ env: MessengerEnvironment) -> Messenger {
     Messenger(
-      cMix: .live(env),
-      e2e: .live(env),
-      ud: .live(env),
+      cMix: env.cMix,
+      e2e: env.e2e,
+      ud: env.ud,
       isCreated: .live(env),
       create: .live(env),
       isLoaded: .live(env),
diff --git a/Sources/XXMessengerClient/Messenger/MessengerContext.swift b/Sources/XXMessengerClient/Messenger/MessengerContext.swift
deleted file mode 100644
index c98523f2..00000000
--- a/Sources/XXMessengerClient/Messenger/MessengerContext.swift
+++ /dev/null
@@ -1,42 +0,0 @@
-import XXClient
-import XCTestDynamicOverlay
-
-public struct MessengerContext {
-  public var getCMix: () -> CMix?
-  public var setCMix: (CMix?) -> Void
-  public var getE2E: () -> E2E?
-  public var setE2E: (E2E?) -> Void
-  public var getUD: () -> UserDiscovery?
-  public var setUD: (UserDiscovery?) -> Void
-}
-
-extension MessengerContext {
-  public static func live() -> MessengerContext {
-    class Container {
-      var cMix: CMix?
-      var e2e: E2E?
-      var ud: UserDiscovery?
-    }
-    let container = Container()
-
-    return MessengerContext(
-      getCMix: { container.cMix },
-      setCMix: { container.cMix = $0 },
-      getE2E: { container.e2e },
-      setE2E: { container.e2e = $0 },
-      getUD: { container.ud },
-      setUD: { container.ud = $0 }
-    )
-  }
-}
-
-extension MessengerContext {
-  public static let unimplemented = MessengerContext(
-    getCMix: XCTUnimplemented("\(Self.self).getCMix"),
-    setCMix: XCTUnimplemented("\(Self.self).setCMix"),
-    getE2E: XCTUnimplemented("\(Self.self).getE2E"),
-    setE2E: XCTUnimplemented("\(Self.self).setE2E"),
-    getUD: XCTUnimplemented("\(Self.self).getUD"),
-    setUD: XCTUnimplemented("\(Self.self).setUD")
-  )
-}
diff --git a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
index eb7646f3..a84a1e87 100644
--- a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
+++ b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
@@ -3,8 +3,9 @@ import XXClient
 import XCTestDynamicOverlay
 
 public struct MessengerEnvironment {
-  public var ctx: MessengerContext
+  public var cMix: MessengerCMix
   public var downloadNDF: DownloadAndVerifySignedNdf
+  public var e2e: MessengerE2E
   public var fileManager: MessengerFileManager
   public var generateSecret: GenerateSecret
   public var getCMixParams: GetCMixParams
@@ -18,6 +19,7 @@ public struct MessengerEnvironment {
   public var passwordStorage: PasswordStorage
   public var sleep: (Int) -> Void
   public var storageDir: String
+  public var ud: MessengerUD
   public var udAddress: String?
   public var udCert: Data?
   public var udContact: Data?
@@ -32,8 +34,9 @@ extension MessengerEnvironment {
 
   public static func live() -> MessengerEnvironment {
     MessengerEnvironment(
-      ctx: .live(),
+      cMix: .live(),
       downloadNDF: .live,
+      e2e: .live(),
       fileManager: .live(),
       generateSecret: .live,
       getCMixParams: .liveDefault,
@@ -47,6 +50,7 @@ extension MessengerEnvironment {
       passwordStorage: .keychain,
       sleep: { Foundation.sleep(UInt32($0)) },
       storageDir: MessengerEnvironment.defaultStorageDir,
+      ud: .live(),
       udAddress: nil,
       udCert: nil,
       udContact: nil
@@ -56,8 +60,9 @@ extension MessengerEnvironment {
 
 extension MessengerEnvironment {
   public static let unimplemented = MessengerEnvironment(
-    ctx: .unimplemented,
+    cMix: .unimplemented,
     downloadNDF: .unimplemented,
+    e2e: .unimplemented,
     fileManager: .unimplemented,
     generateSecret: .unimplemented,
     getCMixParams: .unimplemented,
@@ -71,6 +76,7 @@ extension MessengerEnvironment {
     passwordStorage: .unimplemented,
     sleep: XCTUnimplemented("\(Self.self).sleep"),
     storageDir: "unimplemented",
+    ud: .unimplemented,
     udAddress: nil,
     udCert: nil,
     udContact: nil
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCMixTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCMixTests.swift
index f4327a08..668983f5 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCMixTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCMixTests.swift
@@ -4,17 +4,15 @@ import XXClient
 
 final class MessengerCMixTests: XCTestCase {
   func testCMix() throws {
-    var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = { .unimplemented }
-    let cMix: MessengerCMix = .live(env)
+    let cMix: MessengerCMix = .live()
+
+    XCTAssertNil(cMix())
+
+    cMix.set(.unimplemented)
 
     XCTAssertNotNil(cMix())
-  }
 
-  func testCMixWhenNotSet() throws {
-    var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = { nil }
-    let cMix: MessengerCMix = .live(env)
+    cMix.set(nil)
 
     XCTAssertNil(cMix())
   }
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
index c93e403e..fb780353 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
@@ -21,13 +21,13 @@ final class MessengerConnectTests: XCTestCase {
     let e2eParams = "e2e-params".data(using: .utf8)!
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getId.run = { cMixId }
       cMix.makeLegacyReceptionIdentity.run = { receptionId }
       return cMix
     }
-    env.ctx.setE2E = { didSetE2E.append($0) }
+    env.e2e.set = { didSetE2E.append($0) }
     env.getE2EParams.run = { e2eParams }
     env.login.run = { ephemeral, cMixId, authCallbacks, identity, e2eParamsJSON in
       didLogIn.append(.init(
@@ -57,7 +57,7 @@ final class MessengerConnectTests: XCTestCase {
 
   func testConnectWithoutCMix() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = { nil }
+    env.cMix.get = { nil }
     let connect: MessengerConnect = .live(env)
 
     XCTAssertThrowsError(try connect()) { error in
@@ -73,7 +73,7 @@ final class MessengerConnectTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getId.run = { 1234 }
       cMix.makeLegacyReceptionIdentity.run = { throw error }
@@ -91,7 +91,7 @@ final class MessengerConnectTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getId.run = { 1234 }
       cMix.makeLegacyReceptionIdentity.run = { .stub }
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerE2ETests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerE2ETests.swift
index bb54fb78..63b9f585 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerE2ETests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerE2ETests.swift
@@ -4,17 +4,15 @@ import XXClient
 
 final class MessengerE2ETests: XCTestCase {
   func testE2E() throws {
-    var env: MessengerEnvironment = .unimplemented
-    env.ctx.getE2E = { .unimplemented }
-    let e2e: MessengerE2E = .live(env)
+    let e2e: MessengerE2E = .live()
+
+    XCTAssertNil(e2e())
+
+    e2e.set(.unimplemented)
 
     XCTAssertNotNil(e2e())
-  }
 
-  func testE2EWhenNotSet() throws {
-    var env: MessengerEnvironment = .unimplemented
-    env.ctx.getE2E = { nil }
-    let e2e: MessengerE2E = .live(env)
+    e2e.set(nil)
 
     XCTAssertNil(e2e())
   }
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
index b361170c..c7c5de8b 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
@@ -4,7 +4,7 @@ import XCTest
 final class MessengerIsConnectedTests: XCTestCase {
   func testWithE2E() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getE2E = { .unimplemented }
+    env.e2e.get = { .unimplemented }
     let isConnected: MessengerIsConnected = .live(env)
 
     XCTAssertTrue(isConnected())
@@ -12,7 +12,7 @@ final class MessengerIsConnectedTests: XCTestCase {
 
   func testWithoutE2E() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getE2E = { nil }
+    env.e2e.get = { nil }
     let isConnected: MessengerIsConnected = .live(env)
 
     XCTAssertFalse(isConnected())
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
index a88a1148..6f0591e2 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
@@ -4,7 +4,7 @@ import XCTest
 final class MessengerIsLoadedTests: XCTestCase {
   func testWithCMix() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = { .unimplemented }
+    env.cMix.get = { .unimplemented }
     let isLoaded: MessengerIsLoaded = .live(env)
 
     XCTAssertTrue(isLoaded())
@@ -12,7 +12,7 @@ final class MessengerIsLoadedTests: XCTestCase {
 
   func testWithoutCMix() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = { nil }
+    env.cMix.get = { nil }
     let isLoaded: MessengerIsLoaded = .live(env)
 
     XCTAssertFalse(isLoaded())
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
index 0bbd8867..c6ea87e6 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
@@ -4,7 +4,7 @@ import XCTest
 final class MessengerIsLoggedInTests: XCTestCase {
   func testWithUD() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getUD = { .unimplemented }
+    env.ud.get = { .unimplemented }
     let isLoggedIn: MessengerIsLoggedIn = .live(env)
 
     XCTAssertTrue(isLoggedIn())
@@ -12,7 +12,7 @@ final class MessengerIsLoggedInTests: XCTestCase {
 
   func testWithoutUD() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getUD = { nil }
+    env.ud.get = { nil }
     let isLoggedIn: MessengerIsLoggedIn = .live(env)
 
     XCTAssertFalse(isLoggedIn())
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
index b11bfbc6..b6dca3e9 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
@@ -7,7 +7,7 @@ final class MessengerIsRegisteredTests: XCTestCase {
     var didIsRegisteredWithUD: [Int] = []
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getE2E = {
+    env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { 1234 }
       return e2e
@@ -24,7 +24,7 @@ final class MessengerIsRegisteredTests: XCTestCase {
 
   func testNotRegistered() throws {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getE2E = {
+    env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { 1234 }
       return e2e
@@ -37,7 +37,7 @@ final class MessengerIsRegisteredTests: XCTestCase {
 
   func testWithoutE2E() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getE2E = { nil }
+    env.e2e.get = { nil }
     let isRegistered: MessengerIsRegistered = .live(env)
 
     XCTAssertThrowsError(try isRegistered()) { err in
@@ -53,7 +53,7 @@ final class MessengerIsRegisteredTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getE2E = {
+    env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { 1234 }
       return e2e
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
index eecdca12..5eb90e3a 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
@@ -18,7 +18,7 @@ final class MessengerLoadTests: XCTestCase {
     let cMixParams = "cmix-params".data(using: .utf8)!
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.setCMix = { didSetCMix.append($0) }
+    env.cMix.set = { didSetCMix.append($0) }
     env.storageDir = storageDir
     env.passwordStorage.load = { password }
     env.getCMixParams.run = { cMixParams }
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
index 3186d0ac..83dd2cd0 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
@@ -16,12 +16,12 @@ final class MessengerLogInTests: XCTestCase {
     let udAddressFromNDF = "ndf-ud-address"
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { networkFollowerStatus }
       return cMix
     }
-    env.ctx.getE2E = {
+    env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { e2eId }
       e2e.getUdCertFromNdf.run = { udCertFromNDF }
@@ -29,7 +29,7 @@ final class MessengerLogInTests: XCTestCase {
       e2e.getUdAddressFromNdf.run = { udAddressFromNDF }
       return e2e
     }
-    env.ctx.setUD = { didSetUD.append($0) }
+    env.ud.set = { didSetUD.append($0) }
     env.udCert = nil
     env.udContact = nil
     env.udAddress = nil
@@ -67,17 +67,17 @@ final class MessengerLogInTests: XCTestCase {
     let altUdAddress = "alt-ud-address"
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
       return cMix
     }
-    env.ctx.getE2E = {
+    env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { e2eId }
       return e2e
     }
-    env.ctx.setUD = { didSetUD.append($0) }
+    env.ud.set = { didSetUD.append($0) }
     env.udCert = altUdCert
     env.udContact = altUdContact
     env.udAddress = altUdAddress
@@ -101,7 +101,7 @@ final class MessengerLogInTests: XCTestCase {
 
   func testLoginWithoutCMix() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = { nil }
+    env.cMix.get = { nil }
     let logIn: MessengerLogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { error in
@@ -114,8 +114,8 @@ final class MessengerLogInTests: XCTestCase {
 
   func testLoginWithoutE2E() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = { .unimplemented }
-    env.ctx.getE2E = { nil }
+    env.cMix.get = { .unimplemented }
+    env.e2e.get = { nil }
     let logIn: MessengerLogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { error in
@@ -131,12 +131,12 @@ final class MessengerLogInTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
       return cMix
     }
-    env.ctx.getE2E = {
+    env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { 1234 }
       e2e.getUdCertFromNdf.run = { "ndf-ud-cert".data(using: .utf8)! }
@@ -157,12 +157,12 @@ final class MessengerLogInTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
       return cMix
     }
-    env.ctx.getE2E = {
+    env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { 1234 }
       return e2e
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
index 82f2527b..ef96b251 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
@@ -18,7 +18,7 @@ final class MessengerRegisterTests: XCTestCase {
     let username = "new-user-name"
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { networkFollowerStatus }
       cMix.getReceptionRegistrationValidationSignature.run = {
@@ -26,7 +26,7 @@ final class MessengerRegisterTests: XCTestCase {
       }
       return cMix
     }
-    env.ctx.getE2E = {
+    env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { e2eId }
       e2e.getUdCertFromNdf.run = { udCertFromNDF }
@@ -34,7 +34,7 @@ final class MessengerRegisterTests: XCTestCase {
       e2e.getUdAddressFromNdf.run = { udAddressFromNDF }
       return e2e
     }
-    env.ctx.setUD = { didSetUD.append($0) }
+    env.ud.set = { didSetUD.append($0) }
     env.udCert = nil
     env.udContact = nil
     env.udAddress = nil
@@ -74,7 +74,7 @@ final class MessengerRegisterTests: XCTestCase {
     let username = "new-user-name"
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
       cMix.getReceptionRegistrationValidationSignature.run = {
@@ -82,12 +82,12 @@ final class MessengerRegisterTests: XCTestCase {
       }
       return cMix
     }
-    env.ctx.getE2E = {
+    env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { e2eId }
       return e2e
     }
-    env.ctx.setUD = { didSetUD.append($0) }
+    env.ud.set = { didSetUD.append($0) }
     env.udCert = altUdCert
     env.udContact = altUdContact
     env.udAddress = altUdAddress
@@ -111,7 +111,7 @@ final class MessengerRegisterTests: XCTestCase {
 
   func testRegisterWithoutCMix() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = { nil }
+    env.cMix.get = { nil }
     let register: MessengerRegister = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { error in
@@ -124,8 +124,8 @@ final class MessengerRegisterTests: XCTestCase {
 
   func testRegisterWithoutE2E() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = { .unimplemented }
-    env.ctx.getE2E = { nil }
+    env.cMix.get = { .unimplemented }
+    env.e2e.get = { nil }
     let register: MessengerRegister = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { error in
@@ -141,7 +141,7 @@ final class MessengerRegisterTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
       cMix.getReceptionRegistrationValidationSignature.run = {
@@ -149,7 +149,7 @@ final class MessengerRegisterTests: XCTestCase {
       }
       return cMix
     }
-    env.ctx.getE2E = {
+    env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { 1234 }
       e2e.getUdCertFromNdf.run = { "ndf-ud-cert".data(using: .utf8)! }
@@ -170,7 +170,7 @@ final class MessengerRegisterTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
       cMix.getReceptionRegistrationValidationSignature.run = {
@@ -178,7 +178,7 @@ final class MessengerRegisterTests: XCTestCase {
       }
       return cMix
     }
-    env.ctx.getE2E = {
+    env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { 1234 }
       return e2e
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift
index 1b0f11b4..7b3e33af 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift
@@ -8,7 +8,7 @@ final class MessengerStartTests: XCTestCase {
     var didStartNetworkFollower: [Int] = []
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .stopped }
       cMix.startNetworkFollower.run = { timeoutMS in
@@ -25,7 +25,7 @@ final class MessengerStartTests: XCTestCase {
 
   func testStartWhenNotLoaded() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = { nil }
+    env.cMix.get = { nil }
     let start: MessengerStart = .live(env)
 
     XCTAssertThrowsError(try start()) { error in
@@ -38,7 +38,7 @@ final class MessengerStartTests: XCTestCase {
 
   func testStartWhenRunning() throws {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
       return cMix
@@ -53,7 +53,7 @@ final class MessengerStartTests: XCTestCase {
     let error = Error()
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .stopped }
       cMix.startNetworkFollower.run = { _ in throw error }
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerUDTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerUDTests.swift
index 0166a8bb..73f2092c 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerUDTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerUDTests.swift
@@ -4,18 +4,16 @@ import XXClient
 
 final class MessengerUDTests: XCTestCase {
   func testUD() throws {
-    var env: MessengerEnvironment = .unimplemented
-    env.ctx.getE2E = { .unimplemented }
-    let e2e: MessengerE2E = .live(env)
+    let ud: MessengerUD = .live()
 
-    XCTAssertNotNil(e2e())
-  }
+    XCTAssertNil(ud())
+
+    ud.set(.unimplemented)
+
+    XCTAssertNotNil(ud())
 
-  func testE2EWhenNotSet() throws {
-    var env: MessengerEnvironment = .unimplemented
-    env.ctx.getE2E = { nil }
-    let e2e: MessengerE2E = .live(env)
+    ud.set(nil)
 
-    XCTAssertNil(e2e())
+    XCTAssertNil(ud())
   }
 }
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift
index 9e489226..1dbae735 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift
@@ -8,7 +8,7 @@ final class MessengerWaitForNetworkTests: XCTestCase {
     var didWaitForNetwork: [Int] = []
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.waitForNetwork.run = { timeoutMS in
         didWaitForNetwork.append(timeoutMS)
@@ -25,7 +25,7 @@ final class MessengerWaitForNetworkTests: XCTestCase {
 
   func testWaitWhenNotLoaded() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = { nil }
+    env.cMix.get = { nil }
     let waitForNetwork: MessengerWaitForNetwork = .live(env)
 
     XCTAssertThrowsError(try waitForNetwork()) { error in
@@ -38,7 +38,7 @@ final class MessengerWaitForNetworkTests: XCTestCase {
 
   func testWaitTimeout() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.waitForNetwork.run = { _ in false }
       return cMix
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift
index ba1fd941..bc23afb5 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift
@@ -6,7 +6,7 @@ import XXClient
 final class MessengerWaitForNodesTests: XCTestCase {
   func testWaitWhenNotLoaded() {
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = { nil }
+    env.cMix.get = { nil }
     let waitForNodes: MessengerWaitForNodes = .live(env)
 
     XCTAssertThrowsError(try waitForNodes()) { error in
@@ -21,7 +21,7 @@ final class MessengerWaitForNodesTests: XCTestCase {
     var didProgress: [NodeRegistrationReport] = []
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getNodeRegistrationStatus.run = {
         NodeRegistrationReport(registered: 8, total: 10)
@@ -53,7 +53,7 @@ final class MessengerWaitForNodesTests: XCTestCase {
     ]
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getNodeRegistrationStatus.run = { reports.removeFirst() }
       return cMix
@@ -88,7 +88,7 @@ final class MessengerWaitForNodesTests: XCTestCase {
     ]
 
     var env: MessengerEnvironment = .unimplemented
-    env.ctx.getCMix = {
+    env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getNodeRegistrationStatus.run = { reports.removeFirst() }
       return cMix
-- 
GitLab


From 0b254c4446482aba098884790ac2e2e8c8b7fc26 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Tue, 23 Aug 2022 00:13:11 +0100
Subject: [PATCH 22/27] Add Stored utility

---
 Sources/XXMessengerClient/Utils/Stored.swift  | 41 +++++++++++++++++++
 .../Messenger/Utils/StoredTests.swift         | 18 ++++++++
 2 files changed, 59 insertions(+)
 create mode 100644 Sources/XXMessengerClient/Utils/Stored.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Utils/StoredTests.swift

diff --git a/Sources/XXMessengerClient/Utils/Stored.swift b/Sources/XXMessengerClient/Utils/Stored.swift
new file mode 100644
index 00000000..56b5e97e
--- /dev/null
+++ b/Sources/XXMessengerClient/Utils/Stored.swift
@@ -0,0 +1,41 @@
+import XCTestDynamicOverlay
+
+public struct Stored<Value> {
+  public var get: () -> Value
+  public var set: (Value) -> Void
+
+  public func callAsFunction() -> Value {
+    get()
+  }
+}
+
+extension Stored {
+  public static func inMemory(_ value: Value) -> Stored<Value> {
+    let memory = Memory(value)
+    return Stored(
+      get: { memory.value },
+      set: { memory.value = $0 }
+    )
+  }
+
+  public static func inMemory<V>() -> Stored<Optional<V>> where Value == Optional<V> {
+    inMemory(nil)
+  }
+}
+
+private final class Memory<Value> {
+  init(_ value: Value) {
+    self.value = value
+  }
+
+  var value: Value
+}
+
+extension Stored {
+  public static func unimplemented() -> Stored<Value> {
+    Stored<Value>(
+      get: XCTUnimplemented("\(Self.self).get"),
+      set: XCTUnimplemented("\(Self.self).set")
+    )
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Utils/StoredTests.swift b/Tests/XXMessengerClientTests/Messenger/Utils/StoredTests.swift
new file mode 100644
index 00000000..154f6196
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Utils/StoredTests.swift
@@ -0,0 +1,18 @@
+import XCTest
+@testable import XXMessengerClient
+
+final class StoredTests: XCTestCase {
+  func testInMemory() throws {
+    let stored: Stored<String?> = .inMemory()
+
+    XCTAssertNil(stored())
+
+    stored.set("test")
+
+    XCTAssertEqual(stored(), "test")
+
+    stored.set(nil)
+
+    XCTAssertNil(stored())
+  }
+}
-- 
GitLab


From 1aa177173cdcd65a6f47930d83c61ffb55990aff Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Tue, 23 Aug 2022 00:13:44 +0100
Subject: [PATCH 23/27] Use Stored utility

---
 .../Messenger/Functors/MessengerCMix.swift    | 29 -------------------
 .../Messenger/Functors/MessengerE2E.swift     | 29 -------------------
 .../Messenger/Functors/MessengerUD.swift      | 29 -------------------
 .../Messenger/Messenger.swift                 | 12 ++++----
 .../Messenger/MessengerEnvironment.swift      | 18 ++++++------
 .../Functors/MessengerCMixTests.swift         | 19 ------------
 .../Functors/MessengerE2ETests.swift          | 19 ------------
 .../Messenger/Functors/MessengerUDTests.swift | 19 ------------
 8 files changed, 15 insertions(+), 159 deletions(-)
 delete mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerCMix.swift
 delete mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerE2E.swift
 delete mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerUD.swift
 delete mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerCMixTests.swift
 delete mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerE2ETests.swift
 delete mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerUDTests.swift

diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerCMix.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerCMix.swift
deleted file mode 100644
index d3e062d2..00000000
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerCMix.swift
+++ /dev/null
@@ -1,29 +0,0 @@
-import XXClient
-import XCTestDynamicOverlay
-
-public struct MessengerCMix {
-  public var get: () -> CMix?
-  public var set: (CMix?) -> Void
-
-  public func callAsFunction() -> CMix? {
-    get()
-  }
-}
-
-extension MessengerCMix {
-  public static func live() -> MessengerCMix {
-    class Storage { var value: CMix? }
-    let storage = Storage()
-    return MessengerCMix(
-      get: { storage.value },
-      set: { storage.value = $0 }
-    )
-  }
-}
-
-extension MessengerCMix {
-  public static let unimplemented = MessengerCMix(
-    get: XCTUnimplemented("\(Self.self).get", placeholder: nil),
-    set: XCTUnimplemented("\(Self.self).set")
-  )
-}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerE2E.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerE2E.swift
deleted file mode 100644
index 070a6b70..00000000
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerE2E.swift
+++ /dev/null
@@ -1,29 +0,0 @@
-import XXClient
-import XCTestDynamicOverlay
-
-public struct MessengerE2E {
-  public var get: () -> E2E?
-  public var set: (E2E?) -> Void
-
-  public func callAsFunction() -> E2E? {
-    get()
-  }
-}
-
-extension MessengerE2E {
-  public static func live() -> MessengerE2E {
-    class Storage { var value: E2E? }
-    let storage = Storage()
-    return MessengerE2E(
-      get: { storage.value },
-      set: { storage.value = $0 }
-    )
-  }
-}
-
-extension MessengerE2E {
-  public static let unimplemented = MessengerE2E(
-    get: XCTUnimplemented("\(Self.self).get", placeholder: nil),
-    set: XCTUnimplemented("\(Self.self).set")
-  )
-}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerUD.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerUD.swift
deleted file mode 100644
index c871f6e0..00000000
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerUD.swift
+++ /dev/null
@@ -1,29 +0,0 @@
-import XXClient
-import XCTestDynamicOverlay
-
-public struct MessengerUD {
-  public var get: () -> UserDiscovery?
-  public var set: (UserDiscovery?) -> Void
-
-  public func callAsFunction() -> UserDiscovery? {
-    get()
-  }
-}
-
-extension MessengerUD {
-  public static func live() -> MessengerUD {
-    class Storage { var value: UserDiscovery? }
-    let storage = Storage()
-    return MessengerUD(
-      get: { storage.value },
-      set: { storage.value = $0 }
-    )
-  }
-}
-
-extension MessengerUD {
-  public static let unimplemented = MessengerUD(
-    get: XCTUnimplemented("\(Self.self).get", placeholder: nil),
-    set: XCTUnimplemented("\(Self.self).set")
-  )
-}
diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
index 397c8e84..30d63efd 100644
--- a/Sources/XXMessengerClient/Messenger/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -1,9 +1,9 @@
 import XXClient
 
 public struct Messenger {
-  public var cMix: MessengerCMix
-  public var e2e: MessengerE2E
-  public var ud: MessengerUD
+  public var cMix: Stored<CMix?>
+  public var e2e: Stored<E2E?>
+  public var ud: Stored<UserDiscovery?>
   public var isCreated: MessengerIsCreated
   public var create: MessengerCreate
   public var isLoaded: MessengerIsLoaded
@@ -44,9 +44,9 @@ extension Messenger {
 
 extension Messenger {
   public static let unimplemented = Messenger(
-    cMix: .unimplemented,
-    e2e: .unimplemented,
-    ud: .unimplemented,
+    cMix: .unimplemented(),
+    e2e: .unimplemented(),
+    ud: .unimplemented(),
     isCreated: .unimplemented,
     create: .unimplemented,
     isLoaded: .unimplemented,
diff --git a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
index a84a1e87..0918142a 100644
--- a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
+++ b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
@@ -3,9 +3,9 @@ import XXClient
 import XCTestDynamicOverlay
 
 public struct MessengerEnvironment {
-  public var cMix: MessengerCMix
+  public var cMix: Stored<CMix?>
   public var downloadNDF: DownloadAndVerifySignedNdf
-  public var e2e: MessengerE2E
+  public var e2e: Stored<E2E?>
   public var fileManager: MessengerFileManager
   public var generateSecret: GenerateSecret
   public var getCMixParams: GetCMixParams
@@ -19,7 +19,7 @@ public struct MessengerEnvironment {
   public var passwordStorage: PasswordStorage
   public var sleep: (Int) -> Void
   public var storageDir: String
-  public var ud: MessengerUD
+  public var ud: Stored<UserDiscovery?>
   public var udAddress: String?
   public var udCert: Data?
   public var udContact: Data?
@@ -34,9 +34,9 @@ extension MessengerEnvironment {
 
   public static func live() -> MessengerEnvironment {
     MessengerEnvironment(
-      cMix: .live(),
+      cMix: .inMemory(),
       downloadNDF: .live,
-      e2e: .live(),
+      e2e: .inMemory(),
       fileManager: .live(),
       generateSecret: .live,
       getCMixParams: .liveDefault,
@@ -50,7 +50,7 @@ extension MessengerEnvironment {
       passwordStorage: .keychain,
       sleep: { Foundation.sleep(UInt32($0)) },
       storageDir: MessengerEnvironment.defaultStorageDir,
-      ud: .live(),
+      ud: .inMemory(),
       udAddress: nil,
       udCert: nil,
       udContact: nil
@@ -60,9 +60,9 @@ extension MessengerEnvironment {
 
 extension MessengerEnvironment {
   public static let unimplemented = MessengerEnvironment(
-    cMix: .unimplemented,
+    cMix: .unimplemented(),
     downloadNDF: .unimplemented,
-    e2e: .unimplemented,
+    e2e: .unimplemented(),
     fileManager: .unimplemented,
     generateSecret: .unimplemented,
     getCMixParams: .unimplemented,
@@ -76,7 +76,7 @@ extension MessengerEnvironment {
     passwordStorage: .unimplemented,
     sleep: XCTUnimplemented("\(Self.self).sleep"),
     storageDir: "unimplemented",
-    ud: .unimplemented,
+    ud: .unimplemented(),
     udAddress: nil,
     udCert: nil,
     udContact: nil
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCMixTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCMixTests.swift
deleted file mode 100644
index 668983f5..00000000
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCMixTests.swift
+++ /dev/null
@@ -1,19 +0,0 @@
-import XCTest
-import XXClient
-@testable import XXMessengerClient
-
-final class MessengerCMixTests: XCTestCase {
-  func testCMix() throws {
-    let cMix: MessengerCMix = .live()
-
-    XCTAssertNil(cMix())
-
-    cMix.set(.unimplemented)
-
-    XCTAssertNotNil(cMix())
-
-    cMix.set(nil)
-
-    XCTAssertNil(cMix())
-  }
-}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerE2ETests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerE2ETests.swift
deleted file mode 100644
index 63b9f585..00000000
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerE2ETests.swift
+++ /dev/null
@@ -1,19 +0,0 @@
-import XCTest
-import XXClient
-@testable import XXMessengerClient
-
-final class MessengerE2ETests: XCTestCase {
-  func testE2E() throws {
-    let e2e: MessengerE2E = .live()
-
-    XCTAssertNil(e2e())
-
-    e2e.set(.unimplemented)
-
-    XCTAssertNotNil(e2e())
-
-    e2e.set(nil)
-
-    XCTAssertNil(e2e())
-  }
-}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerUDTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerUDTests.swift
deleted file mode 100644
index 73f2092c..00000000
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerUDTests.swift
+++ /dev/null
@@ -1,19 +0,0 @@
-import XCTest
-import XXClient
-@testable import XXMessengerClient
-
-final class MessengerUDTests: XCTestCase {
-  func testUD() throws {
-    let ud: MessengerUD = .live()
-
-    XCTAssertNil(ud())
-
-    ud.set(.unimplemented)
-
-    XCTAssertNotNil(ud())
-
-    ud.set(nil)
-
-    XCTAssertNil(ud())
-  }
-}
-- 
GitLab


From b7c181295fe02c4f9de10b9f567a7c8735f2e05a Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Tue, 23 Aug 2022 00:26:04 +0100
Subject: [PATCH 24/27] Refactor

---
 Docs/XXMessengerClient.md                     |  4 +-
 ...gerEnvironment.swift => Environment.swift} | 20 +++++-----
 .../Connect.swift}                            | 12 +++---
 .../Create.swift}                             | 16 ++++----
 .../Functors/IsConnected.swift                | 25 ++++++++++++
 .../Functors/IsCreated.swift                  | 24 +++++++++++
 .../XXMessengerClient/Functors/IsLoaded.swift | 24 +++++++++++
 .../Functors/IsLoggedIn.swift                 | 24 +++++++++++
 .../IsRegistered.swift}                       | 12 +++---
 .../Load.swift}                               | 12 +++---
 .../LogIn.swift}                              | 12 +++---
 .../Register.swift}                           | 12 +++---
 .../Start.swift}                              | 12 +++---
 .../WaitForNetwork.swift}                     | 12 +++---
 .../WaitForNodes.swift}                       | 12 +++---
 .../{Messenger => }/Messenger.swift           | 28 ++++++-------
 .../Functors/MessengerIsConnected.swift       | 25 ------------
 .../Functors/MessengerIsCreated.swift         | 24 -----------
 .../Functors/MessengerIsLoaded.swift          | 24 -----------
 .../Functors/MessengerIsLoggedIn.swift        | 24 -----------
 .../Utils/DirectoryManager.swift              | 40 +++++++++++++++++++
 .../Utils/MessengerFileManager.swift          | 40 -------------------
 .../ConnectTests.swift}                       | 22 +++++-----
 .../CreateTests.swift}                        | 40 +++++++++----------
 .../Functors/IsConnectedTests.swift           | 20 ++++++++++
 .../IsCreatedTests.swift}                     | 14 +++----
 .../Functors/IsLoadedTests.swift              | 20 ++++++++++
 .../Functors/IsLoggedInTests.swift            | 20 ++++++++++
 .../IsRegisteredTests.swift}                  | 22 +++++-----
 .../LoadTests.swift}                          | 14 +++----
 .../LogInTests.swift}                         | 34 ++++++++--------
 .../RegisterTests.swift}                      | 34 ++++++++--------
 .../StartTests.swift}                         | 22 +++++-----
 .../WaitForNetworkTests.swift}                | 22 +++++-----
 .../WaitForNodesTests.swift}                  | 26 ++++++------
 .../Functors/MessengerIsConnectedTests.swift  | 20 ----------
 .../Functors/MessengerIsLoadedTests.swift     | 20 ----------
 .../Functors/MessengerIsLoggedInTests.swift   | 20 ----------
 .../{Messenger => }/Utils/StoredTests.swift   |  0
 39 files changed, 404 insertions(+), 404 deletions(-)
 rename Sources/XXMessengerClient/{Messenger/MessengerEnvironment.swift => Environment.swift} (83%)
 rename Sources/XXMessengerClient/{Messenger/Functors/MessengerConnect.swift => Functors/Connect.swift} (67%)
 rename Sources/XXMessengerClient/{Messenger/Functors/MessengerCreate.swift => Functors/Create.swift} (61%)
 create mode 100644 Sources/XXMessengerClient/Functors/IsConnected.swift
 create mode 100644 Sources/XXMessengerClient/Functors/IsCreated.swift
 create mode 100644 Sources/XXMessengerClient/Functors/IsLoaded.swift
 create mode 100644 Sources/XXMessengerClient/Functors/IsLoggedIn.swift
 rename Sources/XXMessengerClient/{Messenger/Functors/MessengerIsRegistered.swift => Functors/IsRegistered.swift} (59%)
 rename Sources/XXMessengerClient/{Messenger/Functors/MessengerLoad.swift => Functors/Load.swift} (61%)
 rename Sources/XXMessengerClient/{Messenger/Functors/MessengerLogIn.swift => Functors/LogIn.swift} (79%)
 rename Sources/XXMessengerClient/{Messenger/Functors/MessengerRegister.swift => Functors/Register.swift} (78%)
 rename Sources/XXMessengerClient/{Messenger/Functors/MessengerStart.swift => Functors/Start.swift} (68%)
 rename Sources/XXMessengerClient/{Messenger/Functors/MessengerWaitForNetwork.swift => Functors/WaitForNetwork.swift} (62%)
 rename Sources/XXMessengerClient/{Messenger/Functors/MessengerWaitForNodes.swift => Functors/WaitForNodes.swift} (75%)
 rename Sources/XXMessengerClient/{Messenger => }/Messenger.swift (65%)
 delete mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
 delete mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift
 delete mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
 delete mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
 create mode 100644 Sources/XXMessengerClient/Utils/DirectoryManager.swift
 delete mode 100644 Sources/XXMessengerClient/Utils/MessengerFileManager.swift
 rename Tests/XXMessengerClientTests/{Messenger/Functors/MessengerConnectTests.swift => Functors/ConnectTests.swift} (83%)
 rename Tests/XXMessengerClientTests/{Messenger/Functors/MessengerCreateTests.swift => Functors/CreateTests.swift} (80%)
 create mode 100644 Tests/XXMessengerClientTests/Functors/IsConnectedTests.swift
 rename Tests/XXMessengerClientTests/{Messenger/Functors/MessengerIsCreatedTests.swift => Functors/IsCreatedTests.swift} (65%)
 create mode 100644 Tests/XXMessengerClientTests/Functors/IsLoadedTests.swift
 create mode 100644 Tests/XXMessengerClientTests/Functors/IsLoggedInTests.swift
 rename Tests/XXMessengerClientTests/{Messenger/Functors/MessengerIsRegisteredTests.swift => Functors/IsRegisteredTests.swift} (67%)
 rename Tests/XXMessengerClientTests/{Messenger/Functors/MessengerLoadTests.swift => Functors/LoadTests.swift} (85%)
 rename Tests/XXMessengerClientTests/{Messenger/Functors/MessengerLogInTests.swift => Functors/LogInTests.swift} (85%)
 rename Tests/XXMessengerClientTests/{Messenger/Functors/MessengerRegisterTests.swift => Functors/RegisterTests.swift} (86%)
 rename Tests/XXMessengerClientTests/{Messenger/Functors/MessengerStartTests.swift => Functors/StartTests.swift} (71%)
 rename Tests/XXMessengerClientTests/{Messenger/Functors/MessengerWaitForNetworkTests.swift => Functors/WaitForNetworkTests.swift} (60%)
 rename Tests/XXMessengerClientTests/{Messenger/Functors/MessengerWaitForNodesTests.swift => Functors/WaitForNodesTests.swift} (80%)
 delete mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
 delete mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
 delete mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
 rename Tests/XXMessengerClientTests/{Messenger => }/Utils/StoredTests.swift (100%)

diff --git a/Docs/XXMessengerClient.md b/Docs/XXMessengerClient.md
index 2dc19246..fd9ac7ee 100644
--- a/Docs/XXMessengerClient.md
+++ b/Docs/XXMessengerClient.md
@@ -8,7 +8,7 @@ Example:
 
 ```swift
 // setup environment:
-var environment: MessengerEnvironment = .live()
+var environment: Environment = .live()
 
 // change cMix NDF environment if needed:
 environment.ndfEnvironment = ...
@@ -60,4 +60,4 @@ func start(messenger: Messenger) throws {
     }
   }
 }
-```
\ No newline at end of file
+```
diff --git a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift b/Sources/XXMessengerClient/Environment.swift
similarity index 83%
rename from Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
rename to Sources/XXMessengerClient/Environment.swift
index 0918142a..58b18db9 100644
--- a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
+++ b/Sources/XXMessengerClient/Environment.swift
@@ -2,11 +2,11 @@ import Foundation
 import XXClient
 import XCTestDynamicOverlay
 
-public struct MessengerEnvironment {
+public struct Environment {
   public var cMix: Stored<CMix?>
+  public var directoryManager: DirectoryManager
   public var downloadNDF: DownloadAndVerifySignedNdf
   public var e2e: Stored<E2E?>
-  public var fileManager: MessengerFileManager
   public var generateSecret: GenerateSecret
   public var getCMixParams: GetCMixParams
   public var getE2EParams: GetE2EParams
@@ -25,19 +25,19 @@ public struct MessengerEnvironment {
   public var udContact: Data?
 }
 
-extension MessengerEnvironment {
+extension Environment {
   public static let defaultStorageDir = FileManager.default
     .urls(for: .applicationSupportDirectory, in: .userDomainMask)
     .first!
     .appendingPathComponent("xx.network.client")
     .path
 
-  public static func live() -> MessengerEnvironment {
-    MessengerEnvironment(
+  public static func live() -> Environment {
+    Environment(
       cMix: .inMemory(),
+      directoryManager: .live(),
       downloadNDF: .live,
       e2e: .inMemory(),
-      fileManager: .live(),
       generateSecret: .live,
       getCMixParams: .liveDefault,
       getE2EParams: .liveDefault,
@@ -49,7 +49,7 @@ extension MessengerEnvironment {
       newOrLoadUd: .live,
       passwordStorage: .keychain,
       sleep: { Foundation.sleep(UInt32($0)) },
-      storageDir: MessengerEnvironment.defaultStorageDir,
+      storageDir: Environment.defaultStorageDir,
       ud: .inMemory(),
       udAddress: nil,
       udCert: nil,
@@ -58,12 +58,12 @@ extension MessengerEnvironment {
   }
 }
 
-extension MessengerEnvironment {
-  public static let unimplemented = MessengerEnvironment(
+extension Environment {
+  public static let unimplemented = Environment(
     cMix: .unimplemented(),
+    directoryManager: .unimplemented,
     downloadNDF: .unimplemented,
     e2e: .unimplemented(),
-    fileManager: .unimplemented,
     generateSecret: .unimplemented,
     getCMixParams: .unimplemented,
     getE2EParams: .unimplemented,
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift b/Sources/XXMessengerClient/Functors/Connect.swift
similarity index 67%
rename from Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
rename to Sources/XXMessengerClient/Functors/Connect.swift
index 8cebb73a..47d649fe 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
+++ b/Sources/XXMessengerClient/Functors/Connect.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct MessengerConnect {
+public struct Connect {
   public enum Error: Swift.Error, Equatable {
     case notLoaded
   }
@@ -13,9 +13,9 @@ public struct MessengerConnect {
   }
 }
 
-extension MessengerConnect {
-  public static func live(_ env: MessengerEnvironment) -> MessengerConnect {
-    MessengerConnect {
+extension Connect {
+  public static func live(_ env: Environment) -> Connect {
+    Connect {
       guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
@@ -28,8 +28,8 @@ extension MessengerConnect {
   }
 }
 
-extension MessengerConnect {
-  public static let unimplemented = MessengerConnect(
+extension Connect {
+  public static let unimplemented = Connect(
     run: XCTUnimplemented()
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift b/Sources/XXMessengerClient/Functors/Create.swift
similarity index 61%
rename from Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift
rename to Sources/XXMessengerClient/Functors/Create.swift
index b36b55b4..275722c7 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift
+++ b/Sources/XXMessengerClient/Functors/Create.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct MessengerCreate {
+public struct Create {
   public var run: () throws -> Void
 
   public func callAsFunction() throws {
@@ -9,15 +9,15 @@ public struct MessengerCreate {
   }
 }
 
-extension MessengerCreate {
-  public static func live(_ env: MessengerEnvironment) -> MessengerCreate {
-    MessengerCreate {
+extension Create {
+  public static func live(_ env: Environment) -> Create {
+    Create {
       let ndfData = try env.downloadNDF(env.ndfEnvironment)
       let password = env.generateSecret()
       try env.passwordStorage.save(password)
       let storageDir = env.storageDir
-      try env.fileManager.removeDirectory(storageDir)
-      try env.fileManager.createDirectory(storageDir)
+      try env.directoryManager.remove(storageDir)
+      try env.directoryManager.create(storageDir)
       try env.newCMix(
         ndfJSON: String(data: ndfData, encoding: .utf8)!,
         storageDir: storageDir,
@@ -28,8 +28,8 @@ extension MessengerCreate {
   }
 }
 
-extension MessengerCreate {
-  public static let unimplemented = MessengerCreate(
+extension Create {
+  public static let unimplemented = Create(
     run: XCTUnimplemented()
   )
 }
diff --git a/Sources/XXMessengerClient/Functors/IsConnected.swift b/Sources/XXMessengerClient/Functors/IsConnected.swift
new file mode 100644
index 00000000..923d29df
--- /dev/null
+++ b/Sources/XXMessengerClient/Functors/IsConnected.swift
@@ -0,0 +1,25 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct IsConnected {
+  public var run: () -> Bool
+
+  public func callAsFunction() -> Bool {
+    run()
+  }
+}
+
+extension IsConnected {
+  public static func live(_ env: Environment) -> IsConnected {
+    IsConnected {
+      env.e2e() != nil
+    }
+  }
+}
+
+extension IsConnected {
+  public static let unimplemented = IsConnected(
+    run: XCTUnimplemented()
+  )
+}
+
diff --git a/Sources/XXMessengerClient/Functors/IsCreated.swift b/Sources/XXMessengerClient/Functors/IsCreated.swift
new file mode 100644
index 00000000..c9f55cff
--- /dev/null
+++ b/Sources/XXMessengerClient/Functors/IsCreated.swift
@@ -0,0 +1,24 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct IsCreated {
+  public var run: () -> Bool
+
+  public func callAsFunction() -> Bool {
+    run()
+  }
+}
+
+extension IsCreated {
+  public static func live(_ env: Environment) -> IsCreated {
+    IsCreated {
+      env.directoryManager.isEmpty(env.storageDir) == false
+    }
+  }
+}
+
+extension IsCreated {
+  public static let unimplemented = IsCreated(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Functors/IsLoaded.swift b/Sources/XXMessengerClient/Functors/IsLoaded.swift
new file mode 100644
index 00000000..e3365cc3
--- /dev/null
+++ b/Sources/XXMessengerClient/Functors/IsLoaded.swift
@@ -0,0 +1,24 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct IsLoaded {
+  public var run: () -> Bool
+
+  public func callAsFunction() -> Bool {
+    run()
+  }
+}
+
+extension IsLoaded {
+  public static func live(_ env: Environment) -> IsLoaded {
+    IsLoaded {
+      env.cMix() != nil
+    }
+  }
+}
+
+extension IsLoaded {
+  public static let unimplemented = IsLoaded(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Functors/IsLoggedIn.swift b/Sources/XXMessengerClient/Functors/IsLoggedIn.swift
new file mode 100644
index 00000000..bcf0dfdf
--- /dev/null
+++ b/Sources/XXMessengerClient/Functors/IsLoggedIn.swift
@@ -0,0 +1,24 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct IsLoggedIn {
+  public var run: () -> Bool
+
+  public func callAsFunction() -> Bool {
+    run()
+  }
+}
+
+extension IsLoggedIn {
+  public static func live(_ env: Environment) -> IsLoggedIn {
+    IsLoggedIn {
+      env.ud() != nil
+    }
+  }
+}
+
+extension IsLoggedIn {
+  public static let unimplemented = IsLoggedIn(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift b/Sources/XXMessengerClient/Functors/IsRegistered.swift
similarity index 59%
rename from Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
rename to Sources/XXMessengerClient/Functors/IsRegistered.swift
index bf3cafa5..4ccc2ce7 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
+++ b/Sources/XXMessengerClient/Functors/IsRegistered.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct MessengerIsRegistered {
+public struct IsRegistered {
   public enum Error: Swift.Error, Equatable {
     case notConnected
   }
@@ -13,9 +13,9 @@ public struct MessengerIsRegistered {
   }
 }
 
-extension MessengerIsRegistered {
-  public static func live(_ env: MessengerEnvironment) -> MessengerIsRegistered {
-    MessengerIsRegistered {
+extension IsRegistered {
+  public static func live(_ env: Environment) -> IsRegistered {
+    IsRegistered {
       guard let e2e = env.e2e() else {
         throw Error.notConnected
       }
@@ -24,8 +24,8 @@ extension MessengerIsRegistered {
   }
 }
 
-extension MessengerIsRegistered {
-  public static let unimplemented = MessengerIsRegistered(
+extension IsRegistered {
+  public static let unimplemented = IsRegistered(
     run: XCTUnimplemented()
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift b/Sources/XXMessengerClient/Functors/Load.swift
similarity index 61%
rename from Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
rename to Sources/XXMessengerClient/Functors/Load.swift
index 29f28168..03010a22 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
+++ b/Sources/XXMessengerClient/Functors/Load.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct MessengerLoad {
+public struct Load {
   public var run: () throws -> Void
 
   public func callAsFunction() throws {
@@ -9,9 +9,9 @@ public struct MessengerLoad {
   }
 }
 
-extension MessengerLoad {
-  public static func live(_ env: MessengerEnvironment) -> MessengerLoad {
-    MessengerLoad {
+extension Load {
+  public static func live(_ env: Environment) -> Load {
+    Load {
       env.cMix.set(try env.loadCMix(
         storageDir: env.storageDir,
         password: try env.passwordStorage.load(),
@@ -21,8 +21,8 @@ extension MessengerLoad {
   }
 }
 
-extension MessengerLoad {
-  public static let unimplemented = MessengerLoad(
+extension Load {
+  public static let unimplemented = Load(
     run: XCTUnimplemented()
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift b/Sources/XXMessengerClient/Functors/LogIn.swift
similarity index 79%
rename from Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
rename to Sources/XXMessengerClient/Functors/LogIn.swift
index d0f86d8b..db2c34f9 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
+++ b/Sources/XXMessengerClient/Functors/LogIn.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct MessengerLogIn {
+public struct LogIn {
   public enum Error: Swift.Error, Equatable {
     case notLoaded
     case notConnected
@@ -14,9 +14,9 @@ public struct MessengerLogIn {
   }
 }
 
-extension MessengerLogIn {
-  public static func live(_ env: MessengerEnvironment) -> MessengerLogIn {
-    MessengerLogIn {
+extension LogIn {
+  public static func live(_ env: Environment) -> LogIn {
+    LogIn {
       guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
@@ -40,8 +40,8 @@ extension MessengerLogIn {
   }
 }
 
-extension MessengerLogIn {
-  public static let unimplemented = MessengerLogIn(
+extension LogIn {
+  public static let unimplemented = LogIn(
     run: XCTUnimplemented()
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift b/Sources/XXMessengerClient/Functors/Register.swift
similarity index 78%
rename from Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
rename to Sources/XXMessengerClient/Functors/Register.swift
index 6f429631..3608ea93 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
+++ b/Sources/XXMessengerClient/Functors/Register.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct MessengerRegister {
+public struct Register {
   public enum Error: Swift.Error, Equatable {
     case notLoaded
     case notConnected
@@ -16,9 +16,9 @@ public struct MessengerRegister {
   }
 }
 
-extension MessengerRegister {
-  public static func live(_ env: MessengerEnvironment) -> MessengerRegister {
-    MessengerRegister { username in
+extension Register {
+  public static func live(_ env: Environment) -> Register {
+    Register { username in
       guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
@@ -42,8 +42,8 @@ extension MessengerRegister {
   }
 }
 
-extension MessengerRegister {
-  public static let unimplemented = MessengerRegister(
+extension Register {
+  public static let unimplemented = Register(
     run: XCTUnimplemented()
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift b/Sources/XXMessengerClient/Functors/Start.swift
similarity index 68%
rename from Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift
rename to Sources/XXMessengerClient/Functors/Start.swift
index cc3363ec..77e32812 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift
+++ b/Sources/XXMessengerClient/Functors/Start.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct MessengerStart {
+public struct Start {
   public enum Error: Swift.Error {
     case notLoaded
   }
@@ -15,9 +15,9 @@ public struct MessengerStart {
   }
 }
 
-extension MessengerStart {
-  public static func live(_ env: MessengerEnvironment) -> MessengerStart {
-    MessengerStart { timeoutMS in
+extension Start {
+  public static func live(_ env: Environment) -> Start {
+    Start { timeoutMS in
       guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
@@ -29,8 +29,8 @@ extension MessengerStart {
   }
 }
 
-extension MessengerStart {
-  public static let unimplemented = MessengerStart(
+extension Start {
+  public static let unimplemented = Start(
     run: XCTUnimplemented("\(Self.self)")
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift b/Sources/XXMessengerClient/Functors/WaitForNetwork.swift
similarity index 62%
rename from Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift
rename to Sources/XXMessengerClient/Functors/WaitForNetwork.swift
index 8fe8cf3e..976e6423 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift
+++ b/Sources/XXMessengerClient/Functors/WaitForNetwork.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct MessengerWaitForNetwork {
+public struct WaitForNetwork {
   public enum Error: Swift.Error {
     case notLoaded
     case timeout
@@ -16,9 +16,9 @@ public struct MessengerWaitForNetwork {
   }
 }
 
-extension MessengerWaitForNetwork {
-  public static func live(_ env: MessengerEnvironment) -> MessengerWaitForNetwork {
-    MessengerWaitForNetwork { timeoutMS in
+extension WaitForNetwork {
+  public static func live(_ env: Environment) -> WaitForNetwork {
+    WaitForNetwork { timeoutMS in
       guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
@@ -29,8 +29,8 @@ extension MessengerWaitForNetwork {
   }
 }
 
-extension MessengerWaitForNetwork {
-  public static let unimplemented = MessengerWaitForNetwork(
+extension WaitForNetwork {
+  public static let unimplemented = WaitForNetwork(
     run: XCTUnimplemented("\(Self.self)")
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift b/Sources/XXMessengerClient/Functors/WaitForNodes.swift
similarity index 75%
rename from Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
rename to Sources/XXMessengerClient/Functors/WaitForNodes.swift
index b87acc2f..f08a2966 100644
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
+++ b/Sources/XXMessengerClient/Functors/WaitForNodes.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct MessengerWaitForNodes {
+public struct WaitForNodes {
   public typealias Progress = (NodeRegistrationReport) -> Void
 
   public enum Error: Swift.Error {
@@ -21,9 +21,9 @@ public struct MessengerWaitForNodes {
   }
 }
 
-extension MessengerWaitForNodes {
-  public static func live(_ env: MessengerEnvironment) -> MessengerWaitForNodes {
-    MessengerWaitForNodes { targetRatio, sleepMS, retries, onProgress in
+extension WaitForNodes {
+  public static func live(_ env: Environment) -> WaitForNodes {
+    WaitForNodes { targetRatio, sleepMS, retries, onProgress in
       guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
@@ -46,8 +46,8 @@ extension MessengerWaitForNodes {
   }
 }
 
-extension MessengerWaitForNodes {
-  public static let unimplemented = MessengerWaitForNodes(
+extension WaitForNodes {
+  public static let unimplemented = WaitForNodes(
     run: XCTUnimplemented("\(Self.self)")
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger.swift
similarity index 65%
rename from Sources/XXMessengerClient/Messenger/Messenger.swift
rename to Sources/XXMessengerClient/Messenger.swift
index 30d63efd..b3ad9a58 100644
--- a/Sources/XXMessengerClient/Messenger/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger.swift
@@ -4,23 +4,23 @@ public struct Messenger {
   public var cMix: Stored<CMix?>
   public var e2e: Stored<E2E?>
   public var ud: Stored<UserDiscovery?>
-  public var isCreated: MessengerIsCreated
-  public var create: MessengerCreate
-  public var isLoaded: MessengerIsLoaded
-  public var load: MessengerLoad
-  public var start: MessengerStart
-  public var isConnected: MessengerIsConnected
-  public var connect: MessengerConnect
-  public var isRegistered: MessengerIsRegistered
-  public var register: MessengerRegister
-  public var isLoggedIn: MessengerIsLoggedIn
-  public var logIn: MessengerLogIn
-  public var waitForNetwork: MessengerWaitForNetwork
-  public var waitForNodes: MessengerWaitForNodes
+  public var isCreated: IsCreated
+  public var create: Create
+  public var isLoaded: IsLoaded
+  public var load: Load
+  public var start: Start
+  public var isConnected: IsConnected
+  public var connect: Connect
+  public var isRegistered: IsRegistered
+  public var register: Register
+  public var isLoggedIn: IsLoggedIn
+  public var logIn: LogIn
+  public var waitForNetwork: WaitForNetwork
+  public var waitForNodes: WaitForNodes
 }
 
 extension Messenger {
-  public static func live(_ env: MessengerEnvironment) -> Messenger {
+  public static func live(_ env: Environment) -> Messenger {
     Messenger(
       cMix: env.cMix,
       e2e: env.e2e,
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
deleted file mode 100644
index c30437fa..00000000
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
+++ /dev/null
@@ -1,25 +0,0 @@
-import XXClient
-import XCTestDynamicOverlay
-
-public struct MessengerIsConnected {
-  public var run: () -> Bool
-
-  public func callAsFunction() -> Bool {
-    run()
-  }
-}
-
-extension MessengerIsConnected {
-  public static func live(_ env: MessengerEnvironment) -> MessengerIsConnected {
-    MessengerIsConnected {
-      env.e2e() != nil
-    }
-  }
-}
-
-extension MessengerIsConnected {
-  public static let unimplemented = MessengerIsConnected(
-    run: XCTUnimplemented()
-  )
-}
-
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift
deleted file mode 100644
index c848518c..00000000
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift
+++ /dev/null
@@ -1,24 +0,0 @@
-import XXClient
-import XCTestDynamicOverlay
-
-public struct MessengerIsCreated {
-  public var run: () -> Bool
-
-  public func callAsFunction() -> Bool {
-    run()
-  }
-}
-
-extension MessengerIsCreated {
-  public static func live(_ env: MessengerEnvironment) -> MessengerIsCreated {
-    MessengerIsCreated {
-      env.fileManager.isDirectoryEmpty(env.storageDir) == false
-    }
-  }
-}
-
-extension MessengerIsCreated {
-  public static let unimplemented = MessengerIsCreated(
-    run: XCTUnimplemented()
-  )
-}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
deleted file mode 100644
index dc0b4216..00000000
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
+++ /dev/null
@@ -1,24 +0,0 @@
-import XXClient
-import XCTestDynamicOverlay
-
-public struct MessengerIsLoaded {
-  public var run: () -> Bool
-
-  public func callAsFunction() -> Bool {
-    run()
-  }
-}
-
-extension MessengerIsLoaded {
-  public static func live(_ env: MessengerEnvironment) -> MessengerIsLoaded {
-    MessengerIsLoaded {
-      env.cMix() != nil
-    }
-  }
-}
-
-extension MessengerIsLoaded {
-  public static let unimplemented = MessengerIsLoaded(
-    run: XCTUnimplemented()
-  )
-}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
deleted file mode 100644
index 7c54c578..00000000
--- a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
+++ /dev/null
@@ -1,24 +0,0 @@
-import XXClient
-import XCTestDynamicOverlay
-
-public struct MessengerIsLoggedIn {
-  public var run: () -> Bool
-
-  public func callAsFunction() -> Bool {
-    run()
-  }
-}
-
-extension MessengerIsLoggedIn {
-  public static func live(_ env: MessengerEnvironment) -> MessengerIsLoggedIn {
-    MessengerIsLoggedIn {
-      env.ud() != nil
-    }
-  }
-}
-
-extension MessengerIsLoggedIn {
-  public static let unimplemented = MessengerIsLoggedIn(
-    run: XCTUnimplemented()
-  )
-}
diff --git a/Sources/XXMessengerClient/Utils/DirectoryManager.swift b/Sources/XXMessengerClient/Utils/DirectoryManager.swift
new file mode 100644
index 00000000..16b9238e
--- /dev/null
+++ b/Sources/XXMessengerClient/Utils/DirectoryManager.swift
@@ -0,0 +1,40 @@
+import Foundation
+import XCTestDynamicOverlay
+
+public struct DirectoryManager {
+  public var isEmpty: (String) -> Bool
+  public var remove: (String) throws -> Void
+  public var create: (String) throws -> Void
+}
+
+extension DirectoryManager {
+  public static func live(
+    fileManager: FileManager = .default
+  ) -> DirectoryManager {
+    DirectoryManager(
+      isEmpty: { path in
+        let contents = try? fileManager.contentsOfDirectory(atPath: path)
+        return contents?.isEmpty ?? true
+      },
+      remove: { path in
+        if fileManager.fileExists(atPath: path) {
+          try fileManager.removeItem(atPath: path)
+        }
+      },
+      create: { path in
+        try fileManager.createDirectory(
+          atPath: path,
+          withIntermediateDirectories: true
+        )
+      }
+    )
+  }
+}
+
+extension DirectoryManager {
+  public static let unimplemented = DirectoryManager(
+    isEmpty: XCTUnimplemented("\(Self.self).isDirectoryEmpty"),
+    remove: XCTUnimplemented("\(Self.self).removeDirectory"),
+    create: XCTUnimplemented("\(Self.self).createDirectory")
+  )
+}
diff --git a/Sources/XXMessengerClient/Utils/MessengerFileManager.swift b/Sources/XXMessengerClient/Utils/MessengerFileManager.swift
deleted file mode 100644
index 4ff49c5f..00000000
--- a/Sources/XXMessengerClient/Utils/MessengerFileManager.swift
+++ /dev/null
@@ -1,40 +0,0 @@
-import Foundation
-import XCTestDynamicOverlay
-
-public struct MessengerFileManager {
-  public var isDirectoryEmpty: (String) -> Bool
-  public var removeDirectory: (String) throws -> Void
-  public var createDirectory: (String) throws -> Void
-}
-
-extension MessengerFileManager {
-  public static func live(
-    fileManager: FileManager = .default
-  ) -> MessengerFileManager {
-    MessengerFileManager(
-      isDirectoryEmpty: { path in
-        let contents = try? fileManager.contentsOfDirectory(atPath: path)
-        return contents?.isEmpty ?? true
-      },
-      removeDirectory: { path in
-        if fileManager.fileExists(atPath: path) {
-          try fileManager.removeItem(atPath: path)
-        }
-      },
-      createDirectory: { path in
-        try fileManager.createDirectory(
-          atPath: path,
-          withIntermediateDirectories: true
-        )
-      }
-    )
-  }
-}
-
-extension MessengerFileManager {
-  public static let unimplemented = MessengerFileManager(
-    isDirectoryEmpty: XCTUnimplemented("\(Self.self).isDirectoryEmpty"),
-    removeDirectory: XCTUnimplemented("\(Self.self).removeDirectory"),
-    createDirectory: XCTUnimplemented("\(Self.self).createDirectory")
-  )
-}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift b/Tests/XXMessengerClientTests/Functors/ConnectTests.swift
similarity index 83%
rename from Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
rename to Tests/XXMessengerClientTests/Functors/ConnectTests.swift
index fb780353..caac4d6a 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
+++ b/Tests/XXMessengerClientTests/Functors/ConnectTests.swift
@@ -3,7 +3,7 @@ import XXClient
 import XCTest
 @testable import XXMessengerClient
 
-final class MessengerConnectTests: XCTestCase {
+final class ConnectTests: XCTestCase {
   func testConnect() throws {
     struct DidLogIn: Equatable {
       var ephemeral: Bool
@@ -20,7 +20,7 @@ final class MessengerConnectTests: XCTestCase {
     let receptionId = ReceptionIdentity.stub
     let e2eParams = "e2e-params".data(using: .utf8)!
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getId.run = { cMixId }
@@ -39,7 +39,7 @@ final class MessengerConnectTests: XCTestCase {
       ))
       return .unimplemented
     }
-    let connect: MessengerConnect = .live(env)
+    let connect: Connect = .live(env)
 
     try connect()
 
@@ -56,14 +56,14 @@ final class MessengerConnectTests: XCTestCase {
   }
 
   func testConnectWithoutCMix() {
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = { nil }
-    let connect: MessengerConnect = .live(env)
+    let connect: Connect = .live(env)
 
     XCTAssertThrowsError(try connect()) { error in
       XCTAssertEqual(
-        error as? MessengerConnect.Error,
-        MessengerConnect.Error.notLoaded
+        error as? Connect.Error,
+        Connect.Error.notLoaded
       )
     }
   }
@@ -72,14 +72,14 @@ final class MessengerConnectTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getId.run = { 1234 }
       cMix.makeLegacyReceptionIdentity.run = { throw error }
       return cMix
     }
-    let connect: MessengerConnect = .live(env)
+    let connect: Connect = .live(env)
 
     XCTAssertThrowsError(try connect()) { err in
       XCTAssertEqual(err as? Error, error)
@@ -90,7 +90,7 @@ final class MessengerConnectTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getId.run = { 1234 }
@@ -99,7 +99,7 @@ final class MessengerConnectTests: XCTestCase {
     }
     env.getE2EParams.run = { "e2e-params".data(using: .utf8)! }
     env.login.run = { _, _, _, _, _ in throw error }
-    let connect: MessengerConnect = .live(env)
+    let connect: Connect = .live(env)
 
     XCTAssertThrowsError(try connect()) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift b/Tests/XXMessengerClientTests/Functors/CreateTests.swift
similarity index 80%
rename from Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
rename to Tests/XXMessengerClientTests/Functors/CreateTests.swift
index 2180dda3..0ef9e0d7 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
+++ b/Tests/XXMessengerClientTests/Functors/CreateTests.swift
@@ -3,7 +3,7 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class MessengerCreateTests: XCTestCase {
+final class CreateTests: XCTestCase {
   func testCreate() throws {
     struct DidNewCMix: Equatable {
       var ndfJSON: String
@@ -23,7 +23,7 @@ final class MessengerCreateTests: XCTestCase {
     let password = "password".data(using: .utf8)!
     let storageDir = "storage-dir"
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.ndfEnvironment = .unimplemented
     env.downloadNDF.run = { ndfEnvironment in
       didDownloadNDF.append(ndfEnvironment)
@@ -37,10 +37,10 @@ final class MessengerCreateTests: XCTestCase {
       didSavePassword.append(password)
     }
     env.storageDir = storageDir
-    env.fileManager.removeDirectory = { path in
+    env.directoryManager.remove = { path in
       didRemoveDirectory.append(path)
     }
-    env.fileManager.createDirectory = { path in
+    env.directoryManager.create = { path in
       didCreateDirectory.append(path)
     }
     env.newCMix.run = { ndfJSON, storageDir, password, registrationCode in
@@ -51,7 +51,7 @@ final class MessengerCreateTests: XCTestCase {
         registrationCode: registrationCode
       ))
     }
-    let create: MessengerCreate = .live(env)
+    let create: Create = .live(env)
 
     try create()
 
@@ -72,10 +72,10 @@ final class MessengerCreateTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.ndfEnvironment = .unimplemented
     env.downloadNDF.run = { _ in throw error }
-    let create: MessengerCreate = .live(env)
+    let create: Create = .live(env)
 
     XCTAssertThrowsError(try create()) { err in
       XCTAssertEqual(err as? Error, error)
@@ -86,12 +86,12 @@ final class MessengerCreateTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.ndfEnvironment = .unimplemented
     env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
     env.generateSecret.run = { _ in "password".data(using: .utf8)! }
     env.passwordStorage.save = { _ in throw error }
-    let create: MessengerCreate = .live(env)
+    let create: Create = .live(env)
 
     XCTAssertThrowsError(try create()) { err in
       XCTAssertEqual(err as? Error, error)
@@ -102,14 +102,14 @@ final class MessengerCreateTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.ndfEnvironment = .unimplemented
     env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
     env.generateSecret.run = { _ in "password".data(using: .utf8)! }
     env.passwordStorage.save = { _ in }
     env.storageDir = "storage-dir"
-    env.fileManager.removeDirectory = { _ in throw error }
-    let create: MessengerCreate = .live(env)
+    env.directoryManager.remove = { _ in throw error }
+    let create: Create = .live(env)
 
     XCTAssertThrowsError(try create()) { err in
       XCTAssertEqual(err as? Error, error)
@@ -120,15 +120,15 @@ final class MessengerCreateTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.ndfEnvironment = .unimplemented
     env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
     env.generateSecret.run = { _ in "password".data(using: .utf8)! }
     env.passwordStorage.save = { _ in }
     env.storageDir = "storage-dir"
-    env.fileManager.removeDirectory = { _ in }
-    env.fileManager.createDirectory = { _ in throw error }
-    let create: MessengerCreate = .live(env)
+    env.directoryManager.remove = { _ in }
+    env.directoryManager.create = { _ in throw error }
+    let create: Create = .live(env)
 
     XCTAssertThrowsError(try create()) { err in
       XCTAssertEqual(err as? Error, error)
@@ -139,16 +139,16 @@ final class MessengerCreateTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.ndfEnvironment = .unimplemented
     env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
     env.generateSecret.run = { _ in "password".data(using: .utf8)! }
     env.passwordStorage.save = { _ in }
     env.storageDir = "storage-dir"
-    env.fileManager.removeDirectory = { _ in }
-    env.fileManager.createDirectory = { _ in }
+    env.directoryManager.remove = { _ in }
+    env.directoryManager.create = { _ in }
     env.newCMix.run = { _, _, _, _ in throw error }
-    let create: MessengerCreate = .live(env)
+    let create: Create = .live(env)
 
     XCTAssertThrowsError(try create()) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Functors/IsConnectedTests.swift b/Tests/XXMessengerClientTests/Functors/IsConnectedTests.swift
new file mode 100644
index 00000000..05972e05
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Functors/IsConnectedTests.swift
@@ -0,0 +1,20 @@
+import XCTest
+@testable import XXMessengerClient
+
+final class IsConnectedTests: XCTestCase {
+  func testWithE2E() {
+    var env: Environment = .unimplemented
+    env.e2e.get = { .unimplemented }
+    let isConnected: IsConnected = .live(env)
+
+    XCTAssertTrue(isConnected())
+  }
+
+  func testWithoutE2E() {
+    var env: Environment = .unimplemented
+    env.e2e.get = { nil }
+    let isConnected: IsConnected = .live(env)
+
+    XCTAssertFalse(isConnected())
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift b/Tests/XXMessengerClientTests/Functors/IsCreatedTests.swift
similarity index 65%
rename from Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift
rename to Tests/XXMessengerClientTests/Functors/IsCreatedTests.swift
index 246be9d3..dbdd3407 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift
+++ b/Tests/XXMessengerClientTests/Functors/IsCreatedTests.swift
@@ -2,18 +2,18 @@ import CustomDump
 import XCTest
 @testable import XXMessengerClient
 
-final class MessengerIsCreatedTests: XCTestCase {
+final class IsCreatedTests: XCTestCase {
   func testStorageDirNotEmpty() {
     var didIsDirectoryEmpty: [String] = []
     let storageDir = "storage-dir"
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.storageDir = storageDir
-    env.fileManager.isDirectoryEmpty = { path in
+    env.directoryManager.isEmpty = { path in
       didIsDirectoryEmpty.append(path)
       return false
     }
-    let isCreated: MessengerIsCreated = .live(env)
+    let isCreated: IsCreated = .live(env)
 
     XCTAssertTrue(isCreated())
     XCTAssertNoDifference(didIsDirectoryEmpty, [storageDir])
@@ -23,13 +23,13 @@ final class MessengerIsCreatedTests: XCTestCase {
     var didIsDirectoryEmpty: [String] = []
     let storageDir = "storage-dir"
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.storageDir = storageDir
-    env.fileManager.isDirectoryEmpty = { path in
+    env.directoryManager.isEmpty = { path in
       didIsDirectoryEmpty.append(path)
       return true
     }
-    let isCreated: MessengerIsCreated = .live(env)
+    let isCreated: IsCreated = .live(env)
 
     XCTAssertFalse(isCreated())
     XCTAssertNoDifference(didIsDirectoryEmpty, [storageDir])
diff --git a/Tests/XXMessengerClientTests/Functors/IsLoadedTests.swift b/Tests/XXMessengerClientTests/Functors/IsLoadedTests.swift
new file mode 100644
index 00000000..37adffbe
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Functors/IsLoadedTests.swift
@@ -0,0 +1,20 @@
+import XCTest
+@testable import XXMessengerClient
+
+final class IsLoadedTests: XCTestCase {
+  func testWithCMix() {
+    var env: Environment = .unimplemented
+    env.cMix.get = { .unimplemented }
+    let isLoaded: IsLoaded = .live(env)
+
+    XCTAssertTrue(isLoaded())
+  }
+
+  func testWithoutCMix() {
+    var env: Environment = .unimplemented
+    env.cMix.get = { nil }
+    let isLoaded: IsLoaded = .live(env)
+
+    XCTAssertFalse(isLoaded())
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Functors/IsLoggedInTests.swift b/Tests/XXMessengerClientTests/Functors/IsLoggedInTests.swift
new file mode 100644
index 00000000..31f60325
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Functors/IsLoggedInTests.swift
@@ -0,0 +1,20 @@
+import XCTest
+@testable import XXMessengerClient
+
+final class IsLoggedInTests: XCTestCase {
+  func testWithUD() {
+    var env: Environment = .unimplemented
+    env.ud.get = { .unimplemented }
+    let isLoggedIn: IsLoggedIn = .live(env)
+
+    XCTAssertTrue(isLoggedIn())
+  }
+
+  func testWithoutUD() {
+    var env: Environment = .unimplemented
+    env.ud.get = { nil }
+    let isLoggedIn: IsLoggedIn = .live(env)
+
+    XCTAssertFalse(isLoggedIn())
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift b/Tests/XXMessengerClientTests/Functors/IsRegisteredTests.swift
similarity index 67%
rename from Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
rename to Tests/XXMessengerClientTests/Functors/IsRegisteredTests.swift
index b6dca3e9..1069fb5e 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
+++ b/Tests/XXMessengerClientTests/Functors/IsRegisteredTests.swift
@@ -2,11 +2,11 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class MessengerIsRegisteredTests: XCTestCase {
+final class IsRegisteredTests: XCTestCase {
   func testRegistered() throws {
     var didIsRegisteredWithUD: [Int] = []
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { 1234 }
@@ -16,34 +16,34 @@ final class MessengerIsRegisteredTests: XCTestCase {
       didIsRegisteredWithUD.append(e2eId)
       return true
     }
-    let isRegistered: MessengerIsRegistered = .live(env)
+    let isRegistered: IsRegistered = .live(env)
 
     XCTAssertTrue(try isRegistered())
     XCTAssertEqual(didIsRegisteredWithUD, [1234])
   }
 
   func testNotRegistered() throws {
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { 1234 }
       return e2e
     }
     env.isRegisteredWithUD.run = { _ in false }
-    let isRegistered: MessengerIsRegistered = .live(env)
+    let isRegistered: IsRegistered = .live(env)
 
     XCTAssertFalse(try isRegistered())
   }
 
   func testWithoutE2E() {
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.e2e.get = { nil }
-    let isRegistered: MessengerIsRegistered = .live(env)
+    let isRegistered: IsRegistered = .live(env)
 
     XCTAssertThrowsError(try isRegistered()) { err in
       XCTAssertEqual(
-        err as? MessengerIsRegistered.Error,
-        MessengerIsRegistered.Error.notConnected
+        err as? IsRegistered.Error,
+        IsRegistered.Error.notConnected
       )
     }
   }
@@ -52,14 +52,14 @@ final class MessengerIsRegisteredTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { 1234 }
       return e2e
     }
     env.isRegisteredWithUD.run = { _ in throw error }
-    let isRegistered: MessengerIsRegistered = .live(env)
+    let isRegistered: IsRegistered = .live(env)
 
     XCTAssertThrowsError(try isRegistered()) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift b/Tests/XXMessengerClientTests/Functors/LoadTests.swift
similarity index 85%
rename from Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
rename to Tests/XXMessengerClientTests/Functors/LoadTests.swift
index 5eb90e3a..fc07659b 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
+++ b/Tests/XXMessengerClientTests/Functors/LoadTests.swift
@@ -3,7 +3,7 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class MessengerLoadTests: XCTestCase {
+final class LoadTests: XCTestCase {
   func testLoad() throws {
     struct DidLoadCMix: Equatable {
       var storageDir: String
@@ -17,7 +17,7 @@ final class MessengerLoadTests: XCTestCase {
     let password = "password".data(using: .utf8)!
     let cMixParams = "cmix-params".data(using: .utf8)!
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.set = { didSetCMix.append($0) }
     env.storageDir = storageDir
     env.passwordStorage.load = { password }
@@ -30,7 +30,7 @@ final class MessengerLoadTests: XCTestCase {
       ))
       return .unimplemented
     }
-    let load: MessengerLoad = .live(env)
+    let load: Load = .live(env)
 
     try load()
 
@@ -45,10 +45,10 @@ final class MessengerLoadTests: XCTestCase {
   }
 
   func testMissingPassword() {
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.storageDir = "storage-dir"
     env.passwordStorage.load = { throw PasswordStorage.MissingPasswordError() }
-    let load: MessengerLoad = .live(env)
+    let load: Load = .live(env)
 
     XCTAssertThrowsError(try load()) { err in
       XCTAssertEqual(
@@ -62,12 +62,12 @@ final class MessengerLoadTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.storageDir = "storage-dir"
     env.passwordStorage.load = { "password".data(using: .utf8)! }
     env.getCMixParams.run = { "cmix-params".data(using: .utf8)! }
     env.loadCMix.run = { _, _, _ in throw error }
-    let load: MessengerLoad = .live(env)
+    let load: Load = .live(env)
 
     XCTAssertThrowsError(try load()) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift b/Tests/XXMessengerClientTests/Functors/LogInTests.swift
similarity index 85%
rename from Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
rename to Tests/XXMessengerClientTests/Functors/LogInTests.swift
index 83dd2cd0..cf8a3708 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
+++ b/Tests/XXMessengerClientTests/Functors/LogInTests.swift
@@ -3,7 +3,7 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class MessengerLogInTests: XCTestCase {
+final class LogInTests: XCTestCase {
   func testLogin() throws {
     var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
     var didNewOrLoadUDWithFollower: [UdNetworkStatus] = []
@@ -15,7 +15,7 @@ final class MessengerLogInTests: XCTestCase {
     let udContactFromNDF = "ndf-ud-contact".data(using: .utf8)!
     let udAddressFromNDF = "ndf-ud-address"
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { networkFollowerStatus }
@@ -38,7 +38,7 @@ final class MessengerLogInTests: XCTestCase {
       didNewOrLoadUDWithFollower.append(follower)
       return .unimplemented
     }
-    let logIn: MessengerLogIn = .live(env)
+    let logIn: LogIn = .live(env)
     try logIn()
 
     XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
@@ -66,7 +66,7 @@ final class MessengerLogInTests: XCTestCase {
     let altUdContact = "alt-ud-contact".data(using: .utf8)!
     let altUdAddress = "alt-ud-address"
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
@@ -85,7 +85,7 @@ final class MessengerLogInTests: XCTestCase {
       didNewOrLoadUDWithParams.append(params)
       return .unimplemented
     }
-    let logIn: MessengerLogIn = .live(env)
+    let logIn: LogIn = .live(env)
     try logIn()
 
     XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
@@ -100,28 +100,28 @@ final class MessengerLogInTests: XCTestCase {
   }
 
   func testLoginWithoutCMix() {
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = { nil }
-    let logIn: MessengerLogIn = .live(env)
+    let logIn: LogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { error in
       XCTAssertEqual(
-        error as? MessengerLogIn.Error,
-        MessengerLogIn.Error.notLoaded
+        error as? LogIn.Error,
+        LogIn.Error.notLoaded
       )
     }
   }
 
   func testLoginWithoutE2E() {
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = { .unimplemented }
     env.e2e.get = { nil }
-    let logIn: MessengerLogIn = .live(env)
+    let logIn: LogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { error in
       XCTAssertEqual(
-        error as? MessengerLogIn.Error,
-        MessengerLogIn.Error.notConnected
+        error as? LogIn.Error,
+        LogIn.Error.notConnected
       )
     }
   }
@@ -130,7 +130,7 @@ final class MessengerLogInTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
@@ -145,7 +145,7 @@ final class MessengerLogInTests: XCTestCase {
     }
     env.udCert = nil
     env.udContact = nil
-    let logIn: MessengerLogIn = .live(env)
+    let logIn: LogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { err in
       XCTAssertEqual(err as? Error, error)
@@ -156,7 +156,7 @@ final class MessengerLogInTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
@@ -171,7 +171,7 @@ final class MessengerLogInTests: XCTestCase {
     env.udContact = "ud-contact".data(using: .utf8)!
     env.udAddress = "ud-address"
     env.newOrLoadUd.run = { _, _ in throw error }
-    let logIn: MessengerLogIn = .live(env)
+    let logIn: LogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift b/Tests/XXMessengerClientTests/Functors/RegisterTests.swift
similarity index 86%
rename from Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
rename to Tests/XXMessengerClientTests/Functors/RegisterTests.swift
index ef96b251..b43e967a 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
+++ b/Tests/XXMessengerClientTests/Functors/RegisterTests.swift
@@ -3,7 +3,7 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class MessengerRegisterTests: XCTestCase {
+final class RegisterTests: XCTestCase {
   func testRegister() throws {
     var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
     var didNewOrLoadUDWithFollower: [UdNetworkStatus] = []
@@ -17,7 +17,7 @@ final class MessengerRegisterTests: XCTestCase {
     let udAddressFromNDF = "ndf-ud-address"
     let username = "new-user-name"
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { networkFollowerStatus }
@@ -43,7 +43,7 @@ final class MessengerRegisterTests: XCTestCase {
       didNewOrLoadUDWithFollower.append(follower)
       return .unimplemented
     }
-    let register: MessengerRegister = .live(env)
+    let register: Register = .live(env)
     try register(username: username)
 
     XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
@@ -73,7 +73,7 @@ final class MessengerRegisterTests: XCTestCase {
     let altUdAddress = "alt-ud-address"
     let username = "new-user-name"
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
@@ -95,7 +95,7 @@ final class MessengerRegisterTests: XCTestCase {
       didNewOrLoadUDWithParams.append(params)
       return .unimplemented
     }
-    let register: MessengerRegister = .live(env)
+    let register: Register = .live(env)
     try register(username: username)
 
     XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
@@ -110,28 +110,28 @@ final class MessengerRegisterTests: XCTestCase {
   }
 
   func testRegisterWithoutCMix() {
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = { nil }
-    let register: MessengerRegister = .live(env)
+    let register: Register = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { error in
       XCTAssertEqual(
-        error as? MessengerRegister.Error,
-        MessengerRegister.Error.notLoaded
+        error as? Register.Error,
+        Register.Error.notLoaded
       )
     }
   }
 
   func testRegisterWithoutE2E() {
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = { .unimplemented }
     env.e2e.get = { nil }
-    let register: MessengerRegister = .live(env)
+    let register: Register = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { error in
       XCTAssertEqual(
-        error as? MessengerRegister.Error,
-        MessengerRegister.Error.notConnected
+        error as? Register.Error,
+        Register.Error.notConnected
       )
     }
   }
@@ -140,7 +140,7 @@ final class MessengerRegisterTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
@@ -158,7 +158,7 @@ final class MessengerRegisterTests: XCTestCase {
     }
     env.udCert = nil
     env.udContact = nil
-    let register: MessengerRegister = .live(env)
+    let register: Register = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { err in
       XCTAssertEqual(err as? Error, error)
@@ -169,7 +169,7 @@ final class MessengerRegisterTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
@@ -187,7 +187,7 @@ final class MessengerRegisterTests: XCTestCase {
     env.udContact = "ud-contact".data(using: .utf8)!
     env.udAddress = "ud-address"
     env.newOrLoadUd.run = { _, _ in throw error }
-    let register: MessengerRegister = .live(env)
+    let register: Register = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift b/Tests/XXMessengerClientTests/Functors/StartTests.swift
similarity index 71%
rename from Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift
rename to Tests/XXMessengerClientTests/Functors/StartTests.swift
index 7b3e33af..f15d6f1d 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift
+++ b/Tests/XXMessengerClientTests/Functors/StartTests.swift
@@ -3,11 +3,11 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class MessengerStartTests: XCTestCase {
+final class StartTests: XCTestCase {
   func testStart() throws {
     var didStartNetworkFollower: [Int] = []
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .stopped }
@@ -16,7 +16,7 @@ final class MessengerStartTests: XCTestCase {
       }
       return cMix
     }
-    let start: MessengerStart = .live(env)
+    let start: Start = .live(env)
 
     try start(timeoutMS: 123)
 
@@ -24,26 +24,26 @@ final class MessengerStartTests: XCTestCase {
   }
 
   func testStartWhenNotLoaded() {
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = { nil }
-    let start: MessengerStart = .live(env)
+    let start: Start = .live(env)
 
     XCTAssertThrowsError(try start()) { error in
       XCTAssertEqual(
-        error as? MessengerStart.Error,
-        MessengerStart.Error.notLoaded
+        error as? Start.Error,
+        Start.Error.notLoaded
       )
     }
   }
 
   func testStartWhenRunning() throws {
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
       return cMix
     }
-    let start: MessengerStart = .live(env)
+    let start: Start = .live(env)
 
     try start()
   }
@@ -52,14 +52,14 @@ final class MessengerStartTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .stopped }
       cMix.startNetworkFollower.run = { _ in throw error }
       return cMix
     }
-    let start: MessengerStart = .live(env)
+    let start: Start = .live(env)
 
     XCTAssertThrowsError(try start()) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift b/Tests/XXMessengerClientTests/Functors/WaitForNetworkTests.swift
similarity index 60%
rename from Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift
rename to Tests/XXMessengerClientTests/Functors/WaitForNetworkTests.swift
index 1dbae735..f0d15ca7 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift
+++ b/Tests/XXMessengerClientTests/Functors/WaitForNetworkTests.swift
@@ -3,11 +3,11 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class MessengerWaitForNetworkTests: XCTestCase {
+final class WaitForNetworkTests: XCTestCase {
   func testWaitSuccess() throws {
     var didWaitForNetwork: [Int] = []
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.waitForNetwork.run = { timeoutMS in
@@ -16,7 +16,7 @@ final class MessengerWaitForNetworkTests: XCTestCase {
       }
       return cMix
     }
-    let waitForNetwork: MessengerWaitForNetwork = .live(env)
+    let waitForNetwork: WaitForNetwork = .live(env)
 
     try waitForNetwork(timeoutMS: 123)
 
@@ -24,31 +24,31 @@ final class MessengerWaitForNetworkTests: XCTestCase {
   }
 
   func testWaitWhenNotLoaded() {
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = { nil }
-    let waitForNetwork: MessengerWaitForNetwork = .live(env)
+    let waitForNetwork: WaitForNetwork = .live(env)
 
     XCTAssertThrowsError(try waitForNetwork()) { error in
       XCTAssertEqual(
-        error as? MessengerWaitForNetwork.Error,
-        MessengerWaitForNetwork.Error.notLoaded
+        error as? WaitForNetwork.Error,
+        WaitForNetwork.Error.notLoaded
       )
     }
   }
 
   func testWaitTimeout() {
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.waitForNetwork.run = { _ in false }
       return cMix
     }
-    let waitForNetwork: MessengerWaitForNetwork = .live(env)
+    let waitForNetwork: WaitForNetwork = .live(env)
 
     XCTAssertThrowsError(try waitForNetwork()) { error in
       XCTAssertEqual(
-        error as? MessengerWaitForNetwork.Error,
-        MessengerWaitForNetwork.Error.timeout
+        error as? WaitForNetwork.Error,
+        WaitForNetwork.Error.timeout
       )
     }
   }
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift b/Tests/XXMessengerClientTests/Functors/WaitForNodesTests.swift
similarity index 80%
rename from Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift
rename to Tests/XXMessengerClientTests/Functors/WaitForNodesTests.swift
index bc23afb5..e001d270 100644
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift
+++ b/Tests/XXMessengerClientTests/Functors/WaitForNodesTests.swift
@@ -3,16 +3,16 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class MessengerWaitForNodesTests: XCTestCase {
+final class WaitForNodesTests: XCTestCase {
   func testWaitWhenNotLoaded() {
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = { nil }
-    let waitForNodes: MessengerWaitForNodes = .live(env)
+    let waitForNodes: WaitForNodes = .live(env)
 
     XCTAssertThrowsError(try waitForNodes()) { error in
       XCTAssertEqual(
-        error as? MessengerWaitForNodes.Error,
-        MessengerWaitForNodes.Error.notLoaded
+        error as? WaitForNodes.Error,
+        WaitForNodes.Error.notLoaded
       )
     }
   }
@@ -20,7 +20,7 @@ final class MessengerWaitForNodesTests: XCTestCase {
   func testWaitWhenHasTargetRatio() throws {
     var didProgress: [NodeRegistrationReport] = []
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getNodeRegistrationStatus.run = {
@@ -28,7 +28,7 @@ final class MessengerWaitForNodesTests: XCTestCase {
       }
       return cMix
     }
-    let waitForNodes: MessengerWaitForNodes = .live(env)
+    let waitForNodes: WaitForNodes = .live(env)
 
     try waitForNodes(
       targetRatio: 0.7,
@@ -52,14 +52,14 @@ final class MessengerWaitForNodesTests: XCTestCase {
       .init(registered: 8, total: 10),
     ]
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getNodeRegistrationStatus.run = { reports.removeFirst() }
       return cMix
     }
     env.sleep = { didSleep.append($0) }
-    let waitForNodes: MessengerWaitForNodes = .live(env)
+    let waitForNodes: WaitForNodes = .live(env)
 
     try waitForNodes(
       targetRatio: 0.7,
@@ -87,14 +87,14 @@ final class MessengerWaitForNodesTests: XCTestCase {
       .init(registered: 6, total: 10),
     ]
 
-    var env: MessengerEnvironment = .unimplemented
+    var env: Environment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getNodeRegistrationStatus.run = { reports.removeFirst() }
       return cMix
     }
     env.sleep = { didSleep.append($0) }
-    let waitForNodes: MessengerWaitForNodes = .live(env)
+    let waitForNodes: WaitForNodes = .live(env)
 
     XCTAssertThrowsError(try waitForNodes(
       targetRatio: 0.7,
@@ -103,8 +103,8 @@ final class MessengerWaitForNodesTests: XCTestCase {
       onProgress: { didProgress.append($0) }
     )) { error in
       XCTAssertEqual(
-        error as? MessengerWaitForNodes.Error,
-        MessengerWaitForNodes.Error.timeout
+        error as? WaitForNodes.Error,
+        WaitForNodes.Error.timeout
       )
     }
 
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
deleted file mode 100644
index c7c5de8b..00000000
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
+++ /dev/null
@@ -1,20 +0,0 @@
-import XCTest
-@testable import XXMessengerClient
-
-final class MessengerIsConnectedTests: XCTestCase {
-  func testWithE2E() {
-    var env: MessengerEnvironment = .unimplemented
-    env.e2e.get = { .unimplemented }
-    let isConnected: MessengerIsConnected = .live(env)
-
-    XCTAssertTrue(isConnected())
-  }
-
-  func testWithoutE2E() {
-    var env: MessengerEnvironment = .unimplemented
-    env.e2e.get = { nil }
-    let isConnected: MessengerIsConnected = .live(env)
-
-    XCTAssertFalse(isConnected())
-  }
-}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
deleted file mode 100644
index 6f0591e2..00000000
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
+++ /dev/null
@@ -1,20 +0,0 @@
-import XCTest
-@testable import XXMessengerClient
-
-final class MessengerIsLoadedTests: XCTestCase {
-  func testWithCMix() {
-    var env: MessengerEnvironment = .unimplemented
-    env.cMix.get = { .unimplemented }
-    let isLoaded: MessengerIsLoaded = .live(env)
-
-    XCTAssertTrue(isLoaded())
-  }
-
-  func testWithoutCMix() {
-    var env: MessengerEnvironment = .unimplemented
-    env.cMix.get = { nil }
-    let isLoaded: MessengerIsLoaded = .live(env)
-
-    XCTAssertFalse(isLoaded())
-  }
-}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
deleted file mode 100644
index c6ea87e6..00000000
--- a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
+++ /dev/null
@@ -1,20 +0,0 @@
-import XCTest
-@testable import XXMessengerClient
-
-final class MessengerIsLoggedInTests: XCTestCase {
-  func testWithUD() {
-    var env: MessengerEnvironment = .unimplemented
-    env.ud.get = { .unimplemented }
-    let isLoggedIn: MessengerIsLoggedIn = .live(env)
-
-    XCTAssertTrue(isLoggedIn())
-  }
-
-  func testWithoutUD() {
-    var env: MessengerEnvironment = .unimplemented
-    env.ud.get = { nil }
-    let isLoggedIn: MessengerIsLoggedIn = .live(env)
-
-    XCTAssertFalse(isLoggedIn())
-  }
-}
diff --git a/Tests/XXMessengerClientTests/Messenger/Utils/StoredTests.swift b/Tests/XXMessengerClientTests/Utils/StoredTests.swift
similarity index 100%
rename from Tests/XXMessengerClientTests/Messenger/Utils/StoredTests.swift
rename to Tests/XXMessengerClientTests/Utils/StoredTests.swift
-- 
GitLab


From cdd28314f36d5c9119b43faaac4cd31ed98a7edb Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Tue, 23 Aug 2022 00:56:16 +0100
Subject: [PATCH 25/27] Revert "Refactor"

This reverts commit b7c181295fe02c4f9de10b9f567a7c8735f2e05a.
---
 Docs/XXMessengerClient.md                     |  4 +-
 .../Functors/IsConnected.swift                | 25 ------------
 .../Functors/IsCreated.swift                  | 24 -----------
 .../XXMessengerClient/Functors/IsLoaded.swift | 24 -----------
 .../Functors/IsLoggedIn.swift                 | 24 -----------
 .../Functors/MessengerConnect.swift}          | 12 +++---
 .../Functors/MessengerCreate.swift}           | 16 ++++----
 .../Functors/MessengerIsConnected.swift       | 25 ++++++++++++
 .../Functors/MessengerIsCreated.swift         | 24 +++++++++++
 .../Functors/MessengerIsLoaded.swift          | 24 +++++++++++
 .../Functors/MessengerIsLoggedIn.swift        | 24 +++++++++++
 .../Functors/MessengerIsRegistered.swift}     | 12 +++---
 .../Functors/MessengerLoad.swift}             | 12 +++---
 .../Functors/MessengerLogIn.swift}            | 12 +++---
 .../Functors/MessengerRegister.swift}         | 12 +++---
 .../Functors/MessengerStart.swift}            | 12 +++---
 .../Functors/MessengerWaitForNetwork.swift}   | 12 +++---
 .../Functors/MessengerWaitForNodes.swift}     | 12 +++---
 .../{ => Messenger}/Messenger.swift           | 28 ++++++-------
 .../MessengerEnvironment.swift}               | 20 +++++-----
 .../Utils/DirectoryManager.swift              | 40 -------------------
 .../Utils/MessengerFileManager.swift          | 40 +++++++++++++++++++
 .../Functors/IsConnectedTests.swift           | 20 ----------
 .../Functors/IsLoadedTests.swift              | 20 ----------
 .../Functors/IsLoggedInTests.swift            | 20 ----------
 .../Functors/MessengerConnectTests.swift}     | 22 +++++-----
 .../Functors/MessengerCreateTests.swift}      | 40 +++++++++----------
 .../Functors/MessengerIsConnectedTests.swift  | 20 ++++++++++
 .../Functors/MessengerIsCreatedTests.swift}   | 14 +++----
 .../Functors/MessengerIsLoadedTests.swift     | 20 ++++++++++
 .../Functors/MessengerIsLoggedInTests.swift   | 20 ++++++++++
 .../MessengerIsRegisteredTests.swift}         | 22 +++++-----
 .../Functors/MessengerLoadTests.swift}        | 14 +++----
 .../Functors/MessengerLogInTests.swift}       | 34 ++++++++--------
 .../Functors/MessengerRegisterTests.swift}    | 34 ++++++++--------
 .../Functors/MessengerStartTests.swift}       | 22 +++++-----
 .../MessengerWaitForNetworkTests.swift}       | 22 +++++-----
 .../MessengerWaitForNodesTests.swift}         | 26 ++++++------
 .../{ => Messenger}/Utils/StoredTests.swift   |  0
 39 files changed, 404 insertions(+), 404 deletions(-)
 delete mode 100644 Sources/XXMessengerClient/Functors/IsConnected.swift
 delete mode 100644 Sources/XXMessengerClient/Functors/IsCreated.swift
 delete mode 100644 Sources/XXMessengerClient/Functors/IsLoaded.swift
 delete mode 100644 Sources/XXMessengerClient/Functors/IsLoggedIn.swift
 rename Sources/XXMessengerClient/{Functors/Connect.swift => Messenger/Functors/MessengerConnect.swift} (67%)
 rename Sources/XXMessengerClient/{Functors/Create.swift => Messenger/Functors/MessengerCreate.swift} (61%)
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
 create mode 100644 Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
 rename Sources/XXMessengerClient/{Functors/IsRegistered.swift => Messenger/Functors/MessengerIsRegistered.swift} (59%)
 rename Sources/XXMessengerClient/{Functors/Load.swift => Messenger/Functors/MessengerLoad.swift} (61%)
 rename Sources/XXMessengerClient/{Functors/LogIn.swift => Messenger/Functors/MessengerLogIn.swift} (79%)
 rename Sources/XXMessengerClient/{Functors/Register.swift => Messenger/Functors/MessengerRegister.swift} (78%)
 rename Sources/XXMessengerClient/{Functors/Start.swift => Messenger/Functors/MessengerStart.swift} (68%)
 rename Sources/XXMessengerClient/{Functors/WaitForNetwork.swift => Messenger/Functors/MessengerWaitForNetwork.swift} (62%)
 rename Sources/XXMessengerClient/{Functors/WaitForNodes.swift => Messenger/Functors/MessengerWaitForNodes.swift} (75%)
 rename Sources/XXMessengerClient/{ => Messenger}/Messenger.swift (65%)
 rename Sources/XXMessengerClient/{Environment.swift => Messenger/MessengerEnvironment.swift} (83%)
 delete mode 100644 Sources/XXMessengerClient/Utils/DirectoryManager.swift
 create mode 100644 Sources/XXMessengerClient/Utils/MessengerFileManager.swift
 delete mode 100644 Tests/XXMessengerClientTests/Functors/IsConnectedTests.swift
 delete mode 100644 Tests/XXMessengerClientTests/Functors/IsLoadedTests.swift
 delete mode 100644 Tests/XXMessengerClientTests/Functors/IsLoggedInTests.swift
 rename Tests/XXMessengerClientTests/{Functors/ConnectTests.swift => Messenger/Functors/MessengerConnectTests.swift} (83%)
 rename Tests/XXMessengerClientTests/{Functors/CreateTests.swift => Messenger/Functors/MessengerCreateTests.swift} (80%)
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
 rename Tests/XXMessengerClientTests/{Functors/IsCreatedTests.swift => Messenger/Functors/MessengerIsCreatedTests.swift} (65%)
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
 rename Tests/XXMessengerClientTests/{Functors/IsRegisteredTests.swift => Messenger/Functors/MessengerIsRegisteredTests.swift} (67%)
 rename Tests/XXMessengerClientTests/{Functors/LoadTests.swift => Messenger/Functors/MessengerLoadTests.swift} (85%)
 rename Tests/XXMessengerClientTests/{Functors/LogInTests.swift => Messenger/Functors/MessengerLogInTests.swift} (85%)
 rename Tests/XXMessengerClientTests/{Functors/RegisterTests.swift => Messenger/Functors/MessengerRegisterTests.swift} (86%)
 rename Tests/XXMessengerClientTests/{Functors/StartTests.swift => Messenger/Functors/MessengerStartTests.swift} (71%)
 rename Tests/XXMessengerClientTests/{Functors/WaitForNetworkTests.swift => Messenger/Functors/MessengerWaitForNetworkTests.swift} (60%)
 rename Tests/XXMessengerClientTests/{Functors/WaitForNodesTests.swift => Messenger/Functors/MessengerWaitForNodesTests.swift} (80%)
 rename Tests/XXMessengerClientTests/{ => Messenger}/Utils/StoredTests.swift (100%)

diff --git a/Docs/XXMessengerClient.md b/Docs/XXMessengerClient.md
index fd9ac7ee..2dc19246 100644
--- a/Docs/XXMessengerClient.md
+++ b/Docs/XXMessengerClient.md
@@ -8,7 +8,7 @@ Example:
 
 ```swift
 // setup environment:
-var environment: Environment = .live()
+var environment: MessengerEnvironment = .live()
 
 // change cMix NDF environment if needed:
 environment.ndfEnvironment = ...
@@ -60,4 +60,4 @@ func start(messenger: Messenger) throws {
     }
   }
 }
-```
+```
\ No newline at end of file
diff --git a/Sources/XXMessengerClient/Functors/IsConnected.swift b/Sources/XXMessengerClient/Functors/IsConnected.swift
deleted file mode 100644
index 923d29df..00000000
--- a/Sources/XXMessengerClient/Functors/IsConnected.swift
+++ /dev/null
@@ -1,25 +0,0 @@
-import XXClient
-import XCTestDynamicOverlay
-
-public struct IsConnected {
-  public var run: () -> Bool
-
-  public func callAsFunction() -> Bool {
-    run()
-  }
-}
-
-extension IsConnected {
-  public static func live(_ env: Environment) -> IsConnected {
-    IsConnected {
-      env.e2e() != nil
-    }
-  }
-}
-
-extension IsConnected {
-  public static let unimplemented = IsConnected(
-    run: XCTUnimplemented()
-  )
-}
-
diff --git a/Sources/XXMessengerClient/Functors/IsCreated.swift b/Sources/XXMessengerClient/Functors/IsCreated.swift
deleted file mode 100644
index c9f55cff..00000000
--- a/Sources/XXMessengerClient/Functors/IsCreated.swift
+++ /dev/null
@@ -1,24 +0,0 @@
-import XXClient
-import XCTestDynamicOverlay
-
-public struct IsCreated {
-  public var run: () -> Bool
-
-  public func callAsFunction() -> Bool {
-    run()
-  }
-}
-
-extension IsCreated {
-  public static func live(_ env: Environment) -> IsCreated {
-    IsCreated {
-      env.directoryManager.isEmpty(env.storageDir) == false
-    }
-  }
-}
-
-extension IsCreated {
-  public static let unimplemented = IsCreated(
-    run: XCTUnimplemented()
-  )
-}
diff --git a/Sources/XXMessengerClient/Functors/IsLoaded.swift b/Sources/XXMessengerClient/Functors/IsLoaded.swift
deleted file mode 100644
index e3365cc3..00000000
--- a/Sources/XXMessengerClient/Functors/IsLoaded.swift
+++ /dev/null
@@ -1,24 +0,0 @@
-import XXClient
-import XCTestDynamicOverlay
-
-public struct IsLoaded {
-  public var run: () -> Bool
-
-  public func callAsFunction() -> Bool {
-    run()
-  }
-}
-
-extension IsLoaded {
-  public static func live(_ env: Environment) -> IsLoaded {
-    IsLoaded {
-      env.cMix() != nil
-    }
-  }
-}
-
-extension IsLoaded {
-  public static let unimplemented = IsLoaded(
-    run: XCTUnimplemented()
-  )
-}
diff --git a/Sources/XXMessengerClient/Functors/IsLoggedIn.swift b/Sources/XXMessengerClient/Functors/IsLoggedIn.swift
deleted file mode 100644
index bcf0dfdf..00000000
--- a/Sources/XXMessengerClient/Functors/IsLoggedIn.swift
+++ /dev/null
@@ -1,24 +0,0 @@
-import XXClient
-import XCTestDynamicOverlay
-
-public struct IsLoggedIn {
-  public var run: () -> Bool
-
-  public func callAsFunction() -> Bool {
-    run()
-  }
-}
-
-extension IsLoggedIn {
-  public static func live(_ env: Environment) -> IsLoggedIn {
-    IsLoggedIn {
-      env.ud() != nil
-    }
-  }
-}
-
-extension IsLoggedIn {
-  public static let unimplemented = IsLoggedIn(
-    run: XCTUnimplemented()
-  )
-}
diff --git a/Sources/XXMessengerClient/Functors/Connect.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
similarity index 67%
rename from Sources/XXMessengerClient/Functors/Connect.swift
rename to Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
index 47d649fe..8cebb73a 100644
--- a/Sources/XXMessengerClient/Functors/Connect.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerConnect.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct Connect {
+public struct MessengerConnect {
   public enum Error: Swift.Error, Equatable {
     case notLoaded
   }
@@ -13,9 +13,9 @@ public struct Connect {
   }
 }
 
-extension Connect {
-  public static func live(_ env: Environment) -> Connect {
-    Connect {
+extension MessengerConnect {
+  public static func live(_ env: MessengerEnvironment) -> MessengerConnect {
+    MessengerConnect {
       guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
@@ -28,8 +28,8 @@ extension Connect {
   }
 }
 
-extension Connect {
-  public static let unimplemented = Connect(
+extension MessengerConnect {
+  public static let unimplemented = MessengerConnect(
     run: XCTUnimplemented()
   )
 }
diff --git a/Sources/XXMessengerClient/Functors/Create.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift
similarity index 61%
rename from Sources/XXMessengerClient/Functors/Create.swift
rename to Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift
index 275722c7..b36b55b4 100644
--- a/Sources/XXMessengerClient/Functors/Create.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerCreate.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct Create {
+public struct MessengerCreate {
   public var run: () throws -> Void
 
   public func callAsFunction() throws {
@@ -9,15 +9,15 @@ public struct Create {
   }
 }
 
-extension Create {
-  public static func live(_ env: Environment) -> Create {
-    Create {
+extension MessengerCreate {
+  public static func live(_ env: MessengerEnvironment) -> MessengerCreate {
+    MessengerCreate {
       let ndfData = try env.downloadNDF(env.ndfEnvironment)
       let password = env.generateSecret()
       try env.passwordStorage.save(password)
       let storageDir = env.storageDir
-      try env.directoryManager.remove(storageDir)
-      try env.directoryManager.create(storageDir)
+      try env.fileManager.removeDirectory(storageDir)
+      try env.fileManager.createDirectory(storageDir)
       try env.newCMix(
         ndfJSON: String(data: ndfData, encoding: .utf8)!,
         storageDir: storageDir,
@@ -28,8 +28,8 @@ extension Create {
   }
 }
 
-extension Create {
-  public static let unimplemented = Create(
+extension MessengerCreate {
+  public static let unimplemented = MessengerCreate(
     run: XCTUnimplemented()
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
new file mode 100644
index 00000000..c30437fa
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsConnected.swift
@@ -0,0 +1,25 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerIsConnected {
+  public var run: () -> Bool
+
+  public func callAsFunction() -> Bool {
+    run()
+  }
+}
+
+extension MessengerIsConnected {
+  public static func live(_ env: MessengerEnvironment) -> MessengerIsConnected {
+    MessengerIsConnected {
+      env.e2e() != nil
+    }
+  }
+}
+
+extension MessengerIsConnected {
+  public static let unimplemented = MessengerIsConnected(
+    run: XCTUnimplemented()
+  )
+}
+
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift
new file mode 100644
index 00000000..c848518c
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsCreated.swift
@@ -0,0 +1,24 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerIsCreated {
+  public var run: () -> Bool
+
+  public func callAsFunction() -> Bool {
+    run()
+  }
+}
+
+extension MessengerIsCreated {
+  public static func live(_ env: MessengerEnvironment) -> MessengerIsCreated {
+    MessengerIsCreated {
+      env.fileManager.isDirectoryEmpty(env.storageDir) == false
+    }
+  }
+}
+
+extension MessengerIsCreated {
+  public static let unimplemented = MessengerIsCreated(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
new file mode 100644
index 00000000..dc0b4216
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoaded.swift
@@ -0,0 +1,24 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerIsLoaded {
+  public var run: () -> Bool
+
+  public func callAsFunction() -> Bool {
+    run()
+  }
+}
+
+extension MessengerIsLoaded {
+  public static func live(_ env: MessengerEnvironment) -> MessengerIsLoaded {
+    MessengerIsLoaded {
+      env.cMix() != nil
+    }
+  }
+}
+
+extension MessengerIsLoaded {
+  public static let unimplemented = MessengerIsLoaded(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
new file mode 100644
index 00000000..7c54c578
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsLoggedIn.swift
@@ -0,0 +1,24 @@
+import XXClient
+import XCTestDynamicOverlay
+
+public struct MessengerIsLoggedIn {
+  public var run: () -> Bool
+
+  public func callAsFunction() -> Bool {
+    run()
+  }
+}
+
+extension MessengerIsLoggedIn {
+  public static func live(_ env: MessengerEnvironment) -> MessengerIsLoggedIn {
+    MessengerIsLoggedIn {
+      env.ud() != nil
+    }
+  }
+}
+
+extension MessengerIsLoggedIn {
+  public static let unimplemented = MessengerIsLoggedIn(
+    run: XCTUnimplemented()
+  )
+}
diff --git a/Sources/XXMessengerClient/Functors/IsRegistered.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
similarity index 59%
rename from Sources/XXMessengerClient/Functors/IsRegistered.swift
rename to Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
index 4ccc2ce7..bf3cafa5 100644
--- a/Sources/XXMessengerClient/Functors/IsRegistered.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerIsRegistered.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct IsRegistered {
+public struct MessengerIsRegistered {
   public enum Error: Swift.Error, Equatable {
     case notConnected
   }
@@ -13,9 +13,9 @@ public struct IsRegistered {
   }
 }
 
-extension IsRegistered {
-  public static func live(_ env: Environment) -> IsRegistered {
-    IsRegistered {
+extension MessengerIsRegistered {
+  public static func live(_ env: MessengerEnvironment) -> MessengerIsRegistered {
+    MessengerIsRegistered {
       guard let e2e = env.e2e() else {
         throw Error.notConnected
       }
@@ -24,8 +24,8 @@ extension IsRegistered {
   }
 }
 
-extension IsRegistered {
-  public static let unimplemented = IsRegistered(
+extension MessengerIsRegistered {
+  public static let unimplemented = MessengerIsRegistered(
     run: XCTUnimplemented()
   )
 }
diff --git a/Sources/XXMessengerClient/Functors/Load.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
similarity index 61%
rename from Sources/XXMessengerClient/Functors/Load.swift
rename to Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
index 03010a22..29f28168 100644
--- a/Sources/XXMessengerClient/Functors/Load.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerLoad.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct Load {
+public struct MessengerLoad {
   public var run: () throws -> Void
 
   public func callAsFunction() throws {
@@ -9,9 +9,9 @@ public struct Load {
   }
 }
 
-extension Load {
-  public static func live(_ env: Environment) -> Load {
-    Load {
+extension MessengerLoad {
+  public static func live(_ env: MessengerEnvironment) -> MessengerLoad {
+    MessengerLoad {
       env.cMix.set(try env.loadCMix(
         storageDir: env.storageDir,
         password: try env.passwordStorage.load(),
@@ -21,8 +21,8 @@ extension Load {
   }
 }
 
-extension Load {
-  public static let unimplemented = Load(
+extension MessengerLoad {
+  public static let unimplemented = MessengerLoad(
     run: XCTUnimplemented()
   )
 }
diff --git a/Sources/XXMessengerClient/Functors/LogIn.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
similarity index 79%
rename from Sources/XXMessengerClient/Functors/LogIn.swift
rename to Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
index db2c34f9..d0f86d8b 100644
--- a/Sources/XXMessengerClient/Functors/LogIn.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerLogIn.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct LogIn {
+public struct MessengerLogIn {
   public enum Error: Swift.Error, Equatable {
     case notLoaded
     case notConnected
@@ -14,9 +14,9 @@ public struct LogIn {
   }
 }
 
-extension LogIn {
-  public static func live(_ env: Environment) -> LogIn {
-    LogIn {
+extension MessengerLogIn {
+  public static func live(_ env: MessengerEnvironment) -> MessengerLogIn {
+    MessengerLogIn {
       guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
@@ -40,8 +40,8 @@ extension LogIn {
   }
 }
 
-extension LogIn {
-  public static let unimplemented = LogIn(
+extension MessengerLogIn {
+  public static let unimplemented = MessengerLogIn(
     run: XCTUnimplemented()
   )
 }
diff --git a/Sources/XXMessengerClient/Functors/Register.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
similarity index 78%
rename from Sources/XXMessengerClient/Functors/Register.swift
rename to Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
index 3608ea93..6f429631 100644
--- a/Sources/XXMessengerClient/Functors/Register.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerRegister.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct Register {
+public struct MessengerRegister {
   public enum Error: Swift.Error, Equatable {
     case notLoaded
     case notConnected
@@ -16,9 +16,9 @@ public struct Register {
   }
 }
 
-extension Register {
-  public static func live(_ env: Environment) -> Register {
-    Register { username in
+extension MessengerRegister {
+  public static func live(_ env: MessengerEnvironment) -> MessengerRegister {
+    MessengerRegister { username in
       guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
@@ -42,8 +42,8 @@ extension Register {
   }
 }
 
-extension Register {
-  public static let unimplemented = Register(
+extension MessengerRegister {
+  public static let unimplemented = MessengerRegister(
     run: XCTUnimplemented()
   )
 }
diff --git a/Sources/XXMessengerClient/Functors/Start.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift
similarity index 68%
rename from Sources/XXMessengerClient/Functors/Start.swift
rename to Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift
index 77e32812..cc3363ec 100644
--- a/Sources/XXMessengerClient/Functors/Start.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerStart.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct Start {
+public struct MessengerStart {
   public enum Error: Swift.Error {
     case notLoaded
   }
@@ -15,9 +15,9 @@ public struct Start {
   }
 }
 
-extension Start {
-  public static func live(_ env: Environment) -> Start {
-    Start { timeoutMS in
+extension MessengerStart {
+  public static func live(_ env: MessengerEnvironment) -> MessengerStart {
+    MessengerStart { timeoutMS in
       guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
@@ -29,8 +29,8 @@ extension Start {
   }
 }
 
-extension Start {
-  public static let unimplemented = Start(
+extension MessengerStart {
+  public static let unimplemented = MessengerStart(
     run: XCTUnimplemented("\(Self.self)")
   )
 }
diff --git a/Sources/XXMessengerClient/Functors/WaitForNetwork.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift
similarity index 62%
rename from Sources/XXMessengerClient/Functors/WaitForNetwork.swift
rename to Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift
index 976e6423..8fe8cf3e 100644
--- a/Sources/XXMessengerClient/Functors/WaitForNetwork.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNetwork.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct WaitForNetwork {
+public struct MessengerWaitForNetwork {
   public enum Error: Swift.Error {
     case notLoaded
     case timeout
@@ -16,9 +16,9 @@ public struct WaitForNetwork {
   }
 }
 
-extension WaitForNetwork {
-  public static func live(_ env: Environment) -> WaitForNetwork {
-    WaitForNetwork { timeoutMS in
+extension MessengerWaitForNetwork {
+  public static func live(_ env: MessengerEnvironment) -> MessengerWaitForNetwork {
+    MessengerWaitForNetwork { timeoutMS in
       guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
@@ -29,8 +29,8 @@ extension WaitForNetwork {
   }
 }
 
-extension WaitForNetwork {
-  public static let unimplemented = WaitForNetwork(
+extension MessengerWaitForNetwork {
+  public static let unimplemented = MessengerWaitForNetwork(
     run: XCTUnimplemented("\(Self.self)")
   )
 }
diff --git a/Sources/XXMessengerClient/Functors/WaitForNodes.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
similarity index 75%
rename from Sources/XXMessengerClient/Functors/WaitForNodes.swift
rename to Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
index f08a2966..b87acc2f 100644
--- a/Sources/XXMessengerClient/Functors/WaitForNodes.swift
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerWaitForNodes.swift
@@ -1,7 +1,7 @@
 import XXClient
 import XCTestDynamicOverlay
 
-public struct WaitForNodes {
+public struct MessengerWaitForNodes {
   public typealias Progress = (NodeRegistrationReport) -> Void
 
   public enum Error: Swift.Error {
@@ -21,9 +21,9 @@ public struct WaitForNodes {
   }
 }
 
-extension WaitForNodes {
-  public static func live(_ env: Environment) -> WaitForNodes {
-    WaitForNodes { targetRatio, sleepMS, retries, onProgress in
+extension MessengerWaitForNodes {
+  public static func live(_ env: MessengerEnvironment) -> MessengerWaitForNodes {
+    MessengerWaitForNodes { targetRatio, sleepMS, retries, onProgress in
       guard let cMix = env.cMix() else {
         throw Error.notLoaded
       }
@@ -46,8 +46,8 @@ extension WaitForNodes {
   }
 }
 
-extension WaitForNodes {
-  public static let unimplemented = WaitForNodes(
+extension MessengerWaitForNodes {
+  public static let unimplemented = MessengerWaitForNodes(
     run: XCTUnimplemented("\(Self.self)")
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
similarity index 65%
rename from Sources/XXMessengerClient/Messenger.swift
rename to Sources/XXMessengerClient/Messenger/Messenger.swift
index b3ad9a58..30d63efd 100644
--- a/Sources/XXMessengerClient/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -4,23 +4,23 @@ public struct Messenger {
   public var cMix: Stored<CMix?>
   public var e2e: Stored<E2E?>
   public var ud: Stored<UserDiscovery?>
-  public var isCreated: IsCreated
-  public var create: Create
-  public var isLoaded: IsLoaded
-  public var load: Load
-  public var start: Start
-  public var isConnected: IsConnected
-  public var connect: Connect
-  public var isRegistered: IsRegistered
-  public var register: Register
-  public var isLoggedIn: IsLoggedIn
-  public var logIn: LogIn
-  public var waitForNetwork: WaitForNetwork
-  public var waitForNodes: WaitForNodes
+  public var isCreated: MessengerIsCreated
+  public var create: MessengerCreate
+  public var isLoaded: MessengerIsLoaded
+  public var load: MessengerLoad
+  public var start: MessengerStart
+  public var isConnected: MessengerIsConnected
+  public var connect: MessengerConnect
+  public var isRegistered: MessengerIsRegistered
+  public var register: MessengerRegister
+  public var isLoggedIn: MessengerIsLoggedIn
+  public var logIn: MessengerLogIn
+  public var waitForNetwork: MessengerWaitForNetwork
+  public var waitForNodes: MessengerWaitForNodes
 }
 
 extension Messenger {
-  public static func live(_ env: Environment) -> Messenger {
+  public static func live(_ env: MessengerEnvironment) -> Messenger {
     Messenger(
       cMix: env.cMix,
       e2e: env.e2e,
diff --git a/Sources/XXMessengerClient/Environment.swift b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
similarity index 83%
rename from Sources/XXMessengerClient/Environment.swift
rename to Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
index 58b18db9..0918142a 100644
--- a/Sources/XXMessengerClient/Environment.swift
+++ b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
@@ -2,11 +2,11 @@ import Foundation
 import XXClient
 import XCTestDynamicOverlay
 
-public struct Environment {
+public struct MessengerEnvironment {
   public var cMix: Stored<CMix?>
-  public var directoryManager: DirectoryManager
   public var downloadNDF: DownloadAndVerifySignedNdf
   public var e2e: Stored<E2E?>
+  public var fileManager: MessengerFileManager
   public var generateSecret: GenerateSecret
   public var getCMixParams: GetCMixParams
   public var getE2EParams: GetE2EParams
@@ -25,19 +25,19 @@ public struct Environment {
   public var udContact: Data?
 }
 
-extension Environment {
+extension MessengerEnvironment {
   public static let defaultStorageDir = FileManager.default
     .urls(for: .applicationSupportDirectory, in: .userDomainMask)
     .first!
     .appendingPathComponent("xx.network.client")
     .path
 
-  public static func live() -> Environment {
-    Environment(
+  public static func live() -> MessengerEnvironment {
+    MessengerEnvironment(
       cMix: .inMemory(),
-      directoryManager: .live(),
       downloadNDF: .live,
       e2e: .inMemory(),
+      fileManager: .live(),
       generateSecret: .live,
       getCMixParams: .liveDefault,
       getE2EParams: .liveDefault,
@@ -49,7 +49,7 @@ extension Environment {
       newOrLoadUd: .live,
       passwordStorage: .keychain,
       sleep: { Foundation.sleep(UInt32($0)) },
-      storageDir: Environment.defaultStorageDir,
+      storageDir: MessengerEnvironment.defaultStorageDir,
       ud: .inMemory(),
       udAddress: nil,
       udCert: nil,
@@ -58,12 +58,12 @@ extension Environment {
   }
 }
 
-extension Environment {
-  public static let unimplemented = Environment(
+extension MessengerEnvironment {
+  public static let unimplemented = MessengerEnvironment(
     cMix: .unimplemented(),
-    directoryManager: .unimplemented,
     downloadNDF: .unimplemented,
     e2e: .unimplemented(),
+    fileManager: .unimplemented,
     generateSecret: .unimplemented,
     getCMixParams: .unimplemented,
     getE2EParams: .unimplemented,
diff --git a/Sources/XXMessengerClient/Utils/DirectoryManager.swift b/Sources/XXMessengerClient/Utils/DirectoryManager.swift
deleted file mode 100644
index 16b9238e..00000000
--- a/Sources/XXMessengerClient/Utils/DirectoryManager.swift
+++ /dev/null
@@ -1,40 +0,0 @@
-import Foundation
-import XCTestDynamicOverlay
-
-public struct DirectoryManager {
-  public var isEmpty: (String) -> Bool
-  public var remove: (String) throws -> Void
-  public var create: (String) throws -> Void
-}
-
-extension DirectoryManager {
-  public static func live(
-    fileManager: FileManager = .default
-  ) -> DirectoryManager {
-    DirectoryManager(
-      isEmpty: { path in
-        let contents = try? fileManager.contentsOfDirectory(atPath: path)
-        return contents?.isEmpty ?? true
-      },
-      remove: { path in
-        if fileManager.fileExists(atPath: path) {
-          try fileManager.removeItem(atPath: path)
-        }
-      },
-      create: { path in
-        try fileManager.createDirectory(
-          atPath: path,
-          withIntermediateDirectories: true
-        )
-      }
-    )
-  }
-}
-
-extension DirectoryManager {
-  public static let unimplemented = DirectoryManager(
-    isEmpty: XCTUnimplemented("\(Self.self).isDirectoryEmpty"),
-    remove: XCTUnimplemented("\(Self.self).removeDirectory"),
-    create: XCTUnimplemented("\(Self.self).createDirectory")
-  )
-}
diff --git a/Sources/XXMessengerClient/Utils/MessengerFileManager.swift b/Sources/XXMessengerClient/Utils/MessengerFileManager.swift
new file mode 100644
index 00000000..4ff49c5f
--- /dev/null
+++ b/Sources/XXMessengerClient/Utils/MessengerFileManager.swift
@@ -0,0 +1,40 @@
+import Foundation
+import XCTestDynamicOverlay
+
+public struct MessengerFileManager {
+  public var isDirectoryEmpty: (String) -> Bool
+  public var removeDirectory: (String) throws -> Void
+  public var createDirectory: (String) throws -> Void
+}
+
+extension MessengerFileManager {
+  public static func live(
+    fileManager: FileManager = .default
+  ) -> MessengerFileManager {
+    MessengerFileManager(
+      isDirectoryEmpty: { path in
+        let contents = try? fileManager.contentsOfDirectory(atPath: path)
+        return contents?.isEmpty ?? true
+      },
+      removeDirectory: { path in
+        if fileManager.fileExists(atPath: path) {
+          try fileManager.removeItem(atPath: path)
+        }
+      },
+      createDirectory: { path in
+        try fileManager.createDirectory(
+          atPath: path,
+          withIntermediateDirectories: true
+        )
+      }
+    )
+  }
+}
+
+extension MessengerFileManager {
+  public static let unimplemented = MessengerFileManager(
+    isDirectoryEmpty: XCTUnimplemented("\(Self.self).isDirectoryEmpty"),
+    removeDirectory: XCTUnimplemented("\(Self.self).removeDirectory"),
+    createDirectory: XCTUnimplemented("\(Self.self).createDirectory")
+  )
+}
diff --git a/Tests/XXMessengerClientTests/Functors/IsConnectedTests.swift b/Tests/XXMessengerClientTests/Functors/IsConnectedTests.swift
deleted file mode 100644
index 05972e05..00000000
--- a/Tests/XXMessengerClientTests/Functors/IsConnectedTests.swift
+++ /dev/null
@@ -1,20 +0,0 @@
-import XCTest
-@testable import XXMessengerClient
-
-final class IsConnectedTests: XCTestCase {
-  func testWithE2E() {
-    var env: Environment = .unimplemented
-    env.e2e.get = { .unimplemented }
-    let isConnected: IsConnected = .live(env)
-
-    XCTAssertTrue(isConnected())
-  }
-
-  func testWithoutE2E() {
-    var env: Environment = .unimplemented
-    env.e2e.get = { nil }
-    let isConnected: IsConnected = .live(env)
-
-    XCTAssertFalse(isConnected())
-  }
-}
diff --git a/Tests/XXMessengerClientTests/Functors/IsLoadedTests.swift b/Tests/XXMessengerClientTests/Functors/IsLoadedTests.swift
deleted file mode 100644
index 37adffbe..00000000
--- a/Tests/XXMessengerClientTests/Functors/IsLoadedTests.swift
+++ /dev/null
@@ -1,20 +0,0 @@
-import XCTest
-@testable import XXMessengerClient
-
-final class IsLoadedTests: XCTestCase {
-  func testWithCMix() {
-    var env: Environment = .unimplemented
-    env.cMix.get = { .unimplemented }
-    let isLoaded: IsLoaded = .live(env)
-
-    XCTAssertTrue(isLoaded())
-  }
-
-  func testWithoutCMix() {
-    var env: Environment = .unimplemented
-    env.cMix.get = { nil }
-    let isLoaded: IsLoaded = .live(env)
-
-    XCTAssertFalse(isLoaded())
-  }
-}
diff --git a/Tests/XXMessengerClientTests/Functors/IsLoggedInTests.swift b/Tests/XXMessengerClientTests/Functors/IsLoggedInTests.swift
deleted file mode 100644
index 31f60325..00000000
--- a/Tests/XXMessengerClientTests/Functors/IsLoggedInTests.swift
+++ /dev/null
@@ -1,20 +0,0 @@
-import XCTest
-@testable import XXMessengerClient
-
-final class IsLoggedInTests: XCTestCase {
-  func testWithUD() {
-    var env: Environment = .unimplemented
-    env.ud.get = { .unimplemented }
-    let isLoggedIn: IsLoggedIn = .live(env)
-
-    XCTAssertTrue(isLoggedIn())
-  }
-
-  func testWithoutUD() {
-    var env: Environment = .unimplemented
-    env.ud.get = { nil }
-    let isLoggedIn: IsLoggedIn = .live(env)
-
-    XCTAssertFalse(isLoggedIn())
-  }
-}
diff --git a/Tests/XXMessengerClientTests/Functors/ConnectTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
similarity index 83%
rename from Tests/XXMessengerClientTests/Functors/ConnectTests.swift
rename to Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
index caac4d6a..fb780353 100644
--- a/Tests/XXMessengerClientTests/Functors/ConnectTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerConnectTests.swift
@@ -3,7 +3,7 @@ import XXClient
 import XCTest
 @testable import XXMessengerClient
 
-final class ConnectTests: XCTestCase {
+final class MessengerConnectTests: XCTestCase {
   func testConnect() throws {
     struct DidLogIn: Equatable {
       var ephemeral: Bool
@@ -20,7 +20,7 @@ final class ConnectTests: XCTestCase {
     let receptionId = ReceptionIdentity.stub
     let e2eParams = "e2e-params".data(using: .utf8)!
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getId.run = { cMixId }
@@ -39,7 +39,7 @@ final class ConnectTests: XCTestCase {
       ))
       return .unimplemented
     }
-    let connect: Connect = .live(env)
+    let connect: MessengerConnect = .live(env)
 
     try connect()
 
@@ -56,14 +56,14 @@ final class ConnectTests: XCTestCase {
   }
 
   func testConnectWithoutCMix() {
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = { nil }
-    let connect: Connect = .live(env)
+    let connect: MessengerConnect = .live(env)
 
     XCTAssertThrowsError(try connect()) { error in
       XCTAssertEqual(
-        error as? Connect.Error,
-        Connect.Error.notLoaded
+        error as? MessengerConnect.Error,
+        MessengerConnect.Error.notLoaded
       )
     }
   }
@@ -72,14 +72,14 @@ final class ConnectTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getId.run = { 1234 }
       cMix.makeLegacyReceptionIdentity.run = { throw error }
       return cMix
     }
-    let connect: Connect = .live(env)
+    let connect: MessengerConnect = .live(env)
 
     XCTAssertThrowsError(try connect()) { err in
       XCTAssertEqual(err as? Error, error)
@@ -90,7 +90,7 @@ final class ConnectTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getId.run = { 1234 }
@@ -99,7 +99,7 @@ final class ConnectTests: XCTestCase {
     }
     env.getE2EParams.run = { "e2e-params".data(using: .utf8)! }
     env.login.run = { _, _, _, _, _ in throw error }
-    let connect: Connect = .live(env)
+    let connect: MessengerConnect = .live(env)
 
     XCTAssertThrowsError(try connect()) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Functors/CreateTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
similarity index 80%
rename from Tests/XXMessengerClientTests/Functors/CreateTests.swift
rename to Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
index 0ef9e0d7..2180dda3 100644
--- a/Tests/XXMessengerClientTests/Functors/CreateTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerCreateTests.swift
@@ -3,7 +3,7 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class CreateTests: XCTestCase {
+final class MessengerCreateTests: XCTestCase {
   func testCreate() throws {
     struct DidNewCMix: Equatable {
       var ndfJSON: String
@@ -23,7 +23,7 @@ final class CreateTests: XCTestCase {
     let password = "password".data(using: .utf8)!
     let storageDir = "storage-dir"
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.ndfEnvironment = .unimplemented
     env.downloadNDF.run = { ndfEnvironment in
       didDownloadNDF.append(ndfEnvironment)
@@ -37,10 +37,10 @@ final class CreateTests: XCTestCase {
       didSavePassword.append(password)
     }
     env.storageDir = storageDir
-    env.directoryManager.remove = { path in
+    env.fileManager.removeDirectory = { path in
       didRemoveDirectory.append(path)
     }
-    env.directoryManager.create = { path in
+    env.fileManager.createDirectory = { path in
       didCreateDirectory.append(path)
     }
     env.newCMix.run = { ndfJSON, storageDir, password, registrationCode in
@@ -51,7 +51,7 @@ final class CreateTests: XCTestCase {
         registrationCode: registrationCode
       ))
     }
-    let create: Create = .live(env)
+    let create: MessengerCreate = .live(env)
 
     try create()
 
@@ -72,10 +72,10 @@ final class CreateTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.ndfEnvironment = .unimplemented
     env.downloadNDF.run = { _ in throw error }
-    let create: Create = .live(env)
+    let create: MessengerCreate = .live(env)
 
     XCTAssertThrowsError(try create()) { err in
       XCTAssertEqual(err as? Error, error)
@@ -86,12 +86,12 @@ final class CreateTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.ndfEnvironment = .unimplemented
     env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
     env.generateSecret.run = { _ in "password".data(using: .utf8)! }
     env.passwordStorage.save = { _ in throw error }
-    let create: Create = .live(env)
+    let create: MessengerCreate = .live(env)
 
     XCTAssertThrowsError(try create()) { err in
       XCTAssertEqual(err as? Error, error)
@@ -102,14 +102,14 @@ final class CreateTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.ndfEnvironment = .unimplemented
     env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
     env.generateSecret.run = { _ in "password".data(using: .utf8)! }
     env.passwordStorage.save = { _ in }
     env.storageDir = "storage-dir"
-    env.directoryManager.remove = { _ in throw error }
-    let create: Create = .live(env)
+    env.fileManager.removeDirectory = { _ in throw error }
+    let create: MessengerCreate = .live(env)
 
     XCTAssertThrowsError(try create()) { err in
       XCTAssertEqual(err as? Error, error)
@@ -120,15 +120,15 @@ final class CreateTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.ndfEnvironment = .unimplemented
     env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
     env.generateSecret.run = { _ in "password".data(using: .utf8)! }
     env.passwordStorage.save = { _ in }
     env.storageDir = "storage-dir"
-    env.directoryManager.remove = { _ in }
-    env.directoryManager.create = { _ in throw error }
-    let create: Create = .live(env)
+    env.fileManager.removeDirectory = { _ in }
+    env.fileManager.createDirectory = { _ in throw error }
+    let create: MessengerCreate = .live(env)
 
     XCTAssertThrowsError(try create()) { err in
       XCTAssertEqual(err as? Error, error)
@@ -139,16 +139,16 @@ final class CreateTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.ndfEnvironment = .unimplemented
     env.downloadNDF.run = { _ in "ndf".data(using: .utf8)! }
     env.generateSecret.run = { _ in "password".data(using: .utf8)! }
     env.passwordStorage.save = { _ in }
     env.storageDir = "storage-dir"
-    env.directoryManager.remove = { _ in }
-    env.directoryManager.create = { _ in }
+    env.fileManager.removeDirectory = { _ in }
+    env.fileManager.createDirectory = { _ in }
     env.newCMix.run = { _, _, _, _ in throw error }
-    let create: Create = .live(env)
+    let create: MessengerCreate = .live(env)
 
     XCTAssertThrowsError(try create()) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
new file mode 100644
index 00000000..c7c5de8b
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsConnectedTests.swift
@@ -0,0 +1,20 @@
+import XCTest
+@testable import XXMessengerClient
+
+final class MessengerIsConnectedTests: XCTestCase {
+  func testWithE2E() {
+    var env: MessengerEnvironment = .unimplemented
+    env.e2e.get = { .unimplemented }
+    let isConnected: MessengerIsConnected = .live(env)
+
+    XCTAssertTrue(isConnected())
+  }
+
+  func testWithoutE2E() {
+    var env: MessengerEnvironment = .unimplemented
+    env.e2e.get = { nil }
+    let isConnected: MessengerIsConnected = .live(env)
+
+    XCTAssertFalse(isConnected())
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Functors/IsCreatedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift
similarity index 65%
rename from Tests/XXMessengerClientTests/Functors/IsCreatedTests.swift
rename to Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift
index dbdd3407..246be9d3 100644
--- a/Tests/XXMessengerClientTests/Functors/IsCreatedTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsCreatedTests.swift
@@ -2,18 +2,18 @@ import CustomDump
 import XCTest
 @testable import XXMessengerClient
 
-final class IsCreatedTests: XCTestCase {
+final class MessengerIsCreatedTests: XCTestCase {
   func testStorageDirNotEmpty() {
     var didIsDirectoryEmpty: [String] = []
     let storageDir = "storage-dir"
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.storageDir = storageDir
-    env.directoryManager.isEmpty = { path in
+    env.fileManager.isDirectoryEmpty = { path in
       didIsDirectoryEmpty.append(path)
       return false
     }
-    let isCreated: IsCreated = .live(env)
+    let isCreated: MessengerIsCreated = .live(env)
 
     XCTAssertTrue(isCreated())
     XCTAssertNoDifference(didIsDirectoryEmpty, [storageDir])
@@ -23,13 +23,13 @@ final class IsCreatedTests: XCTestCase {
     var didIsDirectoryEmpty: [String] = []
     let storageDir = "storage-dir"
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.storageDir = storageDir
-    env.directoryManager.isEmpty = { path in
+    env.fileManager.isDirectoryEmpty = { path in
       didIsDirectoryEmpty.append(path)
       return true
     }
-    let isCreated: IsCreated = .live(env)
+    let isCreated: MessengerIsCreated = .live(env)
 
     XCTAssertFalse(isCreated())
     XCTAssertNoDifference(didIsDirectoryEmpty, [storageDir])
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
new file mode 100644
index 00000000..6f0591e2
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoadedTests.swift
@@ -0,0 +1,20 @@
+import XCTest
+@testable import XXMessengerClient
+
+final class MessengerIsLoadedTests: XCTestCase {
+  func testWithCMix() {
+    var env: MessengerEnvironment = .unimplemented
+    env.cMix.get = { .unimplemented }
+    let isLoaded: MessengerIsLoaded = .live(env)
+
+    XCTAssertTrue(isLoaded())
+  }
+
+  func testWithoutCMix() {
+    var env: MessengerEnvironment = .unimplemented
+    env.cMix.get = { nil }
+    let isLoaded: MessengerIsLoaded = .live(env)
+
+    XCTAssertFalse(isLoaded())
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
new file mode 100644
index 00000000..c6ea87e6
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsLoggedInTests.swift
@@ -0,0 +1,20 @@
+import XCTest
+@testable import XXMessengerClient
+
+final class MessengerIsLoggedInTests: XCTestCase {
+  func testWithUD() {
+    var env: MessengerEnvironment = .unimplemented
+    env.ud.get = { .unimplemented }
+    let isLoggedIn: MessengerIsLoggedIn = .live(env)
+
+    XCTAssertTrue(isLoggedIn())
+  }
+
+  func testWithoutUD() {
+    var env: MessengerEnvironment = .unimplemented
+    env.ud.get = { nil }
+    let isLoggedIn: MessengerIsLoggedIn = .live(env)
+
+    XCTAssertFalse(isLoggedIn())
+  }
+}
diff --git a/Tests/XXMessengerClientTests/Functors/IsRegisteredTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
similarity index 67%
rename from Tests/XXMessengerClientTests/Functors/IsRegisteredTests.swift
rename to Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
index 1069fb5e..b6dca3e9 100644
--- a/Tests/XXMessengerClientTests/Functors/IsRegisteredTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerIsRegisteredTests.swift
@@ -2,11 +2,11 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class IsRegisteredTests: XCTestCase {
+final class MessengerIsRegisteredTests: XCTestCase {
   func testRegistered() throws {
     var didIsRegisteredWithUD: [Int] = []
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { 1234 }
@@ -16,34 +16,34 @@ final class IsRegisteredTests: XCTestCase {
       didIsRegisteredWithUD.append(e2eId)
       return true
     }
-    let isRegistered: IsRegistered = .live(env)
+    let isRegistered: MessengerIsRegistered = .live(env)
 
     XCTAssertTrue(try isRegistered())
     XCTAssertEqual(didIsRegisteredWithUD, [1234])
   }
 
   func testNotRegistered() throws {
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { 1234 }
       return e2e
     }
     env.isRegisteredWithUD.run = { _ in false }
-    let isRegistered: IsRegistered = .live(env)
+    let isRegistered: MessengerIsRegistered = .live(env)
 
     XCTAssertFalse(try isRegistered())
   }
 
   func testWithoutE2E() {
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.e2e.get = { nil }
-    let isRegistered: IsRegistered = .live(env)
+    let isRegistered: MessengerIsRegistered = .live(env)
 
     XCTAssertThrowsError(try isRegistered()) { err in
       XCTAssertEqual(
-        err as? IsRegistered.Error,
-        IsRegistered.Error.notConnected
+        err as? MessengerIsRegistered.Error,
+        MessengerIsRegistered.Error.notConnected
       )
     }
   }
@@ -52,14 +52,14 @@ final class IsRegisteredTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.e2e.get = {
       var e2e: E2E = .unimplemented
       e2e.getId.run = { 1234 }
       return e2e
     }
     env.isRegisteredWithUD.run = { _ in throw error }
-    let isRegistered: IsRegistered = .live(env)
+    let isRegistered: MessengerIsRegistered = .live(env)
 
     XCTAssertThrowsError(try isRegistered()) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Functors/LoadTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
similarity index 85%
rename from Tests/XXMessengerClientTests/Functors/LoadTests.swift
rename to Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
index fc07659b..5eb90e3a 100644
--- a/Tests/XXMessengerClientTests/Functors/LoadTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLoadTests.swift
@@ -3,7 +3,7 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class LoadTests: XCTestCase {
+final class MessengerLoadTests: XCTestCase {
   func testLoad() throws {
     struct DidLoadCMix: Equatable {
       var storageDir: String
@@ -17,7 +17,7 @@ final class LoadTests: XCTestCase {
     let password = "password".data(using: .utf8)!
     let cMixParams = "cmix-params".data(using: .utf8)!
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.set = { didSetCMix.append($0) }
     env.storageDir = storageDir
     env.passwordStorage.load = { password }
@@ -30,7 +30,7 @@ final class LoadTests: XCTestCase {
       ))
       return .unimplemented
     }
-    let load: Load = .live(env)
+    let load: MessengerLoad = .live(env)
 
     try load()
 
@@ -45,10 +45,10 @@ final class LoadTests: XCTestCase {
   }
 
   func testMissingPassword() {
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.storageDir = "storage-dir"
     env.passwordStorage.load = { throw PasswordStorage.MissingPasswordError() }
-    let load: Load = .live(env)
+    let load: MessengerLoad = .live(env)
 
     XCTAssertThrowsError(try load()) { err in
       XCTAssertEqual(
@@ -62,12 +62,12 @@ final class LoadTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.storageDir = "storage-dir"
     env.passwordStorage.load = { "password".data(using: .utf8)! }
     env.getCMixParams.run = { "cmix-params".data(using: .utf8)! }
     env.loadCMix.run = { _, _, _ in throw error }
-    let load: Load = .live(env)
+    let load: MessengerLoad = .live(env)
 
     XCTAssertThrowsError(try load()) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Functors/LogInTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
similarity index 85%
rename from Tests/XXMessengerClientTests/Functors/LogInTests.swift
rename to Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
index cf8a3708..83dd2cd0 100644
--- a/Tests/XXMessengerClientTests/Functors/LogInTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerLogInTests.swift
@@ -3,7 +3,7 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class LogInTests: XCTestCase {
+final class MessengerLogInTests: XCTestCase {
   func testLogin() throws {
     var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
     var didNewOrLoadUDWithFollower: [UdNetworkStatus] = []
@@ -15,7 +15,7 @@ final class LogInTests: XCTestCase {
     let udContactFromNDF = "ndf-ud-contact".data(using: .utf8)!
     let udAddressFromNDF = "ndf-ud-address"
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { networkFollowerStatus }
@@ -38,7 +38,7 @@ final class LogInTests: XCTestCase {
       didNewOrLoadUDWithFollower.append(follower)
       return .unimplemented
     }
-    let logIn: LogIn = .live(env)
+    let logIn: MessengerLogIn = .live(env)
     try logIn()
 
     XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
@@ -66,7 +66,7 @@ final class LogInTests: XCTestCase {
     let altUdContact = "alt-ud-contact".data(using: .utf8)!
     let altUdAddress = "alt-ud-address"
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
@@ -85,7 +85,7 @@ final class LogInTests: XCTestCase {
       didNewOrLoadUDWithParams.append(params)
       return .unimplemented
     }
-    let logIn: LogIn = .live(env)
+    let logIn: MessengerLogIn = .live(env)
     try logIn()
 
     XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
@@ -100,28 +100,28 @@ final class LogInTests: XCTestCase {
   }
 
   func testLoginWithoutCMix() {
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = { nil }
-    let logIn: LogIn = .live(env)
+    let logIn: MessengerLogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { error in
       XCTAssertEqual(
-        error as? LogIn.Error,
-        LogIn.Error.notLoaded
+        error as? MessengerLogIn.Error,
+        MessengerLogIn.Error.notLoaded
       )
     }
   }
 
   func testLoginWithoutE2E() {
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = { .unimplemented }
     env.e2e.get = { nil }
-    let logIn: LogIn = .live(env)
+    let logIn: MessengerLogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { error in
       XCTAssertEqual(
-        error as? LogIn.Error,
-        LogIn.Error.notConnected
+        error as? MessengerLogIn.Error,
+        MessengerLogIn.Error.notConnected
       )
     }
   }
@@ -130,7 +130,7 @@ final class LogInTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
@@ -145,7 +145,7 @@ final class LogInTests: XCTestCase {
     }
     env.udCert = nil
     env.udContact = nil
-    let logIn: LogIn = .live(env)
+    let logIn: MessengerLogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { err in
       XCTAssertEqual(err as? Error, error)
@@ -156,7 +156,7 @@ final class LogInTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
@@ -171,7 +171,7 @@ final class LogInTests: XCTestCase {
     env.udContact = "ud-contact".data(using: .utf8)!
     env.udAddress = "ud-address"
     env.newOrLoadUd.run = { _, _ in throw error }
-    let logIn: LogIn = .live(env)
+    let logIn: MessengerLogIn = .live(env)
 
     XCTAssertThrowsError(try logIn()) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Functors/RegisterTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
similarity index 86%
rename from Tests/XXMessengerClientTests/Functors/RegisterTests.swift
rename to Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
index b43e967a..ef96b251 100644
--- a/Tests/XXMessengerClientTests/Functors/RegisterTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerRegisterTests.swift
@@ -3,7 +3,7 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class RegisterTests: XCTestCase {
+final class MessengerRegisterTests: XCTestCase {
   func testRegister() throws {
     var didNewOrLoadUDWithParams: [NewOrLoadUd.Params] = []
     var didNewOrLoadUDWithFollower: [UdNetworkStatus] = []
@@ -17,7 +17,7 @@ final class RegisterTests: XCTestCase {
     let udAddressFromNDF = "ndf-ud-address"
     let username = "new-user-name"
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { networkFollowerStatus }
@@ -43,7 +43,7 @@ final class RegisterTests: XCTestCase {
       didNewOrLoadUDWithFollower.append(follower)
       return .unimplemented
     }
-    let register: Register = .live(env)
+    let register: MessengerRegister = .live(env)
     try register(username: username)
 
     XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
@@ -73,7 +73,7 @@ final class RegisterTests: XCTestCase {
     let altUdAddress = "alt-ud-address"
     let username = "new-user-name"
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
@@ -95,7 +95,7 @@ final class RegisterTests: XCTestCase {
       didNewOrLoadUDWithParams.append(params)
       return .unimplemented
     }
-    let register: Register = .live(env)
+    let register: MessengerRegister = .live(env)
     try register(username: username)
 
     XCTAssertNoDifference(didNewOrLoadUDWithParams, [.init(
@@ -110,28 +110,28 @@ final class RegisterTests: XCTestCase {
   }
 
   func testRegisterWithoutCMix() {
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = { nil }
-    let register: Register = .live(env)
+    let register: MessengerRegister = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { error in
       XCTAssertEqual(
-        error as? Register.Error,
-        Register.Error.notLoaded
+        error as? MessengerRegister.Error,
+        MessengerRegister.Error.notLoaded
       )
     }
   }
 
   func testRegisterWithoutE2E() {
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = { .unimplemented }
     env.e2e.get = { nil }
-    let register: Register = .live(env)
+    let register: MessengerRegister = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { error in
       XCTAssertEqual(
-        error as? Register.Error,
-        Register.Error.notConnected
+        error as? MessengerRegister.Error,
+        MessengerRegister.Error.notConnected
       )
     }
   }
@@ -140,7 +140,7 @@ final class RegisterTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
@@ -158,7 +158,7 @@ final class RegisterTests: XCTestCase {
     }
     env.udCert = nil
     env.udContact = nil
-    let register: Register = .live(env)
+    let register: MessengerRegister = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { err in
       XCTAssertEqual(err as? Error, error)
@@ -169,7 +169,7 @@ final class RegisterTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
@@ -187,7 +187,7 @@ final class RegisterTests: XCTestCase {
     env.udContact = "ud-contact".data(using: .utf8)!
     env.udAddress = "ud-address"
     env.newOrLoadUd.run = { _, _ in throw error }
-    let register: Register = .live(env)
+    let register: MessengerRegister = .live(env)
 
     XCTAssertThrowsError(try register(username: "new-user-name")) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Functors/StartTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift
similarity index 71%
rename from Tests/XXMessengerClientTests/Functors/StartTests.swift
rename to Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift
index f15d6f1d..7b3e33af 100644
--- a/Tests/XXMessengerClientTests/Functors/StartTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerStartTests.swift
@@ -3,11 +3,11 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class StartTests: XCTestCase {
+final class MessengerStartTests: XCTestCase {
   func testStart() throws {
     var didStartNetworkFollower: [Int] = []
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .stopped }
@@ -16,7 +16,7 @@ final class StartTests: XCTestCase {
       }
       return cMix
     }
-    let start: Start = .live(env)
+    let start: MessengerStart = .live(env)
 
     try start(timeoutMS: 123)
 
@@ -24,26 +24,26 @@ final class StartTests: XCTestCase {
   }
 
   func testStartWhenNotLoaded() {
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = { nil }
-    let start: Start = .live(env)
+    let start: MessengerStart = .live(env)
 
     XCTAssertThrowsError(try start()) { error in
       XCTAssertEqual(
-        error as? Start.Error,
-        Start.Error.notLoaded
+        error as? MessengerStart.Error,
+        MessengerStart.Error.notLoaded
       )
     }
   }
 
   func testStartWhenRunning() throws {
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .running }
       return cMix
     }
-    let start: Start = .live(env)
+    let start: MessengerStart = .live(env)
 
     try start()
   }
@@ -52,14 +52,14 @@ final class StartTests: XCTestCase {
     struct Error: Swift.Error, Equatable {}
     let error = Error()
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.networkFollowerStatus.run = { .stopped }
       cMix.startNetworkFollower.run = { _ in throw error }
       return cMix
     }
-    let start: Start = .live(env)
+    let start: MessengerStart = .live(env)
 
     XCTAssertThrowsError(try start()) { err in
       XCTAssertEqual(err as? Error, error)
diff --git a/Tests/XXMessengerClientTests/Functors/WaitForNetworkTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift
similarity index 60%
rename from Tests/XXMessengerClientTests/Functors/WaitForNetworkTests.swift
rename to Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift
index f0d15ca7..1dbae735 100644
--- a/Tests/XXMessengerClientTests/Functors/WaitForNetworkTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNetworkTests.swift
@@ -3,11 +3,11 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class WaitForNetworkTests: XCTestCase {
+final class MessengerWaitForNetworkTests: XCTestCase {
   func testWaitSuccess() throws {
     var didWaitForNetwork: [Int] = []
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.waitForNetwork.run = { timeoutMS in
@@ -16,7 +16,7 @@ final class WaitForNetworkTests: XCTestCase {
       }
       return cMix
     }
-    let waitForNetwork: WaitForNetwork = .live(env)
+    let waitForNetwork: MessengerWaitForNetwork = .live(env)
 
     try waitForNetwork(timeoutMS: 123)
 
@@ -24,31 +24,31 @@ final class WaitForNetworkTests: XCTestCase {
   }
 
   func testWaitWhenNotLoaded() {
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = { nil }
-    let waitForNetwork: WaitForNetwork = .live(env)
+    let waitForNetwork: MessengerWaitForNetwork = .live(env)
 
     XCTAssertThrowsError(try waitForNetwork()) { error in
       XCTAssertEqual(
-        error as? WaitForNetwork.Error,
-        WaitForNetwork.Error.notLoaded
+        error as? MessengerWaitForNetwork.Error,
+        MessengerWaitForNetwork.Error.notLoaded
       )
     }
   }
 
   func testWaitTimeout() {
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.waitForNetwork.run = { _ in false }
       return cMix
     }
-    let waitForNetwork: WaitForNetwork = .live(env)
+    let waitForNetwork: MessengerWaitForNetwork = .live(env)
 
     XCTAssertThrowsError(try waitForNetwork()) { error in
       XCTAssertEqual(
-        error as? WaitForNetwork.Error,
-        WaitForNetwork.Error.timeout
+        error as? MessengerWaitForNetwork.Error,
+        MessengerWaitForNetwork.Error.timeout
       )
     }
   }
diff --git a/Tests/XXMessengerClientTests/Functors/WaitForNodesTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift
similarity index 80%
rename from Tests/XXMessengerClientTests/Functors/WaitForNodesTests.swift
rename to Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift
index e001d270..bc23afb5 100644
--- a/Tests/XXMessengerClientTests/Functors/WaitForNodesTests.swift
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerWaitForNodesTests.swift
@@ -3,16 +3,16 @@ import XCTest
 import XXClient
 @testable import XXMessengerClient
 
-final class WaitForNodesTests: XCTestCase {
+final class MessengerWaitForNodesTests: XCTestCase {
   func testWaitWhenNotLoaded() {
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = { nil }
-    let waitForNodes: WaitForNodes = .live(env)
+    let waitForNodes: MessengerWaitForNodes = .live(env)
 
     XCTAssertThrowsError(try waitForNodes()) { error in
       XCTAssertEqual(
-        error as? WaitForNodes.Error,
-        WaitForNodes.Error.notLoaded
+        error as? MessengerWaitForNodes.Error,
+        MessengerWaitForNodes.Error.notLoaded
       )
     }
   }
@@ -20,7 +20,7 @@ final class WaitForNodesTests: XCTestCase {
   func testWaitWhenHasTargetRatio() throws {
     var didProgress: [NodeRegistrationReport] = []
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getNodeRegistrationStatus.run = {
@@ -28,7 +28,7 @@ final class WaitForNodesTests: XCTestCase {
       }
       return cMix
     }
-    let waitForNodes: WaitForNodes = .live(env)
+    let waitForNodes: MessengerWaitForNodes = .live(env)
 
     try waitForNodes(
       targetRatio: 0.7,
@@ -52,14 +52,14 @@ final class WaitForNodesTests: XCTestCase {
       .init(registered: 8, total: 10),
     ]
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getNodeRegistrationStatus.run = { reports.removeFirst() }
       return cMix
     }
     env.sleep = { didSleep.append($0) }
-    let waitForNodes: WaitForNodes = .live(env)
+    let waitForNodes: MessengerWaitForNodes = .live(env)
 
     try waitForNodes(
       targetRatio: 0.7,
@@ -87,14 +87,14 @@ final class WaitForNodesTests: XCTestCase {
       .init(registered: 6, total: 10),
     ]
 
-    var env: Environment = .unimplemented
+    var env: MessengerEnvironment = .unimplemented
     env.cMix.get = {
       var cMix: CMix = .unimplemented
       cMix.getNodeRegistrationStatus.run = { reports.removeFirst() }
       return cMix
     }
     env.sleep = { didSleep.append($0) }
-    let waitForNodes: WaitForNodes = .live(env)
+    let waitForNodes: MessengerWaitForNodes = .live(env)
 
     XCTAssertThrowsError(try waitForNodes(
       targetRatio: 0.7,
@@ -103,8 +103,8 @@ final class WaitForNodesTests: XCTestCase {
       onProgress: { didProgress.append($0) }
     )) { error in
       XCTAssertEqual(
-        error as? WaitForNodes.Error,
-        WaitForNodes.Error.timeout
+        error as? MessengerWaitForNodes.Error,
+        MessengerWaitForNodes.Error.timeout
       )
     }
 
diff --git a/Tests/XXMessengerClientTests/Utils/StoredTests.swift b/Tests/XXMessengerClientTests/Messenger/Utils/StoredTests.swift
similarity index 100%
rename from Tests/XXMessengerClientTests/Utils/StoredTests.swift
rename to Tests/XXMessengerClientTests/Messenger/Utils/StoredTests.swift
-- 
GitLab


From 155b1250a1a25d0b760aa58940597013fbf3551c Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Tue, 23 Aug 2022 14:00:18 +0100
Subject: [PATCH 26/27] Update docs

---
 Docs/XXMessengerClient.md | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/Docs/XXMessengerClient.md b/Docs/XXMessengerClient.md
index 2dc19246..7b29ad57 100644
--- a/Docs/XXMessengerClient.md
+++ b/Docs/XXMessengerClient.md
@@ -2,7 +2,7 @@
 
 `XXMessengerClient` is a client wrapper library for use in xx-messenger application.
 
-## 🛠 Instantiate messenger
+## ▶️ Instantiate messenger
 
 Example:
 
@@ -60,4 +60,19 @@ func start(messenger: Messenger) throws {
     }
   }
 }
+```
+
+## 🛠 Use client components directly
+
+Example:
+
+```swift
+// get cMix:
+let cMix = messenger.cMix()
+
+// get E2E:
+let e2e = messenger.e2e()
+
+// get UserDicovery:
+let ud = messenger.ud()
 ```
\ No newline at end of file
-- 
GitLab


From 89d9eb3be9b41cb8ab6df12085f7219c1aa08654 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Tue, 23 Aug 2022 14:03:29 +0100
Subject: [PATCH 27/27] Update NewUdManagerFromBackup.Params

---
 .../Functors/NewUdManagerFromBackup.swift      | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/Sources/XXClient/Functors/NewUdManagerFromBackup.swift b/Sources/XXClient/Functors/NewUdManagerFromBackup.swift
index 09dbf72e..e3f403e7 100644
--- a/Sources/XXClient/Functors/NewUdManagerFromBackup.swift
+++ b/Sources/XXClient/Functors/NewUdManagerFromBackup.swift
@@ -2,10 +2,9 @@ import Bindings
 import XCTestDynamicOverlay
 
 public struct NewUdManagerFromBackup {
-  public struct Params {
+  public struct Params: Equatable {
     public init(
       e2eId: Int,
-      follower: UdNetworkStatus,
       email: Fact?,
       phone: Fact?,
       cert: Data,
@@ -13,7 +12,6 @@ public struct NewUdManagerFromBackup {
       address: String
     ) {
       self.e2eId = e2eId
-      self.follower = follower
       self.email = email
       self.phone = phone
       self.cert = cert
@@ -22,7 +20,6 @@ public struct NewUdManagerFromBackup {
     }
 
     public var e2eId: Int
-    public var follower: UdNetworkStatus
     public var email: Fact?
     public var phone: Fact?
     public var cert: Data
@@ -30,19 +27,22 @@ public struct NewUdManagerFromBackup {
     public var address: String
   }
 
-  public var run: (Params) throws -> UserDiscovery
+  public var run: (Params, UdNetworkStatus) throws -> UserDiscovery
 
-  public func callAsFunction(_ params: Params) throws -> UserDiscovery {
-    try run(params)
+  public func callAsFunction(
+    params: Params,
+    follower: UdNetworkStatus
+  ) throws -> UserDiscovery {
+    try run(params, follower)
   }
 }
 
 extension NewUdManagerFromBackup {
-  public static let live = NewUdManagerFromBackup { params in
+  public static let live = NewUdManagerFromBackup { params, follower in
     var error: NSError?
     let bindingsUD = BindingsNewUdManagerFromBackup(
       params.e2eId,
-      params.follower.makeBindingsUdNetworkStatus(),
+      follower.makeBindingsUdNetworkStatus(),
       try params.email?.encode(),
       try params.phone?.encode(),
       params.cert,
-- 
GitLab