diff --git a/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/MyContactFeature.xcscheme b/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/MyContactFeature.xcscheme
new file mode 100644
index 0000000000000000000000000000000000000000..60c61fd3b79f6c748a322027d0ca61e8f4e8df28
--- /dev/null
+++ b/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/MyContactFeature.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 = "MyContactFeature"
+               BuildableName = "MyContactFeature"
+               BlueprintName = "MyContactFeature"
+               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 = "MyContactFeatureTests"
+               BuildableName = "MyContactFeatureTests"
+               BlueprintName = "MyContactFeatureTests"
+               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 = "MyContactFeature"
+            BuildableName = "MyContactFeature"
+            BlueprintName = "MyContactFeature"
+            ReferencedContainer = "container:">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/MyIdentityFeature.xcscheme b/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/MyIdentityFeature.xcscheme
new file mode 100644
index 0000000000000000000000000000000000000000..e69b1d44aa7ba292ef94bb8db602faa9111304f6
--- /dev/null
+++ b/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/MyIdentityFeature.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 = "MyIdentityFeature"
+               BuildableName = "MyIdentityFeature"
+               BlueprintName = "MyIdentityFeature"
+               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 = "MyIdentityFeatureTests"
+               BuildableName = "MyIdentityFeatureTests"
+               BlueprintName = "MyIdentityFeatureTests"
+               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 = "MyIdentityFeature"
+            BuildableName = "MyIdentityFeature"
+            BlueprintName = "MyIdentityFeature"
+            ReferencedContainer = "container:">
+         </BuildableReference>
+      </MacroExpansion>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/example-app.xcscheme b/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/example-app.xcscheme
index ac213623f3e728760923364f7769a3ffd075fbd1..c6edd5dda410050c40e6df64bd48b668c357afde 100644
--- a/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/example-app.xcscheme
+++ b/Example/example-app/.swiftpm/xcode/xcshareddata/xcschemes/example-app.xcscheme
@@ -48,6 +48,34 @@
                ReferencedContainer = "container:">
             </BuildableReference>
          </BuildActionEntry>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "MyContactFeature"
+               BuildableName = "MyContactFeature"
+               BlueprintName = "MyContactFeature"
+               ReferencedContainer = "container:">
+            </BuildableReference>
+         </BuildActionEntry>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "MyIdentityFeature"
+               BuildableName = "MyIdentityFeature"
+               BlueprintName = "MyIdentityFeature"
+               ReferencedContainer = "container:">
+            </BuildableReference>
+         </BuildActionEntry>
          <BuildActionEntry
             buildForTesting = "YES"
             buildForRunning = "YES"
@@ -101,6 +129,26 @@
                ReferencedContainer = "container:">
             </BuildableReference>
          </TestableReference>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "MyContactFeatureTests"
+               BuildableName = "MyContactFeatureTests"
+               BlueprintName = "MyContactFeatureTests"
+               ReferencedContainer = "container:">
+            </BuildableReference>
+         </TestableReference>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "MyIdentityFeatureTests"
+               BuildableName = "MyIdentityFeatureTests"
+               BlueprintName = "MyIdentityFeatureTests"
+               ReferencedContainer = "container:">
+            </BuildableReference>
+         </TestableReference>
          <TestableReference
             skipped = "NO">
             <BuildableReference
diff --git a/Example/example-app/Package.swift b/Example/example-app/Package.swift
index 55d546265e9cafd943d11e006d1d3ddcb298cad3..6aa4531627631a16dff789a4acbef611711dd361 100644
--- a/Example/example-app/Package.swift
+++ b/Example/example-app/Package.swift
@@ -32,6 +32,14 @@ let package = Package(
       name: "LandingFeature",
       targets: ["LandingFeature"]
     ),
+    .library(
+      name: "MyContactFeature",
+      targets: ["MyContactFeature"]
+    ),
+    .library(
+      name: "MyIdentityFeature",
+      targets: ["MyIdentityFeature"]
+    ),
     .library(
       name: "SessionFeature",
       targets: ["SessionFeature"]
@@ -58,6 +66,8 @@ let package = Package(
       dependencies: [
         .target(name: "ErrorFeature"),
         .target(name: "LandingFeature"),
+        .target(name: "MyContactFeature"),
+        .target(name: "MyIdentityFeature"),
         .target(name: "SessionFeature"),
         .product(
           name: "ElixxirDAppsSDK",
@@ -132,10 +142,64 @@ let package = Package(
       ],
       swiftSettings: swiftSettings
     ),
+    .target(
+      name: "MyContactFeature",
+      dependencies: [
+        .target(name: "ErrorFeature"),
+        .product(
+          name: "ComposableArchitecture",
+          package: "swift-composable-architecture"
+        ),
+        .product(
+          name: "ComposablePresentation",
+          package: "swift-composable-presentation"
+        ),
+        .product(
+          name: "ElixxirDAppsSDK",
+          package: "elixxir-dapps-sdk-swift"
+        ),
+      ],
+      swiftSettings: swiftSettings
+    ),
+    .testTarget(
+      name: "MyContactFeatureTests",
+      dependencies: [
+        .target(name: "MyContactFeature"),
+      ],
+      swiftSettings: swiftSettings
+    ),
+    .target(
+      name: "MyIdentityFeature",
+      dependencies: [
+        .target(name: "ErrorFeature"),
+        .product(
+          name: "ComposableArchitecture",
+          package: "swift-composable-architecture"
+        ),
+        .product(
+          name: "ComposablePresentation",
+          package: "swift-composable-presentation"
+        ),
+        .product(
+          name: "ElixxirDAppsSDK",
+          package: "elixxir-dapps-sdk-swift"
+        ),
+      ],
+      swiftSettings: swiftSettings
+    ),
+    .testTarget(
+      name: "MyIdentityFeatureTests",
+      dependencies: [
+        .target(name: "MyIdentityFeature"),
+      ],
+      swiftSettings: swiftSettings
+    ),
     .target(
       name: "SessionFeature",
       dependencies: [
         .target(name: "ErrorFeature"),
+        .target(name: "MyContactFeature"),
+        .target(name: "MyIdentityFeature"),
         .product(
           name: "ComposableArchitecture",
           package: "swift-composable-architecture"
diff --git a/Example/example-app/Sources/AppFeature/App.swift b/Example/example-app/Sources/AppFeature/App.swift
index 341cb46c6bbc7515e222c9e4157fab6f42c82160..65f4728edaf4f763712e3e9ef425e923135ba2ef 100644
--- a/Example/example-app/Sources/AppFeature/App.swift
+++ b/Example/example-app/Sources/AppFeature/App.swift
@@ -3,6 +3,8 @@ import ComposableArchitecture
 import ElixxirDAppsSDK
 import ErrorFeature
 import LandingFeature
+import MyContactFeature
+import MyIdentityFeature
 import SessionFeature
 import SwiftUI
 
@@ -22,6 +24,8 @@ struct App: SwiftUI.App {
 extension AppEnvironment {
   static func live() -> AppEnvironment {
     let clientSubject = CurrentValueSubject<Client?, Never>(nil)
+    let identitySubject = CurrentValueSubject<Identity?, Never>(nil)
+    let contactSubject = CurrentValueSubject<Data?, Never>(nil)
     let mainScheduler = DispatchQueue.main.eraseToAnyScheduler()
     let bgScheduler = DispatchQueue(
       label: "xx.network.dApps.ExampleApp.bg",
@@ -44,7 +48,26 @@ extension AppEnvironment {
       session: SessionEnvironment(
         getClient: { clientSubject.value },
         bgScheduler: bgScheduler,
-        mainScheduler: mainScheduler
+        mainScheduler: mainScheduler,
+        makeId: UUID.init,
+        error: ErrorEnvironment(),
+        myIdentity: MyIdentityEnvironment(
+          getClient: { clientSubject.value },
+          observeIdentity: { identitySubject.eraseToAnyPublisher() },
+          updateIdentity: { identitySubject.value = $0 },
+          bgScheduler: bgScheduler,
+          mainScheduler: mainScheduler,
+          error: ErrorEnvironment()
+        ),
+        myContact: MyContactEnvironment(
+          getClient: { clientSubject.value },
+          getIdentity: { identitySubject.value },
+          observeContact: { contactSubject.eraseToAnyPublisher() },
+          updateContact: { contactSubject.value = $0 },
+          bgScheduler: bgScheduler,
+          mainScheduler: mainScheduler,
+          error: ErrorEnvironment()
+        )
       )
     )
   }
diff --git a/Example/example-app/Sources/MyContactFeature/MyContactFeature.swift b/Example/example-app/Sources/MyContactFeature/MyContactFeature.swift
new file mode 100644
index 0000000000000000000000000000000000000000..317b646f1f7b5897f1cd4b4829f41cd8e67fd259
--- /dev/null
+++ b/Example/example-app/Sources/MyContactFeature/MyContactFeature.swift
@@ -0,0 +1,138 @@
+import Combine
+import ComposableArchitecture
+import ComposablePresentation
+import ElixxirDAppsSDK
+import ErrorFeature
+
+public struct MyContactState: Equatable {
+  public init(
+    id: UUID,
+    contact: Data? = nil,
+    isMakingContact: Bool = false,
+    error: ErrorState? = nil
+  ) {
+    self.id = id
+    self.contact = contact
+    self.isMakingContact = isMakingContact
+    self.error = error
+  }
+
+  public var id: UUID
+  public var contact: Data?
+  public var isMakingContact: Bool
+  public var error: ErrorState?
+}
+
+public enum MyContactAction: Equatable {
+  case viewDidLoad
+  case observeMyContact
+  case didUpdateMyContact(Data?)
+  case makeContact
+  case didFinishMakingContact(NSError?)
+  case didDismissError
+  case error(ErrorAction)
+}
+
+public struct MyContactEnvironment {
+  public init(
+    getClient: @escaping () -> Client?,
+    getIdentity: @escaping () -> Identity?,
+    observeContact: @escaping () -> AnyPublisher<Data?, Never>,
+    updateContact: @escaping (Data?) -> Void,
+    bgScheduler: AnySchedulerOf<DispatchQueue>,
+    mainScheduler: AnySchedulerOf<DispatchQueue>,
+    error: ErrorEnvironment
+  ) {
+    self.getClient = getClient
+    self.getIdentity = getIdentity
+    self.observeContact = observeContact
+    self.updateContact = updateContact
+    self.bgScheduler = bgScheduler
+    self.mainScheduler = mainScheduler
+    self.error = error
+  }
+
+  public var getClient: () -> Client?
+  public var getIdentity: () -> Identity?
+  public var observeContact: () -> AnyPublisher<Data?, Never>
+  public var updateContact: (Data?) -> Void
+  public var bgScheduler: AnySchedulerOf<DispatchQueue>
+  public var mainScheduler: AnySchedulerOf<DispatchQueue>
+  public var error: ErrorEnvironment
+}
+
+public let myContactReducer = Reducer<MyContactState, MyContactAction, MyContactEnvironment>
+{ state, action, env in
+  switch action {
+  case .viewDidLoad:
+    return .merge([
+      .init(value: .observeMyContact),
+    ])
+
+  case .observeMyContact:
+    struct EffectId: Hashable {
+      let id: UUID
+    }
+    return env.observeContact()
+      .removeDuplicates()
+      .map(MyContactAction.didUpdateMyContact)
+      .subscribe(on: env.bgScheduler)
+      .receive(on: env.mainScheduler)
+      .eraseToEffect()
+      .cancellable(id: EffectId(id: state.id), cancelInFlight: true)
+
+  case .didUpdateMyContact(let contact):
+    state.contact = contact
+    return .none
+
+  case .makeContact:
+    state.isMakingContact = true
+    return Effect.future { fulfill in
+      guard let identity = env.getIdentity() else {
+        fulfill(.success(.didFinishMakingContact(NoIdentityError() as NSError)))
+        return
+      }
+      do {
+        env.updateContact(try env.getClient()?.makeContactFromIdentity(identity: identity))
+        fulfill(.success(.didFinishMakingContact(nil)))
+      } catch {
+        fulfill(.success(.didFinishMakingContact(error as NSError)))
+      }
+    }
+    .subscribe(on: env.bgScheduler)
+    .receive(on: env.mainScheduler)
+    .eraseToEffect()
+
+  case .didFinishMakingContact(let error):
+    state.isMakingContact = false
+    if let error = error {
+      state.error = ErrorState(error: error)
+    }
+    return .none
+
+  case .didDismissError:
+    state.error = nil
+    return .none
+
+  case .error(_):
+    return .none
+  }
+}
+
+public struct NoIdentityError: Error, LocalizedError {
+  public init() {}
+}
+
+#if DEBUG
+extension MyContactEnvironment {
+  public static let failing = MyContactEnvironment(
+    getClient: { fatalError() },
+    getIdentity: { fatalError() },
+    observeContact: { fatalError() },
+    updateContact: { _ in fatalError() },
+    bgScheduler: .failing,
+    mainScheduler: .failing,
+    error: .failing
+  )
+}
+#endif
diff --git a/Example/example-app/Sources/MyContactFeature/MyContactView.swift b/Example/example-app/Sources/MyContactFeature/MyContactView.swift
new file mode 100644
index 0000000000000000000000000000000000000000..88f9d4b8fa84272d7ef3695fed506410d4010aa1
--- /dev/null
+++ b/Example/example-app/Sources/MyContactFeature/MyContactView.swift
@@ -0,0 +1,90 @@
+import ComposableArchitecture
+import ComposablePresentation
+import ElixxirDAppsSDK
+import ErrorFeature
+import SwiftUI
+
+public struct MyContactView: View {
+  public init(store: Store<MyContactState, MyContactAction>) {
+    self.store = store
+  }
+
+  let store: Store<MyContactState, MyContactAction>
+
+  struct ViewState: Equatable {
+    let contact: Data?
+    let isMakingContact: Bool
+
+    init(state: MyContactState) {
+      contact = state.contact
+      isMakingContact = state.isMakingContact
+    }
+
+    var isLoading: Bool {
+      isMakingContact
+    }
+  }
+
+  public var body: some View {
+    WithViewStore(store.scope(state: ViewState.init)) { viewStore in
+      Form {
+        Section {
+          Text(string(for: viewStore.contact))
+            .textSelection(.enabled)
+        }
+
+        Section {
+          Button {
+            viewStore.send(.makeContact)
+          } label: {
+            HStack {
+              Text("Make contact from identity")
+              Spacer()
+              if viewStore.isMakingContact {
+                ProgressView()
+              }
+            }
+          }
+        }
+        .disabled(viewStore.isLoading)
+      }
+      .navigationTitle("My contact")
+      .navigationBarBackButtonHidden(viewStore.isLoading)
+      .task {
+        viewStore.send(.viewDidLoad)
+      }
+      .sheet(
+        store.scope(
+          state: \.error,
+          action: MyContactAction.error
+        ),
+        onDismiss: {
+          viewStore.send(.didDismissError)
+        },
+        content: ErrorView.init(store:)
+      )
+    }
+  }
+
+  func string(for contact: Data?) -> String {
+    guard let contact = contact else {
+      return "No contact"
+    }
+    return String(data: contact, encoding: .utf8) ?? "Decoding error"
+  }
+}
+
+#if DEBUG
+public struct MyContactView_Previews: PreviewProvider {
+  public static var previews: some View {
+    NavigationView {
+      MyContactView(store: .init(
+        initialState: .init(id: UUID()),
+        reducer: .empty,
+        environment: ()
+      ))
+    }
+    .navigationViewStyle(.stack)
+  }
+}
+#endif
diff --git a/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift b/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift
new file mode 100644
index 0000000000000000000000000000000000000000..df4559d5cb56cb3f47c0ad79c57bbe5c0296a3bb
--- /dev/null
+++ b/Example/example-app/Sources/MyIdentityFeature/MyIdentityFeature.swift
@@ -0,0 +1,129 @@
+import Combine
+import ComposableArchitecture
+import ComposablePresentation
+import ElixxirDAppsSDK
+import ErrorFeature
+
+public struct MyIdentityState: Equatable {
+  public init(
+    id: UUID,
+    identity: Identity? = nil,
+    isMakingIdentity: Bool = false,
+    error: ErrorState? = nil
+  ) {
+    self.id = id
+    self.isMakingIdentity = isMakingIdentity
+    self.error = error
+  }
+
+  public var id: UUID
+  public var identity: Identity?
+  public var isMakingIdentity: Bool
+  public var error: ErrorState?
+}
+
+public enum MyIdentityAction: Equatable {
+  case viewDidLoad
+  case observeMyIdentity
+  case didUpdateMyIdentity(Identity?)
+  case makeIdentity
+  case didFinishMakingIdentity(NSError?)
+  case didDismissError
+  case error(ErrorAction)
+}
+
+public struct MyIdentityEnvironment {
+  public init(
+    getClient: @escaping () -> Client?,
+    observeIdentity: @escaping () -> AnyPublisher<Identity?, Never>,
+    updateIdentity: @escaping (Identity?) -> Void,
+    bgScheduler: AnySchedulerOf<DispatchQueue>,
+    mainScheduler: AnySchedulerOf<DispatchQueue>,
+    error: ErrorEnvironment
+  ) {
+    self.getClient = getClient
+    self.observeIdentity = observeIdentity
+    self.updateIdentity = updateIdentity
+    self.bgScheduler = bgScheduler
+    self.mainScheduler = mainScheduler
+    self.error = error
+  }
+
+  public var getClient: () -> Client?
+  public var observeIdentity: () -> AnyPublisher<Identity?, Never>
+  public var updateIdentity: (Identity?) -> Void
+  public var bgScheduler: AnySchedulerOf<DispatchQueue>
+  public var mainScheduler: AnySchedulerOf<DispatchQueue>
+  public var error: ErrorEnvironment
+}
+
+public let myIdentityReducer = Reducer<MyIdentityState, MyIdentityAction, MyIdentityEnvironment>
+{ state, action, env in
+  switch action {
+  case .viewDidLoad:
+    return .merge([
+      .init(value: .observeMyIdentity),
+    ])
+
+  case .observeMyIdentity:
+    struct EffectId: Hashable {
+      let id: UUID
+    }
+    return env.observeIdentity()
+      .removeDuplicates()
+      .map(MyIdentityAction.didUpdateMyIdentity)
+      .subscribe(on: env.bgScheduler)
+      .receive(on: env.mainScheduler)
+      .eraseToEffect()
+      .cancellable(id: EffectId(id: state.id), cancelInFlight: true)
+
+  case .didUpdateMyIdentity(let identity):
+    state.identity = identity
+    return .none
+
+  case .makeIdentity:
+    state.isMakingIdentity = true
+    return Effect.future { fulfill in
+      do {
+        env.updateIdentity(try env.getClient()?.makeIdentity())
+        fulfill(.success(.didFinishMakingIdentity(nil)))
+      } catch {
+        fulfill(.success(.didFinishMakingIdentity(error as NSError)))
+      }
+    }
+    .subscribe(on: env.bgScheduler)
+    .receive(on: env.mainScheduler)
+    .eraseToEffect()
+
+  case .didDismissError:
+    state.error = nil
+    return .none
+
+  case .didFinishMakingIdentity(let error):
+    state.isMakingIdentity = false
+    if let error = error {
+      state.error = ErrorState(error: error)
+    }
+    return .none
+  }
+}
+.presenting(
+  errorReducer,
+  state: .keyPath(\.error),
+  id: .keyPath(\.?.error),
+  action: /MyIdentityAction.error,
+  environment: \.error
+)
+
+#if DEBUG
+extension MyIdentityEnvironment {
+  public static let failing = MyIdentityEnvironment(
+    getClient: { fatalError() },
+    observeIdentity: { fatalError() },
+    updateIdentity: { _ in fatalError() },
+    bgScheduler: .failing,
+    mainScheduler: .failing,
+    error: .failing
+  )
+}
+#endif
diff --git a/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift b/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift
new file mode 100644
index 0000000000000000000000000000000000000000..61e09c1355755a7f1955e91ad7054d78f3689f5a
--- /dev/null
+++ b/Example/example-app/Sources/MyIdentityFeature/MyIdentityView.swift
@@ -0,0 +1,97 @@
+import ComposableArchitecture
+import ComposablePresentation
+import ElixxirDAppsSDK
+import ErrorFeature
+import SwiftUI
+
+public struct MyIdentityView: View {
+  public init(store: Store<MyIdentityState, MyIdentityAction>) {
+    self.store = store
+  }
+
+  let store: Store<MyIdentityState, MyIdentityAction>
+
+  struct ViewState: Equatable {
+    let identity: Identity?
+    let isMakingIdentity: Bool
+
+    init(state: MyIdentityState) {
+      identity = state.identity
+      isMakingIdentity = state.isMakingIdentity
+    }
+
+    var isLoading: Bool {
+      isMakingIdentity
+    }
+  }
+
+  public var body: some View {
+    WithViewStore(store.scope(state: ViewState.init)) { viewStore in
+      Form {
+        Section {
+          Text(string(for: viewStore.identity))
+            .textSelection(.enabled)
+        }
+
+        Section {
+          Button {
+            viewStore.send(.makeIdentity)
+          } label: {
+            HStack {
+              Text("Make new identity")
+              Spacer()
+              if viewStore.isMakingIdentity {
+                ProgressView()
+              }
+            }
+          }
+        }
+        .disabled(viewStore.isLoading)
+      }
+      .navigationTitle("My identity")
+      .navigationBarBackButtonHidden(viewStore.isLoading)
+      .task {
+        viewStore.send(.viewDidLoad)
+      }
+      .sheet(
+        store.scope(
+          state: \.error,
+          action: MyIdentityAction.error
+        ),
+        onDismiss: {
+          viewStore.send(.didDismissError)
+        },
+        content: ErrorView.init(store:)
+      )
+    }
+  }
+
+  func string(for identity: Identity?) -> String {
+    guard let identity = identity else {
+      return "No identity"
+    }
+    let encoder = JSONEncoder()
+    encoder.outputFormatting = .prettyPrinted
+    do {
+      let data = try encoder.encode(identity)
+      return String(data: data, encoding: .utf8) ?? "Decoding error"
+    } catch {
+      return "Decoding error: \(error)"
+    }
+  }
+}
+
+#if DEBUG
+public struct MyIdentityView_Previews: PreviewProvider {
+  public static var previews: some View {
+    NavigationView {
+      MyIdentityView(store: .init(
+        initialState: .init(id: UUID()),
+        reducer: .empty,
+        environment: ()
+      ))
+    }
+    .navigationViewStyle(.stack)
+  }
+}
+#endif
diff --git a/Example/example-app/Sources/SessionFeature/SessionFeature.swift b/Example/example-app/Sources/SessionFeature/SessionFeature.swift
index 0756f738008e1ea1870ffd1a11a600fccab5e0ca..5b1005a9a632e62978cc8a66294566e2f1ba4069 100644
--- a/Example/example-app/Sources/SessionFeature/SessionFeature.swift
+++ b/Example/example-app/Sources/SessionFeature/SessionFeature.swift
@@ -2,24 +2,32 @@ import Combine
 import ComposableArchitecture
 import ElixxirDAppsSDK
 import ErrorFeature
+import MyContactFeature
+import MyIdentityFeature
 
 public struct SessionState: Equatable {
   public init(
     id: UUID,
     networkFollowerStatus: NetworkFollowerStatus? = nil,
     isNetworkHealthy: Bool? = nil,
-    error: ErrorState? = nil
+    error: ErrorState? = nil,
+    myIdentity: MyIdentityState? = nil,
+    myContact: MyContactState? = nil
   ) {
     self.id = id
     self.networkFollowerStatus = networkFollowerStatus
     self.isNetworkHealthy = isNetworkHealthy
     self.error = error
+    self.myIdentity = myIdentity
+    self.myContact = myContact
   }
 
   public var id: UUID
   public var networkFollowerStatus: NetworkFollowerStatus?
   public var isNetworkHealthy: Bool?
   public var error: ErrorState?
+  public var myIdentity: MyIdentityState?
+  public var myContact: MyContactState?
 }
 
 public enum SessionAction: Equatable {
@@ -31,23 +39,41 @@ public enum SessionAction: Equatable {
   case monitorNetworkHealth(Bool)
   case didUpdateNetworkHealth(Bool?)
   case didDismissError
+  case presentMyIdentity
+  case didDismissMyIdentity
+  case presentMyContact
+  case didDismissMyContact
   case error(ErrorAction)
+  case myIdentity(MyIdentityAction)
+  case myContact(MyContactAction)
 }
 
 public struct SessionEnvironment {
   public init(
     getClient: @escaping () -> Client?,
     bgScheduler: AnySchedulerOf<DispatchQueue>,
-    mainScheduler: AnySchedulerOf<DispatchQueue>
+    mainScheduler: AnySchedulerOf<DispatchQueue>,
+    makeId: @escaping () -> UUID,
+    error: ErrorEnvironment,
+    myIdentity: MyIdentityEnvironment,
+    myContact: MyContactEnvironment
   ) {
     self.getClient = getClient
     self.bgScheduler = bgScheduler
     self.mainScheduler = mainScheduler
+    self.makeId = makeId
+    self.error = error
+    self.myIdentity = myIdentity
+    self.myContact = myContact
   }
 
   public var getClient: () -> Client?
   public var bgScheduler: AnySchedulerOf<DispatchQueue>
   public var mainScheduler: AnySchedulerOf<DispatchQueue>
+  public var makeId: () -> UUID
+  public var error: ErrorEnvironment
+  public var myIdentity: MyIdentityEnvironment
+  public var myContact: MyContactEnvironment
 }
 
 public let sessionReducer = Reducer<SessionState, SessionAction, SessionEnvironment>
@@ -129,17 +155,62 @@ public let sessionReducer = Reducer<SessionState, SessionAction, SessionEnvironm
     state.error = nil
     return .none
 
-  case .error(_):
+  case .presentMyIdentity:
+    if state.myIdentity == nil {
+      state.myIdentity = MyIdentityState(id: env.makeId())
+    }
+    return .none
+
+  case .didDismissMyIdentity:
+    state.myIdentity = nil
+    return .none
+
+  case .presentMyContact:
+    if state.myContact == nil {
+      state.myContact = MyContactState(id: env.makeId())
+    }
+    return .none
+
+  case .didDismissMyContact:
+    state.myContact = nil
+    return .none
+
+  case .error(_), .myIdentity(_), .myContact(_):
     return .none
   }
 }
+.presenting(
+  errorReducer,
+  state: .keyPath(\.error),
+  id: .keyPath(\.?.error),
+  action: /SessionAction.error,
+  environment: \.error
+)
+.presenting(
+  myIdentityReducer,
+  state: .keyPath(\.myIdentity),
+  id: .keyPath(\.?.id),
+  action: /SessionAction.myIdentity,
+  environment: \.myIdentity
+)
+.presenting(
+  myContactReducer,
+  state: .keyPath(\.myContact),
+  id: .keyPath(\.?.id),
+  action: /SessionAction.myContact,
+  environment: \.myContact
+)
 
 #if DEBUG
 extension SessionEnvironment {
   public static let failing = SessionEnvironment(
     getClient: { .failing },
     bgScheduler: .failing,
-    mainScheduler: .failing
+    mainScheduler: .failing,
+    makeId: { fatalError() },
+    error: .failing,
+    myIdentity: .failing,
+    myContact: .failing
   )
 }
 #endif
diff --git a/Example/example-app/Sources/SessionFeature/SessionView.swift b/Example/example-app/Sources/SessionFeature/SessionView.swift
index 395cfcb160067fedc31ec3ddd5200aa6960864e2..ea14d91ff94358572a9462647044186b3c47ab6a 100644
--- a/Example/example-app/Sources/SessionFeature/SessionView.swift
+++ b/Example/example-app/Sources/SessionFeature/SessionView.swift
@@ -2,6 +2,8 @@ import ComposableArchitecture
 import ComposablePresentation
 import ElixxirDAppsSDK
 import ErrorFeature
+import MyContactFeature
+import MyIdentityFeature
 import SwiftUI
 
 public struct SessionView: View {
@@ -49,6 +51,28 @@ public struct SessionView: View {
         } header: {
           Text("Network health")
         }
+
+        Section {
+          Button {
+            viewStore.send(.presentMyIdentity)
+          } label: {
+            HStack {
+              Text("My identity")
+              Spacer()
+              Image(systemName: "chevron.forward")
+            }
+          }
+
+          Button {
+            viewStore.send(.presentMyContact)
+          } label: {
+            HStack {
+              Text("My contact")
+              Spacer()
+              Image(systemName: "chevron.forward")
+            }
+          }
+        }
       }
       .navigationTitle("Session")
       .task {
@@ -64,6 +88,30 @@ public struct SessionView: View {
         },
         content: ErrorView.init(store:)
       )
+      .background(
+        NavigationLinkWithStore(
+          store.scope(
+            state: \.myIdentity,
+            action: SessionAction.myIdentity
+          ),
+          onDeactivate: {
+            viewStore.send(.didDismissMyIdentity)
+          },
+          destination: MyIdentityView.init(store:)
+        )
+      )
+      .background(
+        NavigationLinkWithStore(
+          store.scope(
+            state: \.myContact,
+            action: SessionAction.myContact
+          ),
+          onDeactivate: {
+            viewStore.send(.didDismissMyContact)
+          },
+          destination: MyContactView.init(store:)
+        )
+      )
     }
   }
 }
diff --git a/Example/example-app/Tests/MyContactFeatureTests/MyContactFeatureTests.swift b/Example/example-app/Tests/MyContactFeatureTests/MyContactFeatureTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..862be08da221c884a14875b3ceb86010788073f4
--- /dev/null
+++ b/Example/example-app/Tests/MyContactFeatureTests/MyContactFeatureTests.swift
@@ -0,0 +1,174 @@
+import Combine
+import ComposableArchitecture
+import CustomDump
+import ElixxirDAppsSDK
+import ErrorFeature
+import XCTest
+@testable import MyContactFeature
+
+final class MyContactFeatureTests: XCTestCase {
+  func testViewDidLoad() {
+    let myContactSubject = PassthroughSubject<Data?, Never>()
+    let bgScheduler = DispatchQueue.test
+    let mainScheduler = DispatchQueue.test
+
+    var env = MyContactEnvironment.failing
+    env.observeContact = { myContactSubject.eraseToAnyPublisher() }
+    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
+
+    let store = TestStore(
+      initialState: MyContactState(id: UUID()),
+      reducer: myContactReducer,
+      environment: env
+    )
+
+    store.send(.viewDidLoad)
+    store.receive(.observeMyContact)
+
+    bgScheduler.advance()
+    let contact = "\(Int.random(in: 100...999))".data(using: .utf8)!
+    myContactSubject.send(contact)
+    mainScheduler.advance()
+
+    store.receive(.didUpdateMyContact(contact)) {
+      $0.contact = contact
+    }
+
+    myContactSubject.send(nil)
+    mainScheduler.advance()
+
+    store.receive(.didUpdateMyContact(nil)) {
+      $0.contact = nil
+    }
+
+    myContactSubject.send(completion: .finished)
+    mainScheduler.advance()
+  }
+
+  func testMakeContact() {
+    let identity = Identity.stub()
+    let newContact = "\(Int.random(in: 100...999))".data(using: .utf8)!
+    var didMakeContactFromIdentity = [Identity]()
+    var didUpdateContact = [Data?]()
+    let bgScheduler = DispatchQueue.test
+    let mainScheduler = DispatchQueue.test
+
+    var env = MyContactEnvironment.failing
+    env.getClient = {
+      var client = Client.failing
+      client.makeContactFromIdentity.get = { identity in
+        didMakeContactFromIdentity.append(identity)
+        return newContact
+      }
+      return client
+    }
+    env.updateContact = { didUpdateContact.append($0) }
+    env.getIdentity = { identity }
+    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
+
+    let store = TestStore(
+      initialState: MyContactState(id: UUID()),
+      reducer: myContactReducer,
+      environment: env
+    )
+
+    store.send(.makeContact) {
+      $0.isMakingContact = true
+    }
+
+    bgScheduler.advance()
+
+    XCTAssertNoDifference(didMakeContactFromIdentity, [identity])
+    XCTAssertNoDifference(didUpdateContact, [newContact])
+
+    mainScheduler.advance()
+
+    store.receive(.didFinishMakingContact(nil)) {
+      $0.isMakingContact = false
+    }
+  }
+
+  func testMakeContactWithoutIdentity() {
+    let error = NoIdentityError() as NSError
+    let bgScheduler = DispatchQueue.test
+    let mainScheduler = DispatchQueue.test
+
+    var env = MyContactEnvironment.failing
+    env.getIdentity = { nil }
+    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
+
+    let store = TestStore(
+      initialState: MyContactState(id: UUID()),
+      reducer: myContactReducer,
+      environment: env
+    )
+
+    store.send(.makeContact) {
+      $0.isMakingContact = true
+    }
+
+    bgScheduler.advance()
+    mainScheduler.advance()
+
+    store.receive(.didFinishMakingContact(error)) {
+      $0.isMakingContact = false
+      $0.error = ErrorState(error: error)
+    }
+
+    store.send(.didDismissError) {
+      $0.error = nil
+    }
+  }
+
+  func testMakeContactFailure() {
+    let error = NSError(domain: "test", code: 1234)
+    let bgScheduler = DispatchQueue.test
+    let mainScheduler = DispatchQueue.test
+
+    var env = MyContactEnvironment.failing
+    env.getClient = {
+      var client = Client.failing
+      client.makeContactFromIdentity.get = { _ in throw error }
+      return client
+    }
+    env.getIdentity = { .stub() }
+    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
+
+    let store = TestStore(
+      initialState: MyContactState(id: UUID()),
+      reducer: myContactReducer,
+      environment: env
+    )
+
+    store.send(.makeContact) {
+      $0.isMakingContact = true
+    }
+
+    bgScheduler.advance()
+    mainScheduler.advance()
+
+    store.receive(.didFinishMakingContact(error)) {
+      $0.isMakingContact = false
+      $0.error = ErrorState(error: error)
+    }
+
+    store.send(.didDismissError) {
+      $0.error = nil
+    }
+  }
+}
+
+private extension Identity {
+  static func stub() -> Identity {
+    Identity(
+      id: "\(Int.random(in: 100...999))".data(using: .utf8)!,
+      rsaPrivatePem: "\(Int.random(in: 100...999))".data(using: .utf8)!,
+      salt: "\(Int.random(in: 100...999))".data(using: .utf8)!,
+      dhKeyPrivate: "\(Int.random(in: 100...999))".data(using: .utf8)!
+    )
+  }
+}
diff --git a/Example/example-app/Tests/MyIdentityFeatureTests/MyIdentityFeatureTests.swift b/Example/example-app/Tests/MyIdentityFeatureTests/MyIdentityFeatureTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..b426cc0fbd26c49bc14b462db938b1eb27afb712
--- /dev/null
+++ b/Example/example-app/Tests/MyIdentityFeatureTests/MyIdentityFeatureTests.swift
@@ -0,0 +1,133 @@
+import Combine
+import ComposableArchitecture
+import CustomDump
+import ElixxirDAppsSDK
+import ErrorFeature
+import XCTest
+@testable import MyIdentityFeature
+
+final class MyIdentityFeatureTests: XCTestCase {
+  func testViewDidLoad() {
+    let myIdentitySubject = PassthroughSubject<Identity?, Never>()
+    let bgScheduler = DispatchQueue.test
+    let mainScheduler = DispatchQueue.test
+
+    var env = MyIdentityEnvironment.failing
+    env.observeIdentity = { myIdentitySubject.eraseToAnyPublisher() }
+    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
+
+    let store = TestStore(
+      initialState: MyIdentityState(id: UUID()),
+      reducer: myIdentityReducer,
+      environment: env
+    )
+
+    store.send(.viewDidLoad)
+    store.receive(.observeMyIdentity)
+
+    bgScheduler.advance()
+    let identity = Identity.stub()
+    myIdentitySubject.send(identity)
+    mainScheduler.advance()
+
+    store.receive(.didUpdateMyIdentity(identity)) {
+      $0.identity = identity
+    }
+
+    myIdentitySubject.send(nil)
+    mainScheduler.advance()
+
+    store.receive(.didUpdateMyIdentity(nil)) {
+      $0.identity = nil
+    }
+
+    myIdentitySubject.send(completion: .finished)
+    mainScheduler.advance()
+  }
+
+  func testMakeIdentity() {
+    let newIdentity = Identity.stub()
+    var didUpdateIdentity = [Identity?]()
+    let bgScheduler = DispatchQueue.test
+    let mainScheduler = DispatchQueue.test
+
+    var env = MyIdentityEnvironment.failing
+    env.getClient = {
+      var client = Client.failing
+      client.makeIdentity.make = { newIdentity }
+      return client
+    }
+    env.updateIdentity = { didUpdateIdentity.append($0) }
+    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
+
+    let store = TestStore(
+      initialState: MyIdentityState(id: UUID()),
+      reducer: myIdentityReducer,
+      environment: env
+    )
+
+    store.send(.makeIdentity) {
+      $0.isMakingIdentity = true
+    }
+
+    bgScheduler.advance()
+
+    XCTAssertNoDifference(didUpdateIdentity, [newIdentity])
+
+    mainScheduler.advance()
+
+    store.receive(.didFinishMakingIdentity(nil)) {
+      $0.isMakingIdentity = false
+    }
+  }
+
+  func testMakeIdentityFailure() {
+    let error = NSError(domain: "test", code: 1234)
+    let bgScheduler = DispatchQueue.test
+    let mainScheduler = DispatchQueue.test
+
+    var env = MyIdentityEnvironment.failing
+    env.getClient = {
+      var client = Client.failing
+      client.makeIdentity.make = { throw error }
+      return client
+    }
+    env.bgScheduler = bgScheduler.eraseToAnyScheduler()
+    env.mainScheduler = mainScheduler.eraseToAnyScheduler()
+
+    let store = TestStore(
+      initialState: MyIdentityState(id: UUID()),
+      reducer: myIdentityReducer,
+      environment: env
+    )
+
+    store.send(.makeIdentity) {
+      $0.isMakingIdentity = true
+    }
+
+    bgScheduler.advance()
+    mainScheduler.advance()
+
+    store.receive(.didFinishMakingIdentity(error)) {
+      $0.isMakingIdentity = false
+      $0.error = ErrorState(error: error)
+    }
+
+    store.send(.didDismissError) {
+      $0.error = nil
+    }
+  }
+}
+
+private extension Identity {
+  static func stub() -> Identity {
+    Identity(
+      id: "\(Int.random(in: 100...999))".data(using: .utf8)!,
+      rsaPrivatePem: "\(Int.random(in: 100...999))".data(using: .utf8)!,
+      salt: "\(Int.random(in: 100...999))".data(using: .utf8)!,
+      dhKeyPrivate: "\(Int.random(in: 100...999))".data(using: .utf8)!
+    )
+  }
+}
diff --git a/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift b/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift
index 2ada840d7d9d02bdb1c8732836502ad15d15be33..5c1aa3babd922cf042c0df855604dceeae7c36f7 100644
--- a/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift
+++ b/Example/example-app/Tests/SessionFeatureTests/SessionFeatureTests.swift
@@ -1,6 +1,8 @@
 import ComposableArchitecture
 import ElixxirDAppsSDK
 import ErrorFeature
+import MyContactFeature
+import MyIdentityFeature
 import XCTest
 @testable import SessionFeature
 
@@ -155,4 +157,46 @@ final class SessionFeatureTests: XCTestCase {
       $0.error = nil
     }
   }
+
+  func testPresentingMyIdentity() {
+    let newId = UUID()
+
+    var env = SessionEnvironment.failing
+    env.makeId = { newId }
+
+    let store = TestStore(
+      initialState: SessionState(id: UUID()),
+      reducer: sessionReducer,
+      environment: env
+    )
+
+    store.send(.presentMyIdentity) {
+      $0.myIdentity = MyIdentityState(id: newId)
+    }
+
+    store.send(.didDismissMyIdentity) {
+      $0.myIdentity = nil
+    }
+  }
+
+  func testPresentingMyContact() {
+    let newId = UUID()
+
+    var env = SessionEnvironment.failing
+    env.makeId = { newId }
+
+    let store = TestStore(
+      initialState: SessionState(id: UUID()),
+      reducer: sessionReducer,
+      environment: env
+    )
+
+    store.send(.presentMyContact) {
+      $0.myContact = MyContactState(id: newId)
+    }
+
+    store.send(.didDismissMyContact) {
+      $0.myContact = nil
+    }
+  }
 }
diff --git a/Sources/ElixxirDAppsSDK/Client.swift b/Sources/ElixxirDAppsSDK/Client.swift
index c47d98c4009674a9fd144a0ce3b323f4838ff681..621270e4d1896e956f2cee89798ba2bc9e21f576 100644
--- a/Sources/ElixxirDAppsSDK/Client.swift
+++ b/Sources/ElixxirDAppsSDK/Client.swift
@@ -9,6 +9,7 @@ public struct Client {
   public var monitorNetworkHealth: NetworkHealthListener
   public var listenErrors: ClientErrorListener
   public var makeIdentity: IdentityMaker
+  public var makeContactFromIdentity: ContactFromIdentityProvider
   public var connect: ConnectionMaker
   public var getContactFromIdentity: ContactFromIdentityProvider
   public var waitForDelivery: MessageDeliveryWaiter
@@ -25,6 +26,7 @@ extension Client {
       monitorNetworkHealth: .live(bindingsClient: bindingsClient),
       listenErrors: .live(bindingsClient: bindingsClient),
       makeIdentity: .live(bindingsClient: bindingsClient),
+      makeContactFromIdentity: .live(bindingsClient: bindingsClient),
       connect: .live(bindingsClient: bindingsClient),
       getContactFromIdentity: .live(bindingsClient: bindingsClient),
       waitForDelivery: .live(bindingsClient: bindingsClient)
@@ -43,6 +45,7 @@ extension Client {
     monitorNetworkHealth: .failing,
     listenErrors: .failing,
     makeIdentity: .failing,
+    makeContactFromIdentity: .failing,
     connect: .failing,
     getContactFromIdentity: .failing,
     waitForDelivery: .failing