diff --git a/Sources/XXClient/Models/FactType.swift b/Sources/XXClient/Models/FactType.swift
index cbae1a7ebdeaf510440dfcffb631848f3fbe4353..2d55ff855cf7fd25046d489bf7ac14fb10ff6f8a 100644
--- a/Sources/XXClient/Models/FactType.swift
+++ b/Sources/XXClient/Models/FactType.swift
@@ -1,6 +1,6 @@
 import Foundation
 
-public enum FactType: Equatable {
+public enum FactType: Equatable, Hashable {
   public static let knownTypes: [FactType] = [.username, .email, .phone]
 
   case username
diff --git a/Sources/XXMessengerClient/Messenger/Functions/MessengerMyContact.swift b/Sources/XXMessengerClient/Messenger/Functions/MessengerMyContact.swift
new file mode 100644
index 0000000000000000000000000000000000000000..bcedd164fb985724f90f743ce5d417180f39b067
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functions/MessengerMyContact.swift
@@ -0,0 +1,51 @@
+import XCTestDynamicOverlay
+import XXClient
+
+public struct MessengerMyContact {
+  public enum IncludeFacts: Equatable {
+    case all
+    case types(Set<FactType>)
+  }
+
+  public enum Error: Swift.Error {
+    case notConnected
+    case notLoggedIn
+  }
+
+  public var run: (IncludeFacts?) throws -> XXClient.Contact
+
+  public func callAsFunction(includeFacts: IncludeFacts? = .all) throws -> XXClient.Contact {
+    try run(includeFacts)
+  }
+}
+
+extension MessengerMyContact {
+  public static func live(_ env: MessengerEnvironment) -> MessengerMyContact {
+    MessengerMyContact { includeFacts in
+      guard let e2e = env.e2e() else {
+        throw Error.notConnected
+      }
+      var contact = e2e.getContact()
+      if let includeFacts {
+        guard let ud = env.ud() else {
+          throw Error.notLoggedIn
+        }
+        let udFacts = try ud.getFacts()
+        switch includeFacts {
+        case .all:
+          try contact.setFacts(udFacts)
+
+        case .types(let types):
+          try contact.setFacts(udFacts.filter { types.contains($0.type) })
+        }
+      }
+      return contact
+    }
+  }
+}
+
+extension MessengerMyContact {
+  public static let unimplemented = MessengerMyContact(
+    run: XCTUnimplemented("\(Self.self)")
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
index 41c61329b4a538c0945f38affc62c365aeff312f..692d81fd9bdb7ee8cb540b9a4f1a844e7541966d 100644
--- a/Sources/XXMessengerClient/Messenger/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -22,6 +22,7 @@ public struct Messenger {
   public var register: MessengerRegister
   public var isLoggedIn: MessengerIsLoggedIn
   public var logIn: MessengerLogIn
+  public var myContact: MessengerMyContact
   public var waitForNetwork: MessengerWaitForNetwork
   public var waitForNodes: MessengerWaitForNodes
   public var destroy: MessengerDestroy
@@ -63,6 +64,7 @@ extension Messenger {
       register: .live(env),
       isLoggedIn: .live(env),
       logIn: .live(env),
+      myContact: .live(env),
       waitForNetwork: .live(env),
       waitForNodes: .live(env),
       destroy: .live(env),
@@ -105,6 +107,7 @@ extension Messenger {
     register: .unimplemented,
     isLoggedIn: .unimplemented,
     logIn: .unimplemented,
+    myContact: .unimplemented,
     waitForNetwork: .unimplemented,
     waitForNodes: .unimplemented,
     destroy: .unimplemented,
diff --git a/Tests/XXMessengerClientTests/Messenger/Functions/MessengerMyContactTests.swift b/Tests/XXMessengerClientTests/Messenger/Functions/MessengerMyContactTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..113677612ceb36dd8d08e8c35965c890c2586d9c
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functions/MessengerMyContactTests.swift
@@ -0,0 +1,121 @@
+import CustomDump
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+
+final class MessengerMyContactTests: XCTestCase {
+  func testMyContactWithAllFacts() throws {
+    let e2eContactData = "e2e-contact-data".data(using: .utf8)!
+    var e2eContactSetFacts: [[Fact]] = []
+    let e2eContactWithFactsData = "e2e-contact-with-facts-data".data(using: .utf8)!
+    let udFacts = [
+      Fact(type: .username, value: "ud-fact-username"),
+      Fact(type: .email, value: "ud-fact-email"),
+      Fact(type: .phone, value: "ud-fact-phone"),
+    ]
+    var env: MessengerEnvironment = .unimplemented
+    env.e2e.get = {
+      var e2e: E2E = .unimplemented
+      e2e.getContact.run = {
+        var contact: Contact = .unimplemented(e2eContactData)
+        contact.setFactsOnContact.run = { _, facts in
+          e2eContactSetFacts.append(facts)
+          return e2eContactWithFactsData
+        }
+        return contact
+      }
+      return e2e
+    }
+    env.ud.get = {
+      var ud: UserDiscovery = .unimplemented
+      ud.getFacts.run = { udFacts }
+      return ud
+    }
+    let myContact: MessengerMyContact = .live(env)
+
+    let contact = try myContact()
+
+    XCTAssertNoDifference(e2eContactSetFacts, [udFacts])
+    XCTAssertNoDifference(contact, .unimplemented(e2eContactWithFactsData))
+  }
+
+  func testMyContactWithoutFacts() throws {
+    let e2eContactData = "e2e-contact-data".data(using: .utf8)!
+    var env: MessengerEnvironment = .unimplemented
+    env.e2e.get = {
+      var e2e: E2E = .unimplemented
+      e2e.getContact.run = { .unimplemented(e2eContactData) }
+      return e2e
+    }
+    let myContact: MessengerMyContact = .live(env)
+
+    let contact = try myContact(includeFacts: .none)
+
+    XCTAssertNoDifference(contact, .unimplemented(e2eContactData))
+  }
+
+  func testMyContactWithFactTypes() throws {
+    let e2eContactData = "e2e-contact-data".data(using: .utf8)!
+    var e2eContactSetFacts: [[Fact]] = []
+    let e2eContactWithFactsData = "e2e-contact-with-facts-data".data(using: .utf8)!
+    let udFactUsername = Fact(type: .username, value: "ud-fact-username")
+    let udFactEmail = Fact(type: .email, value: "ud-fact-email")
+    let udFactPhone = Fact(type: .phone, value: "ud-fact-phone")
+    let udFacts = [udFactUsername, udFactEmail, udFactPhone]
+    var env: MessengerEnvironment = .unimplemented
+    env.e2e.get = {
+      var e2e: E2E = .unimplemented
+      e2e.getContact.run = {
+        var contact: Contact = .unimplemented(e2eContactData)
+        contact.setFactsOnContact.run = { _, facts in
+          e2eContactSetFacts.append(facts)
+          return e2eContactWithFactsData
+        }
+        return contact
+      }
+      return e2e
+    }
+    env.ud.get = {
+      var ud: UserDiscovery = .unimplemented
+      ud.getFacts.run = { udFacts }
+      return ud
+    }
+    let myContact: MessengerMyContact = .live(env)
+
+    let contact = try myContact(includeFacts: .types([.username, .phone]))
+
+    XCTAssertNoDifference(e2eContactSetFacts, [[udFactUsername, udFactPhone]])
+    XCTAssertNoDifference(contact, .unimplemented(e2eContactWithFactsData))
+  }
+
+  func testMyContactWhenNotConnected() {
+    var env: MessengerEnvironment = .unimplemented
+    env.e2e.get = { nil }
+    let myContact: MessengerMyContact = .live(env)
+
+    XCTAssertThrowsError(try myContact()) { error in
+      XCTAssertNoDifference(
+        error as NSError,
+        MessengerMyContact.Error.notConnected as NSError
+      )
+    }
+  }
+
+  func testMyContactWithFactsWhenNotLoggedIn() {
+    var env: MessengerEnvironment = .unimplemented
+    env.e2e.get = {
+      var e2e: E2E = .unimplemented
+      e2e.getContact.run = { .unimplemented(Data()) }
+      return e2e
+    }
+    env.ud.get = { nil }
+    let myContact: MessengerMyContact = .live(env)
+
+    XCTAssertThrowsError(try myContact()) { error in
+      XCTAssertNoDifference(
+        error as NSError,
+        MessengerMyContact.Error.notLoggedIn as NSError
+      )
+    }
+  }
+}