diff --git a/Examples/xx-messenger/Sources/AppFeature/AppFeature.swift b/Examples/xx-messenger/Sources/AppFeature/AppFeature.swift
index 582478d479dcc31b5e12a491e6843919bdd4aa43..43cede697423359094d9b0186350abbc01e79d2e 100644
--- a/Examples/xx-messenger/Sources/AppFeature/AppFeature.swift
+++ b/Examples/xx-messenger/Sources/AppFeature/AppFeature.swift
@@ -68,7 +68,7 @@ extension AppEnvironment {
 let appReducer = Reducer<AppState, AppAction, AppEnvironment>
 { state, action, env in
   switch action {
-  case .start, .welcome(.finished), .restore(.finished), .home(.didDeleteAccount):
+  case .start, .welcome(.finished), .restore(.finished), .home(.deleteAccount(.success)):
     state.screen = .loading
     return .run { subscriber in
       do {
diff --git a/Examples/xx-messenger/Sources/HomeFeature/Alerts.swift b/Examples/xx-messenger/Sources/HomeFeature/Alerts.swift
index a3347be43974d0e957ea1850369469360bb70311..3b9b9a3d00ee09ec4dd23ddc24fec105f94946fe 100644
--- a/Examples/xx-messenger/Sources/HomeFeature/Alerts.swift
+++ b/Examples/xx-messenger/Sources/HomeFeature/Alerts.swift
@@ -6,7 +6,7 @@ extension AlertState {
       title: TextState("Delete Account"),
       message: TextState("This will permanently delete your account and can't be undone."),
       buttons: [
-        .destructive(TextState("Delete"), action: .send(.deleteAccountConfirmed)),
+        .destructive(TextState("Delete"), action: .send(.deleteAccount(.confirmed))),
         .cancel(TextState("Cancel"))
       ]
     )
diff --git a/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift b/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift
index 279a5628bd12f2e1a6e18beb6940b1388a92f455..0a019179b2d45f23a41e54ecb084ac7ec835fe2d 100644
--- a/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift
+++ b/Examples/xx-messenger/Sources/HomeFeature/HomeFeature.swift
@@ -10,28 +10,54 @@ import XXMessengerClient
 public struct HomeState: Equatable {
   public init(
     failure: String? = nil,
-    register: RegisterState? = nil,
+    isNetworkHealthy: Bool? = nil,
+    networkNodesReport: NodeRegistrationReport? = nil,
+    isDeletingAccount: Bool = false,
     alert: AlertState<HomeAction>? = nil,
-    isDeletingAccount: Bool = false
+    register: RegisterState? = nil
   ) {
     self.failure = failure
-    self.register = register
-    self.alert = alert
+    self.isNetworkHealthy = isNetworkHealthy
     self.isDeletingAccount = isDeletingAccount
+    self.alert = alert
+    self.register = register
   }
 
-  @BindableState public var failure: String?
-  @BindableState public var register: RegisterState?
-  @BindableState public var alert: AlertState<HomeAction>?
-  @BindableState public var isDeletingAccount: Bool
+  public var failure: String?
+  public var isNetworkHealthy: Bool?
+  public var networkNodesReport: NodeRegistrationReport?
+  public var isDeletingAccount: Bool
+  public var alert: AlertState<HomeAction>?
+  public var register: RegisterState?
 }
 
-public enum HomeAction: Equatable, BindableAction {
-  case start
-  case deleteAccountButtonTapped
-  case deleteAccountConfirmed
-  case didDeleteAccount
-  case binding(BindingAction<HomeState>)
+public enum HomeAction: Equatable {
+  public enum Messenger: Equatable {
+    case start
+    case didStartRegistered
+    case didStartUnregistered
+    case failure(NSError)
+  }
+
+  public enum NetworkMonitor: Equatable {
+    case start
+    case stop
+    case health(Bool)
+    case nodes(NodeRegistrationReport)
+  }
+
+  public enum DeleteAccount: Equatable {
+    case buttonTapped
+    case confirmed
+    case success
+    case failure(NSError)
+  }
+
+  case messenger(Messenger)
+  case networkMonitor(NetworkMonitor)
+  case deleteAccount(DeleteAccount)
+  case didDismissAlert
+  case didDismissRegister
   case register(RegisterAction)
 }
 
@@ -69,41 +95,95 @@ extension HomeEnvironment {
 
 public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment>
 { state, action, env in
+  enum NetworkHealthEffectId {}
+  enum NetworkNodesEffectId {}
+
   switch action {
-  case .start:
-    return .run { subscriber in
-      do {
-        try env.messenger.start()
+  case .messenger(.start):
+    return .merge(
+      Effect(value: .networkMonitor(.stop)),
+      Effect.result {
+        do {
+          try env.messenger.start()
 
-        if env.messenger.isConnected() == false {
-          try env.messenger.connect()
-        }
+          if env.messenger.isConnected() == false {
+            try env.messenger.connect()
+          }
 
-        if env.messenger.isLoggedIn() == false {
-          if try env.messenger.isRegistered() == false {
-            subscriber.send(.set(\.$register, RegisterState()))
-            subscriber.send(completion: .finished)
-            return AnyCancellable {}
+          if env.messenger.isLoggedIn() == false {
+            if try env.messenger.isRegistered() == false {
+              return .success(.messenger(.didStartUnregistered))
+            }
+            try env.messenger.logIn()
           }
-          try env.messenger.logIn()
+
+          return .success(.messenger(.didStartRegistered))
+        } catch {
+          return .success(.messenger(.failure(error as NSError)))
         }
-      } catch {
-        subscriber.send(.set(\.$failure, error.localizedDescription))
       }
-      subscriber.send(completion: .finished)
-      return AnyCancellable {}
-    }
+    )
     .subscribe(on: env.bgQueue)
     .receive(on: env.mainQueue)
     .eraseToEffect()
 
-  case .deleteAccountButtonTapped:
+  case .messenger(.didStartUnregistered):
+    state.register = RegisterState()
+    return .none
+
+  case .messenger(.didStartRegistered):
+    return Effect(value: .networkMonitor(.start))
+
+  case .messenger(.failure(let error)):
+    state.failure = error.localizedDescription
+    return .none
+
+  case .networkMonitor(.start):
+    return .merge(
+      Effect.run { subscriber in
+        let callback = HealthCallback { isHealthy in
+          subscriber.send(.networkMonitor(.health(isHealthy)))
+        }
+        let cancellable = env.messenger.cMix()?.addHealthCallback(callback)
+        return AnyCancellable { cancellable?.cancel() }
+      }
+        .cancellable(id: NetworkHealthEffectId.self, cancelInFlight: true),
+      Effect.timer(
+        id: NetworkNodesEffectId.self,
+        every: .seconds(2),
+        on: env.bgQueue
+      )
+      .compactMap { _ in try? env.messenger.cMix()?.getNodeRegistrationStatus() }
+        .map { HomeAction.networkMonitor(.nodes($0)) }
+        .eraseToEffect()
+    )
+    .subscribe(on: env.bgQueue)
+    .receive(on: env.mainQueue)
+    .eraseToEffect()
+
+  case .networkMonitor(.stop):
+    state.isNetworkHealthy = nil
+    state.networkNodesReport = nil
+    return .merge(
+      .cancel(id: NetworkHealthEffectId.self),
+      .cancel(id: NetworkNodesEffectId.self)
+    )
+
+  case .networkMonitor(.health(let isHealthy)):
+    state.isNetworkHealthy = isHealthy
+    return .none
+
+  case .networkMonitor(.nodes(let report)):
+    state.networkNodesReport = report
+    return .none
+
+  case .deleteAccount(.buttonTapped):
     state.alert = .confirmAccountDeletion()
     return .none
 
-  case .deleteAccountConfirmed:
+  case .deleteAccount(.confirmed):
     state.isDeletingAccount = true
-    return .run { subscriber in
+    return .result {
       do {
         let contactId = try env.messenger.e2e.tryGet().getContact().getId()
         let contact = try env.db().fetchContacts(.init(id: [contactId])).first
@@ -113,31 +193,40 @@ public let homeReducer = Reducer<HomeState, HomeAction, HomeEnvironment>
         }
         try env.messenger.destroy()
         try env.db().drop()
-        subscriber.send(.didDeleteAccount)
+        return .success(.deleteAccount(.success))
       } catch {
-        subscriber.send(.set(\.$isDeletingAccount, false))
-        subscriber.send(.set(\.$alert, .accountDeletionFailed(error)))
+        return .success(.deleteAccount(.failure(error as NSError)))
       }
-      subscriber.send(completion: .finished)
-      return AnyCancellable {}
     }
     .subscribe(on: env.bgQueue)
     .receive(on: env.mainQueue)
     .eraseToEffect()
 
-  case .didDeleteAccount:
+  case .deleteAccount(.success):
+    state.isDeletingAccount = false
+    return .none
+
+  case .deleteAccount(.failure(let error)):
     state.isDeletingAccount = false
+    state.alert = .accountDeletionFailed(error)
+    return .none
+
+  case .didDismissAlert:
+    state.alert = nil
+    return .none
+
+  case .didDismissRegister:
+    state.register = nil
     return .none
 
   case .register(.finished):
     state.register = nil
-    return Effect(value: .start)
+    return Effect(value: .messenger(.start))
 
-  case .binding(_), .register(_):
+  case .register(_):
     return .none
   }
 }
-.binding()
 .presenting(
   registerReducer,
   state: .keyPath(\.register),
diff --git a/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift b/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift
index f73f6b8a9ff2696763a995f3358032d3229d2ca3..ce8aac42ab93d9578770f7cb606b7090a6fb6082 100644
--- a/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift
+++ b/Examples/xx-messenger/Sources/HomeFeature/HomeView.swift
@@ -2,6 +2,7 @@ import ComposableArchitecture
 import ComposablePresentation
 import RegisterFeature
 import SwiftUI
+import XXClient
 
 public struct HomeView: View {
   public init(store: Store<HomeState, HomeAction>) {
@@ -12,11 +13,15 @@ public struct HomeView: View {
 
   struct ViewState: Equatable {
     var failure: String?
+    var isNetworkHealthy: Bool?
+    var networkNodesReport: NodeRegistrationReport?
     var isDeletingAccount: Bool
 
     init(state: HomeState) {
       failure = state.failure
+      isNetworkHealthy = state.isNetworkHealthy
       isDeletingAccount = state.isDeletingAccount
+      networkNodesReport = state.networkNodesReport
     }
   }
 
@@ -24,22 +29,66 @@ public struct HomeView: View {
     WithViewStore(store.scope(state: ViewState.init)) { viewStore in
       NavigationView {
         Form {
-          if let failure = viewStore.failure {
-            Section {
+          Section {
+            if let failure = viewStore.failure {
               Text(failure)
               Button {
-                viewStore.send(.start)
+                viewStore.send(.messenger(.start))
               } label: {
                 Text("Retry")
               }
-            } header: {
+            }
+          } header: {
+            if viewStore.failure != nil {
               Text("Error")
             }
           }
 
+          Section {
+            HStack {
+              Text("Health")
+              Spacer()
+              switch viewStore.isNetworkHealthy {
+              case .some(true):
+                Image(systemName: "checkmark.circle.fill")
+                  .foregroundColor(.green)
+
+              case .some(false):
+                Image(systemName: "xmark.diamond.fill")
+                  .foregroundColor(.red)
+
+              case .none:
+                Image(systemName: "questionmark.circle")
+                  .foregroundColor(.gray)
+              }
+            }
+
+            ProgressView(
+              value: viewStore.networkNodesReport?.ratio ?? 0,
+              label: {
+                Text("Node registration")
+              },
+              currentValueLabel: {
+                if let report = viewStore.networkNodesReport {
+                  HStack {
+                    Text("\(Int((report.ratio * 100).rounded(.down)))%")
+                    Spacer()
+                    Text("\(report.registered) / \(report.total)")
+                  }
+                } else {
+                  Text("Unknown")
+                }
+              }
+            )
+            .tint((viewStore.networkNodesReport?.ratio ?? 0) >= 0.8 ? .green : .orange)
+            .animation(.default, value: viewStore.networkNodesReport?.ratio)
+          } header: {
+            Text("Network")
+          }
+
           Section {
             Button(role: .destructive) {
-              viewStore.send(.deleteAccountButtonTapped)
+              viewStore.send(.deleteAccount(.buttonTapped))
             } label: {
               HStack {
                 Text("Delete Account")
@@ -57,18 +106,18 @@ public struct HomeView: View {
         .navigationTitle("Home")
         .alert(
           store.scope(state: \.alert),
-          dismiss: HomeAction.set(\.$alert, nil)
+          dismiss: HomeAction.didDismissAlert
         )
       }
       .navigationViewStyle(.stack)
-      .task { viewStore.send(.start) }
+      .task { viewStore.send(.messenger(.start)) }
       .fullScreenCover(
         store.scope(
           state: \.register,
           action: HomeAction.register
         ),
         onDismiss: {
-          viewStore.send(.set(\.$register, nil))
+          viewStore.send(.didDismissRegister)
         },
         content: RegisterView.init(store:)
       )
diff --git a/Examples/xx-messenger/Tests/AppFeatureTests/AppFeatureTests.swift b/Examples/xx-messenger/Tests/AppFeatureTests/AppFeatureTests.swift
index 5ea968131af6851815f66f6b22edf2d2d139dc56..5a013b28b16126b422ef3d26b19407d0af2bff5c 100644
--- a/Examples/xx-messenger/Tests/AppFeatureTests/AppFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/AppFeatureTests/AppFeatureTests.swift
@@ -159,7 +159,7 @@ final class AppFeatureTests: XCTestCase {
     store.environment.messenger.isLoaded.run = { false }
     store.environment.messenger.isCreated.run = { false }
 
-    store.send(.home(.didDeleteAccount)) {
+    store.send(.home(.deleteAccount(.success))) {
       $0.screen = .loading
     }
 
diff --git a/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift b/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift
index 4fbad5b8c8a3d7775391db66359bd3c97f268ded..c7168d5b4537564a69ac82145b433c6ab22c65ff 100644
--- a/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/HomeFeatureTests/HomeFeatureTests.swift
@@ -7,71 +7,75 @@ import XXModels
 @testable import HomeFeature
 
 final class HomeFeatureTests: XCTestCase {
-  func testStartUnregistered() {
+  func testMessengerStartUnregistered() {
     let store = TestStore(
       initialState: HomeState(),
       reducer: homeReducer,
       environment: .unimplemented
     )
 
-    let bgQueue = DispatchQueue.test
-    let mainQueue = DispatchQueue.test
     var messengerDidStartWithTimeout: [Int] = []
     var messengerDidConnect = 0
 
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.environment.bgQueue = .immediate
+    store.environment.mainQueue = .immediate
     store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
     store.environment.messenger.isConnected.run = { false }
     store.environment.messenger.connect.run = { messengerDidConnect += 1 }
     store.environment.messenger.isLoggedIn.run = { false }
     store.environment.messenger.isRegistered.run = { false }
 
-    store.send(.start)
-
-    bgQueue.advance()
+    store.send(.messenger(.start))
 
     XCTAssertNoDifference(messengerDidStartWithTimeout, [30_000])
     XCTAssertNoDifference(messengerDidConnect, 1)
 
-    mainQueue.advance()
-
-    store.receive(.set(\.$register, RegisterState())) {
+    store.receive(.networkMonitor(.stop))
+    store.receive(.messenger(.didStartUnregistered)) {
       $0.register = RegisterState()
     }
   }
 
-  func testStartRegistered() {
+  func testMessengerStartRegistered() {
     let store = TestStore(
       initialState: HomeState(),
       reducer: homeReducer,
       environment: .unimplemented
     )
 
-    let bgQueue = DispatchQueue.test
-    let mainQueue = DispatchQueue.test
     var messengerDidStartWithTimeout: [Int] = []
     var messengerDidConnect = 0
     var messengerDidLogIn = 0
 
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.environment.bgQueue = .immediate
+    store.environment.mainQueue = .immediate
     store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
     store.environment.messenger.isConnected.run = { false }
     store.environment.messenger.connect.run = { messengerDidConnect += 1 }
     store.environment.messenger.isLoggedIn.run = { false }
     store.environment.messenger.isRegistered.run = { true }
     store.environment.messenger.logIn.run = { messengerDidLogIn += 1 }
+    store.environment.messenger.cMix.get = {
+      var cMix: CMix = .unimplemented
+      cMix.addHealthCallback.run = { _ in Cancellable {} }
+      cMix.getNodeRegistrationStatus.run = {
+        struct Unimplemented: Error {}
+        throw Unimplemented()
+      }
+      return cMix
+    }
 
-    store.send(.start)
-
-    bgQueue.advance()
+    store.send(.messenger(.start))
 
     XCTAssertNoDifference(messengerDidStartWithTimeout, [30_000])
     XCTAssertNoDifference(messengerDidConnect, 1)
     XCTAssertNoDifference(messengerDidLogIn, 1)
 
-    mainQueue.advance()
+    store.receive(.networkMonitor(.stop))
+    store.receive(.messenger(.didStartRegistered))
+    store.receive(.networkMonitor(.start))
+
+    store.send(.networkMonitor(.stop))
   }
 
   func testRegisterFinished() {
@@ -83,34 +87,43 @@ final class HomeFeatureTests: XCTestCase {
       environment: .unimplemented
     )
 
-    let bgQueue = DispatchQueue.test
-    let mainQueue = DispatchQueue.test
     var messengerDidStartWithTimeout: [Int] = []
     var messengerDidLogIn = 0
 
-    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
-    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.environment.bgQueue = .immediate
+    store.environment.mainQueue = .immediate
     store.environment.messenger.start.run = { messengerDidStartWithTimeout.append($0) }
     store.environment.messenger.isConnected.run = { true }
     store.environment.messenger.isLoggedIn.run = { false }
     store.environment.messenger.isRegistered.run = { true }
     store.environment.messenger.logIn.run = { messengerDidLogIn += 1 }
+    store.environment.messenger.cMix.get = {
+      var cMix: CMix = .unimplemented
+      cMix.addHealthCallback.run = { _ in Cancellable {} }
+      cMix.getNodeRegistrationStatus.run = {
+        struct Unimplemented: Error {}
+        throw Unimplemented()
+      }
+      return cMix
+    }
 
     store.send(.register(.finished)) {
       $0.register = nil
     }
 
-    store.receive(.start)
-
-    bgQueue.advance()
+    store.receive(.messenger(.start))
 
     XCTAssertNoDifference(messengerDidStartWithTimeout, [30_000])
     XCTAssertNoDifference(messengerDidLogIn, 1)
 
-    mainQueue.advance()
+    store.receive(.networkMonitor(.stop))
+    store.receive(.messenger(.didStartRegistered))
+    store.receive(.networkMonitor(.start))
+
+    store.send(.networkMonitor(.stop))
   }
 
-  func testStartMessengerStartFailure() {
+  func testMessengerStartFailure() {
     let store = TestStore(
       initialState: HomeState(),
       reducer: homeReducer,
@@ -124,14 +137,15 @@ final class HomeFeatureTests: XCTestCase {
     store.environment.mainQueue = .immediate
     store.environment.messenger.start.run = { _ in throw error }
 
-    store.send(.start)
+    store.send(.messenger(.start))
 
-    store.receive(.set(\.$failure, error.localizedDescription)) {
+    store.receive(.networkMonitor(.stop))
+    store.receive(.messenger(.failure(error as NSError))) {
       $0.failure = error.localizedDescription
     }
   }
 
-  func testStartMessengerConnectFailure() {
+  func testMessengerStartConnectFailure() {
     let store = TestStore(
       initialState: HomeState(),
       reducer: homeReducer,
@@ -147,14 +161,15 @@ final class HomeFeatureTests: XCTestCase {
     store.environment.messenger.isConnected.run = { false }
     store.environment.messenger.connect.run = { throw error }
 
-    store.send(.start)
+    store.send(.messenger(.start))
 
-    store.receive(.set(\.$failure, error.localizedDescription)) {
+    store.receive(.networkMonitor(.stop))
+    store.receive(.messenger(.failure(error as NSError))) {
       $0.failure = error.localizedDescription
     }
   }
 
-  func testStartMessengerIsRegisteredFailure() {
+  func testMessengerStartIsRegisteredFailure() {
     let store = TestStore(
       initialState: HomeState(),
       reducer: homeReducer,
@@ -171,14 +186,15 @@ final class HomeFeatureTests: XCTestCase {
     store.environment.messenger.isLoggedIn.run = { false }
     store.environment.messenger.isRegistered.run = { throw error }
 
-    store.send(.start)
+    store.send(.messenger(.start))
 
-    store.receive(.set(\.$failure, error.localizedDescription)) {
+    store.receive(.networkMonitor(.stop))
+    store.receive(.messenger(.failure(error as NSError))) {
       $0.failure = error.localizedDescription
     }
   }
 
-  func testStartMessengerLogInFailure() {
+  func testMessengerStartLogInFailure() {
     let store = TestStore(
       initialState: HomeState(),
       reducer: homeReducer,
@@ -196,13 +212,99 @@ final class HomeFeatureTests: XCTestCase {
     store.environment.messenger.isRegistered.run = { true }
     store.environment.messenger.logIn.run = { throw error }
 
-    store.send(.start)
+    store.send(.messenger(.start))
 
-    store.receive(.set(\.$failure, error.localizedDescription)) {
+    store.receive(.networkMonitor(.stop))
+    store.receive(.messenger(.failure(error as NSError))) {
       $0.failure = error.localizedDescription
     }
   }
 
+  func testNetworkMonitorStart() {
+    let store = TestStore(
+      initialState: HomeState(),
+      reducer: homeReducer,
+      environment: .unimplemented
+    )
+
+    let bgQueue = DispatchQueue.test
+    let mainQueue = DispatchQueue.test
+
+    var cMixDidAddHealthCallback: [HealthCallback] = []
+    var healthCallbackDidCancel = 0
+    var nodeRegistrationStatusIndex = 0
+    let nodeRegistrationStatus: [NodeRegistrationReport] = [
+      .init(registered: 0, total: 10),
+      .init(registered: 1, total: 11),
+      .init(registered: 2, total: 12),
+    ]
+
+    store.environment.bgQueue = bgQueue.eraseToAnyScheduler()
+    store.environment.mainQueue = mainQueue.eraseToAnyScheduler()
+    store.environment.messenger.cMix.get = {
+      var cMix: CMix = .unimplemented
+      cMix.addHealthCallback.run = { callback in
+        cMixDidAddHealthCallback.append(callback)
+        return Cancellable { healthCallbackDidCancel += 1 }
+      }
+      cMix.getNodeRegistrationStatus.run = {
+        defer { nodeRegistrationStatusIndex += 1 }
+        return nodeRegistrationStatus[nodeRegistrationStatusIndex]
+      }
+      return cMix
+    }
+
+    store.send(.networkMonitor(.start))
+
+    bgQueue.advance()
+
+    XCTAssertNoDifference(cMixDidAddHealthCallback.count, 1)
+
+    cMixDidAddHealthCallback.first?.handle(true)
+    mainQueue.advance()
+
+    store.receive(.networkMonitor(.health(true))) {
+      $0.isNetworkHealthy = true
+    }
+
+    cMixDidAddHealthCallback.first?.handle(false)
+    mainQueue.advance()
+
+    store.receive(.networkMonitor(.health(false))) {
+      $0.isNetworkHealthy = false
+    }
+
+    bgQueue.advance(by: 2)
+    mainQueue.advance()
+
+    store.receive(.networkMonitor(.nodes(nodeRegistrationStatus[0]))) {
+      $0.networkNodesReport = nodeRegistrationStatus[0]
+    }
+
+    bgQueue.advance(by: 2)
+    mainQueue.advance()
+
+    store.receive(.networkMonitor(.nodes(nodeRegistrationStatus[1]))) {
+      $0.networkNodesReport = nodeRegistrationStatus[1]
+    }
+
+    bgQueue.advance(by: 2)
+    mainQueue.advance()
+
+    store.receive(.networkMonitor(.nodes(nodeRegistrationStatus[2]))) {
+      $0.networkNodesReport = nodeRegistrationStatus[2]
+    }
+
+    store.send(.networkMonitor(.stop)) {
+      $0.isNetworkHealthy = nil
+      $0.networkNodesReport = nil
+    }
+
+    XCTAssertNoDifference(healthCallbackDidCancel, 1)
+
+    mainQueue.advance()
+  }
+
   func testAccountDeletion() {
     let store = TestStore(
       initialState: HomeState(),
@@ -254,15 +356,15 @@ final class HomeFeatureTests: XCTestCase {
       messengerDidDestroy += 1
     }
 
-    store.send(.deleteAccountButtonTapped) {
+    store.send(.deleteAccount(.buttonTapped)) {
       $0.alert = .confirmAccountDeletion()
     }
 
-    store.send(.set(\.$alert, nil)) {
+    store.send(.didDismissAlert) {
       $0.alert = nil
     }
 
-    store.send(.deleteAccountConfirmed) {
+    store.send(.deleteAccount(.confirmed)) {
       $0.isDeletingAccount = true
     }
 
@@ -271,7 +373,7 @@ final class HomeFeatureTests: XCTestCase {
     XCTAssertNoDifference(messengerDidDestroy, 1)
     XCTAssertNoDifference(dbDidDrop, 1)
 
-    store.receive(.didDeleteAccount) {
+    store.receive(.deleteAccount(.success)) {
       $0.isDeletingAccount = false
     }
   }
@@ -298,16 +400,41 @@ final class HomeFeatureTests: XCTestCase {
       return e2e
     }
 
-    store.send(.deleteAccountConfirmed) {
+    store.send(.deleteAccount(.confirmed)) {
       $0.isDeletingAccount = true
     }
 
-    store.receive(.set(\.$isDeletingAccount, false)) {
+    store.receive(.deleteAccount(.failure(error as NSError))) {
       $0.isDeletingAccount = false
+      $0.alert = .accountDeletionFailed(error)
     }
+  }
 
-    store.receive(.set(\.$alert, .accountDeletionFailed(error))) {
-      $0.alert = .accountDeletionFailed(error)
+  func testDidDismissAlert() {
+    let store = TestStore(
+      initialState: HomeState(
+        alert: AlertState(title: TextState(""))
+      ),
+      reducer: homeReducer,
+      environment: .unimplemented
+    )
+
+    store.send(.didDismissAlert) {
+      $0.alert = nil
+    }
+  }
+
+  func testDidDismissRegister() {
+    let store = TestStore(
+      initialState: HomeState(
+        register: RegisterState()
+      ),
+      reducer: homeReducer,
+      environment: .unimplemented
+    )
+
+    store.send(.didDismissRegister) {
+      $0.register = nil
     }
   }
 }