diff --git a/Sources/ElixxirDAppsSDK/CmixManager.swift b/Sources/ElixxirDAppsSDK/CmixManager.swift
new file mode 100644
index 0000000000000000000000000000000000000000..6ab8eddad5c12bc61862e45536ca21b7e8cc5951
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/CmixManager.swift
@@ -0,0 +1,63 @@
+import Bindings
+
+public struct CmixManager {
+  public var hasStorage: CmixManagerHasStorage
+  public var create: CmixManagerCreate
+  public var load: CmixManagerLoad
+  public var remove: CmixManagerRemove
+}
+
+extension CmixManager {
+  public static func live(
+    directoryPath: String = FileManager.default
+      .urls(for: .applicationSupportDirectory, in: .userDomainMask)
+      .first!
+      .appendingPathComponent("xx.network.client")
+      .path,
+    fileManager: FileManager = .default,
+    environment: Environment = .mainnet,
+    downloadNDF: DownloadAndVerifySignedNdf = .live,
+    generateSecret: GenerateSecret = .live,
+    passwordStorage: PasswordStorage,
+    newCmix: NewCmix = .live,
+    getCmixParams: GetCmixParams = .liveDefault,
+    loadCmix: LoadCmix = .live
+  ) -> CmixManager {
+    CmixManager(
+      hasStorage: .live(
+        directoryPath: directoryPath,
+        fileManager: fileManager
+      ),
+      create: .live(
+        environment: environment,
+        downloadNDF: downloadNDF,
+        generateSecret: generateSecret,
+        passwordStorage: passwordStorage,
+        directoryPath: directoryPath,
+        fileManager: fileManager,
+        newCmix: newCmix,
+        getCmixParams: getCmixParams,
+        loadCmix: loadCmix
+      ),
+      load: .live(
+        directoryPath: directoryPath,
+        passwordStorage: passwordStorage,
+        getCmixParams: getCmixParams,
+        loadCmix: loadCmix
+      ),
+      remove: .live(
+        directoryPath: directoryPath,
+        fileManager: fileManager
+      )
+    )
+  }
+}
+
+extension CmixManager {
+  public static let unimplemented = CmixManager(
+    hasStorage: .unimplemented,
+    create: .unimplemented,
+    load: .unimplemented,
+    remove: .unimplemented
+  )
+}
diff --git a/Sources/ElixxirDAppsSDK/CmixManagerCreate.swift b/Sources/ElixxirDAppsSDK/CmixManagerCreate.swift
new file mode 100644
index 0000000000000000000000000000000000000000..54ad299387555c774f18f51d66f950a2b69ce522
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/CmixManagerCreate.swift
@@ -0,0 +1,49 @@
+import Bindings
+import XCTestDynamicOverlay
+
+public struct CmixManagerCreate {
+  public var run: () throws -> Cmix
+
+  public func callAsFunction() throws -> Cmix {
+    try run()
+  }
+}
+
+extension CmixManagerCreate {
+  public static func live(
+    environment: Environment,
+    downloadNDF: DownloadAndVerifySignedNdf,
+    generateSecret: GenerateSecret,
+    passwordStorage: PasswordStorage,
+    directoryPath: String,
+    fileManager: FileManager,
+    newCmix: NewCmix,
+    getCmixParams: GetCmixParams,
+    loadCmix: LoadCmix
+  ) -> CmixManagerCreate {
+    CmixManagerCreate {
+      let ndfData = try downloadNDF(environment)
+      let password = generateSecret()
+      try passwordStorage.save(password)
+      try? fileManager.removeItem(atPath: directoryPath)
+      try? fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true)
+      try newCmix(
+        ndfJSON: String(data: ndfData, encoding: .utf8)!,
+        storageDir: directoryPath,
+        password: password,
+        registrationCode: nil
+      )
+      return try loadCmix(
+        storageDir: directoryPath,
+        password: password,
+        cmixParamsJSON: getCmixParams()
+      )
+    }
+  }
+}
+
+extension CmixManagerCreate {
+  public static let unimplemented = CmixManagerCreate(
+    run: XCTUnimplemented("\(Self.self)")
+  )
+}
diff --git a/Sources/ElixxirDAppsSDK/CmixManagerHasStorage.swift b/Sources/ElixxirDAppsSDK/CmixManagerHasStorage.swift
new file mode 100644
index 0000000000000000000000000000000000000000..7e5ca0c1c5639e0b008541b846eab9379dacd249
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/CmixManagerHasStorage.swift
@@ -0,0 +1,28 @@
+import Bindings
+import XCTestDynamicOverlay
+
+public struct CmixManagerHasStorage {
+  public var run: () -> Bool
+
+  public func callAsFunction() -> Bool {
+    run()
+  }
+}
+
+extension CmixManagerHasStorage {
+  public static func live(
+    directoryPath: String,
+    fileManager: FileManager
+  ) -> CmixManagerHasStorage {
+    CmixManagerHasStorage {
+      let contents = try? fileManager.contentsOfDirectory(atPath: directoryPath)
+      return contents.map { $0.isEmpty == false } ?? false
+    }
+  }
+}
+
+extension CmixManagerHasStorage {
+  public static let unimplemented = CmixManagerHasStorage(
+    run: XCTUnimplemented("\(Self.self)")
+  )
+}
diff --git a/Sources/ElixxirDAppsSDK/CmixManagerLoad.swift b/Sources/ElixxirDAppsSDK/CmixManagerLoad.swift
new file mode 100644
index 0000000000000000000000000000000000000000..982f9a61070ef375fd9d2e22ea5f02bdc97781ec
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/CmixManagerLoad.swift
@@ -0,0 +1,33 @@
+import Bindings
+import XCTestDynamicOverlay
+
+public struct CmixManagerLoad {
+  public var run: () throws -> Cmix
+
+  public func callAsFunction() throws -> Cmix {
+    try run()
+  }
+}
+
+extension CmixManagerLoad {
+  public static func live(
+    directoryPath: String,
+    passwordStorage: PasswordStorage,
+    getCmixParams: GetCmixParams,
+    loadCmix: LoadCmix
+  ) -> CmixManagerLoad {
+    CmixManagerLoad {
+      try loadCmix(
+        storageDir: directoryPath,
+        password: passwordStorage.load(),
+        cmixParamsJSON: getCmixParams()
+      )
+    }
+  }
+}
+
+extension CmixManagerLoad {
+  public static let unimplemented = CmixManagerLoad(
+    run: XCTUnimplemented("\(Self.self)")
+  )
+}
diff --git a/Sources/ElixxirDAppsSDK/CmixManagerRemove.swift b/Sources/ElixxirDAppsSDK/CmixManagerRemove.swift
new file mode 100644
index 0000000000000000000000000000000000000000..5488b5a3e23765bf785cbab6d3b0d404bf930a3b
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/CmixManagerRemove.swift
@@ -0,0 +1,27 @@
+import Bindings
+import XCTestDynamicOverlay
+
+public struct CmixManagerRemove {
+  public var run: () throws -> Void
+
+  public func callAsFunction() throws {
+    try run()
+  }
+}
+
+extension CmixManagerRemove {
+  public static func live(
+    directoryPath: String,
+    fileManager: FileManager
+  ) -> CmixManagerRemove {
+    CmixManagerRemove {
+      try fileManager.removeItem(atPath: directoryPath)
+    }
+  }
+}
+
+extension CmixManagerRemove {
+  public static let unimplemented = CmixManagerRemove(
+    run: XCTUnimplemented("\(Self.self)")
+  )
+}
diff --git a/Sources/ElixxirDAppsSDK/Legacy/ClientLoader.swift b/Sources/ElixxirDAppsSDK/Legacy/ClientLoader.swift
deleted file mode 100644
index b5297287e3ca3e815d0b99a7ea33d82598400700..0000000000000000000000000000000000000000
--- a/Sources/ElixxirDAppsSDK/Legacy/ClientLoader.swift
+++ /dev/null
@@ -1,32 +0,0 @@
-//import Bindings
-//
-//public struct ClientLoader {
-//  public var load: (URL, Data) throws -> Client
-//
-//  public func callAsFunction(directoryURL: URL, password: Data) throws -> Client {
-//    try load(directoryURL, password)
-//  }
-//}
-//
-//extension ClientLoader {
-//  public static let live = ClientLoader { directoryURL, password in
-//    var error: NSError?
-//    let bindingsClient = BindingsLogin(directoryURL.path, password, &error)
-//    if let error = error {
-//      throw error
-//    }
-//    guard let bindingsClient = bindingsClient else {
-//      fatalError("BindingsLogin returned `nil` without providing error")
-//    }
-//    return Client.live(bindingsClient: bindingsClient)
-//  }
-//}
-//
-//#if DEBUG
-//extension ClientLoader {
-//  public static let failing = ClientLoader { _, _ in
-//    struct NotImplemented: Error {}
-//    throw NotImplemented()
-//  }
-//}
-//#endif
diff --git a/Sources/ElixxirDAppsSDK/Legacy/ClientStorage.swift b/Sources/ElixxirDAppsSDK/Legacy/ClientStorage.swift
deleted file mode 100644
index 31700520af54e2096993300fc9468becc72d565e..0000000000000000000000000000000000000000
--- a/Sources/ElixxirDAppsSDK/Legacy/ClientStorage.swift
+++ /dev/null
@@ -1,69 +0,0 @@
-//import Bindings
-//
-//public struct ClientStorage {
-//  public var hasStoredClient: () -> Bool
-//  public var createClient: () throws -> Client
-//  public var loadClient: () throws -> Client
-//  public var removeClient: () throws -> Void
-//}
-//
-//extension ClientStorage {
-//  public static let defaultDirectoryURL = FileManager.default
-//    .urls(for: .applicationSupportDirectory, in: .userDomainMask)
-//    .first!
-//    .appendingPathComponent("xx.network.client")
-//
-//  public static func live(
-//    environment: Environment = .mainnet,
-//    directoryURL: URL = defaultDirectoryURL,
-//    fileManager: FileManager = .default,
-//    generatePassword: PasswordGenerator = .live,
-//    passwordStorage: PasswordStorage,
-//    downloadNDF: NDFDownloader = .live,
-//    createClient: ClientCreator = .live,
-//    loadClient: ClientLoader = .live
-//  ) -> ClientStorage {
-//    ClientStorage(
-//      hasStoredClient: {
-//        let contents = try? fileManager.contentsOfDirectory(atPath: directoryURL.path)
-//        return contents.map { $0.isEmpty == false } ?? false
-//      },
-//      createClient: {
-//        let ndf = try downloadNDF(environment)
-//        let password = generatePassword()
-//        try passwordStorage.save(password)
-//        try? fileManager.removeItem(at: directoryURL)
-//        try? fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true)
-//        try createClient(directoryURL: directoryURL, ndf: ndf, password: password)
-//        return try loadClient(directoryURL: directoryURL, password: password)
-//      },
-//      loadClient: {
-//        let password = try passwordStorage.load()
-//        return try loadClient(directoryURL: directoryURL, password: password)
-//      },
-//      removeClient: {
-//        try fileManager.removeItem(at: directoryURL)
-//      }
-//    )
-//  }
-//}
-//
-//#if DEBUG
-//extension ClientStorage {
-//  public static let failing = ClientStorage(
-//    hasStoredClient: { false },
-//    createClient: {
-//      struct NotImplemented: Error {}
-//      throw NotImplemented()
-//    },
-//    loadClient: {
-//      struct NotImplemented: Error {}
-//      throw NotImplemented()
-//    },
-//    removeClient: {
-//      struct NotImplemented: Error {}
-//      throw NotImplemented()
-//    }
-//  )
-//}
-//#endif
diff --git a/Sources/ElixxirDAppsSDK/Legacy/PasswordStorage.swift b/Sources/ElixxirDAppsSDK/PasswordStorage.swift
similarity index 62%
rename from Sources/ElixxirDAppsSDK/Legacy/PasswordStorage.swift
rename to Sources/ElixxirDAppsSDK/PasswordStorage.swift
index 89df9af8f14b84fc947e9e7ef4059488a295f504..bf84f6dd4338a62fcd1604f924099a52a36b9e36 100644
--- a/Sources/ElixxirDAppsSDK/Legacy/PasswordStorage.swift
+++ b/Sources/ElixxirDAppsSDK/PasswordStorage.swift
@@ -1,4 +1,5 @@
 import Foundation
+import XCTestDynamicOverlay
 
 public struct PasswordStorage {
   public struct MissingPasswordError: Error, Equatable {
@@ -17,17 +18,9 @@ public struct PasswordStorage {
   public var load: () throws -> Data
 }
 
-#if DEBUG
 extension PasswordStorage {
-  public static let failing = PasswordStorage(
-    save: { _ in
-      struct NotImplemented: Error {}
-      throw NotImplemented()
-    },
-    load: {
-      struct NotImplemented: Error {}
-      throw NotImplemented()
-    }
+  public static let unimplemented = PasswordStorage(
+    save: XCTUnimplemented("\(Self.self).save"),
+    load: XCTUnimplemented("\(Self.self).load")
   )
 }
-#endif