diff --git a/lib/data/models/contact.dart b/lib/data/models/contact.dart
index 8c684d81b116156c60b30ca28e890b797b0f5319..a7b09ea540761a0f41b7b5e345034f51bbd2843d 100644
--- a/lib/data/models/contact.dart
+++ b/lib/data/models/contact.dart
@@ -5,6 +5,7 @@ import 'package:equatable/equatable.dart';
 import 'package:json_annotation/json_annotation.dart';
 
 import 'is_json_serializable.dart';
+import 'model_utils.dart';
 
 part 'contact.g.dart';
 
@@ -13,7 +14,7 @@ part 'contact.g.dart';
 class Contact extends Equatable implements IsJsonSerializable<Contact> {
   const Contact({
     this.nick,
-    required this.pubkey,
+    required this.pubKey,
     this.avatar,
     this.notes,
     this.name,
@@ -23,14 +24,14 @@ class Contact extends Equatable implements IsJsonSerializable<Contact> {
       _$ContactFromJson(json);
 
   final String? nick;
-  final String pubkey;
-  @JsonKey(fromJson: _fromList, toJson: _toList)
+  final String pubKey;
+  @JsonKey(fromJson: uIntFromList, toJson: uIntToList)
   final Uint8List? avatar;
   final String? notes;
   final String? name;
 
   @override
-  List<Object?> get props => <dynamic>[nick, pubkey, avatar, notes, name];
+  List<Object?> get props => <dynamic>[nick, pubKey, avatar, notes, name];
 
   @override
   Map<String, dynamic> toJson() => _$ContactToJson(this);
@@ -38,13 +39,8 @@ class Contact extends Equatable implements IsJsonSerializable<Contact> {
   @override
   Contact fromJson(Map<String, dynamic> json) => Contact.fromJson(json);
 
-  static Uint8List _fromList(List<int> list) => Uint8List.fromList(list);
-
-  static List<int> _toList(Uint8List? uint8List) =>
-      uint8List != null ? uint8List.toList() : <int>[];
-
   @override
   String toString() {
-    return 'Contact $pubkey, hasAvatar: ${avatar != null}, nick: $nick, name: $name';
+    return 'Contact $pubKey, hasAvatar: ${avatar != null}, nick: $nick, name: $name';
   }
 }
diff --git a/lib/data/models/contact.g.dart b/lib/data/models/contact.g.dart
index e5bc557c0dc0d4bbb161479d92af042551d81db4..b7a39ffdadc0bd4522da342184325855e4254666 100644
--- a/lib/data/models/contact.g.dart
+++ b/lib/data/models/contact.g.dart
@@ -9,7 +9,7 @@ part of 'contact.dart';
 abstract class _$ContactCWProxy {
   Contact nick(String? nick);
 
-  Contact pubkey(String pubkey);
+  Contact pubKey(String pubKey);
 
   Contact avatar(Uint8List? avatar);
 
@@ -25,7 +25,7 @@ abstract class _$ContactCWProxy {
   /// ````
   Contact call({
     String? nick,
-    String? pubkey,
+    String? pubKey,
     Uint8List? avatar,
     String? notes,
     String? name,
@@ -42,7 +42,7 @@ class _$ContactCWProxyImpl implements _$ContactCWProxy {
   Contact nick(String? nick) => this(nick: nick);
 
   @override
-  Contact pubkey(String pubkey) => this(pubkey: pubkey);
+  Contact pubKey(String pubKey) => this(pubKey: pubKey);
 
   @override
   Contact avatar(Uint8List? avatar) => this(avatar: avatar);
@@ -63,7 +63,7 @@ class _$ContactCWProxyImpl implements _$ContactCWProxy {
   /// ````
   Contact call({
     Object? nick = const $CopyWithPlaceholder(),
-    Object? pubkey = const $CopyWithPlaceholder(),
+    Object? pubKey = const $CopyWithPlaceholder(),
     Object? avatar = const $CopyWithPlaceholder(),
     Object? notes = const $CopyWithPlaceholder(),
     Object? name = const $CopyWithPlaceholder(),
@@ -73,10 +73,10 @@ class _$ContactCWProxyImpl implements _$ContactCWProxy {
           ? _value.nick
           // ignore: cast_nullable_to_non_nullable
           : nick as String?,
-      pubkey: pubkey == const $CopyWithPlaceholder() || pubkey == null
-          ? _value.pubkey
+      pubKey: pubKey == const $CopyWithPlaceholder() || pubKey == null
+          ? _value.pubKey
           // ignore: cast_nullable_to_non_nullable
-          : pubkey as String,
+          : pubKey as String,
       avatar: avatar == const $CopyWithPlaceholder()
           ? _value.avatar
           // ignore: cast_nullable_to_non_nullable
@@ -105,16 +105,16 @@ extension $ContactCopyWith on Contact {
 
 Contact _$ContactFromJson(Map<String, dynamic> json) => Contact(
       nick: json['nick'] as String?,
-      pubkey: json['pubkey'] as String,
-      avatar: Contact._fromList(json['avatar'] as List<int>),
+      pubKey: json['pubKey'] as String,
+      avatar: uIntFromList(json['avatar']),
       notes: json['notes'] as String?,
       name: json['name'] as String?,
     );
 
 Map<String, dynamic> _$ContactToJson(Contact instance) => <String, dynamic>{
       'nick': instance.nick,
-      'pubkey': instance.pubkey,
-      'avatar': Contact._toList(instance.avatar),
+      'pubKey': instance.pubKey,
+      'avatar': uIntToList(instance.avatar),
       'notes': instance.notes,
       'name': instance.name,
     };
diff --git a/lib/data/models/contact_cubit.dart b/lib/data/models/contact_cubit.dart
index f3e76655e96eead8831fe5625a769d13ce7772b2..1093045abd55228fbf0fcff52be00114d6a79549 100644
--- a/lib/data/models/contact_cubit.dart
+++ b/lib/data/models/contact_cubit.dart
@@ -9,7 +9,7 @@ class ContactsCubit extends HydratedCubit<ContactsState> {
   Contact? _find(Contact contact) {
     try {
       return state.contacts
-          .firstWhere((Contact c) => c.pubkey == contact.pubkey);
+          .firstWhere((Contact c) => c.pubKey == contact.pubKey);
     } catch (e) {
       return null;
     }
@@ -24,10 +24,10 @@ class ContactsCubit extends HydratedCubit<ContactsState> {
 
   void removeContact(Contact contact) {
     final List<Contact> contactsTruncated = state.contacts
-        .where((Contact c) => c.pubkey != contact.pubkey)
+        .where((Contact c) => c.pubKey != contact.pubKey)
         .toList();
     final List<Contact> filteredContactsTruncated = state.filteredContacts
-        .where((Contact c) => c.pubkey != contact.pubkey)
+        .where((Contact c) => c.pubKey != contact.pubKey)
         .toList();
     emit(state.copyWith(
         contacts: contactsTruncated,
@@ -36,7 +36,7 @@ class ContactsCubit extends HydratedCubit<ContactsState> {
 
   void updateContact(Contact contact) {
     final List<Contact> contacts = state.contacts.map((Contact c) {
-      if (c.pubkey == contact.pubkey) {
+      if (c.pubKey == contact.pubKey) {
         return contact;
       }
       return c;
@@ -50,7 +50,7 @@ class ContactsCubit extends HydratedCubit<ContactsState> {
 
   void filterContacts(String query) {
     final List<Contact> contacts = state.contacts.where((Contact c) {
-      if (c.pubkey.contains(query)) {
+      if (c.pubKey.contains(query)) {
         return true;
       }
       if (c.nick != null && c.nick!.contains(query)) {
@@ -91,5 +91,5 @@ class ContactsCubit extends HydratedCubit<ContactsState> {
   String get id => 'contacts';
 
   bool isContact(String pubKey) =>
-      state.contacts.any((Contact c) => c.pubkey == pubKey);
+      state.contacts.any((Contact c) => c.pubKey == pubKey);
 }
diff --git a/lib/data/models/model_utils.dart b/lib/data/models/model_utils.dart
index 57d0d80e400ef067cc5aef926d1c688a116c6606..0a1525906ec7ea24011ee037095e040b2916010a 100644
--- a/lib/data/models/model_utils.dart
+++ b/lib/data/models/model_utils.dart
@@ -1,6 +1,15 @@
+import 'dart:convert';
 import 'dart:typed_data';
 
-Uint8List uIntFromList(List<int> list) => Uint8List.fromList(list);
+Uint8List? uIntFromList(dynamic value) {
+  if (value is List<int> && value.isNotEmpty) {
+    return Uint8List.fromList(value);
+  } else if (value is String && value.isNotEmpty) {
+    return base64Decode(value);
+  } else {
+    return null;
+  }
+}
 
 List<int> uIntToList(Uint8List? uInt8List) =>
     uInt8List != null ? uInt8List.toList() : <int>[];
diff --git a/lib/data/models/payment_state.g.dart b/lib/data/models/payment_state.g.dart
index 11b4bd1f93acead913934524c1a9f0c56273034b..5bb586a666591a9cdace210b44e9d06ea78c68ea 100644
--- a/lib/data/models/payment_state.g.dart
+++ b/lib/data/models/payment_state.g.dart
@@ -9,7 +9,7 @@ part of 'payment_state.dart';
 PaymentState _$PaymentStateFromJson(Map<String, dynamic> json) => PaymentState(
       publicKey: json['publicKey'] as String,
       nick: json['nick'] as String?,
-      avatar: uIntFromList(json['avatar'] as List<int>),
+      avatar: uIntFromList(json['avatar']),
       comment: json['comment'] as String? ?? '',
       amount: (json['amount'] as num?)?.toDouble(),
       status: $enumDecodeNullable(_$PaymentStatusEnumMap, json['status']) ??
diff --git a/lib/data/models/transaction.g.dart b/lib/data/models/transaction.g.dart
index 6e57d124f37613e2ed8fb70a32e4734dfbba84b5..9442400adfcbe57bd654f92e99fb55f6ed6dad22 100644
--- a/lib/data/models/transaction.g.dart
+++ b/lib/data/models/transaction.g.dart
@@ -242,9 +242,9 @@ Transaction _$TransactionFromJson(Map<String, dynamic> json) => Transaction(
       amount: (json['amount'] as num).toDouble(),
       comment: json['comment'] as String,
       time: DateTime.parse(json['time'] as String),
-      toAvatar: uIntFromList(json['toAvatar'] as List<int>),
+      toAvatar: uIntFromList(json['toAvatar']),
       toNick: json['toNick'] as String?,
-      fromAvatar: uIntFromList(json['fromAvatar'] as List<int>),
+      fromAvatar: uIntFromList(json['fromAvatar']),
       fromNick: json['fromNick'] as String?,
     );
 
diff --git a/lib/g1/api.dart b/lib/g1/api.dart
index 14ecd366cfd344fad4b8efa4b198e5427342df47..a991d5dbc298dba3774da304b0ea3cac9893ccd6 100644
--- a/lib/g1/api.dart
+++ b/lib/g1/api.dart
@@ -56,7 +56,7 @@ Future<Contact> getProfile(String pubKey) async {
     final Map<String, dynamic> result =
         const JsonDecoder().convert(cPlusResponse.body) as Map<String, dynamic>;
     if (result['found'] == false) {
-      return Contact(pubkey: pubKey);
+      return Contact(pubKey: pubKey);
     }
 
     final String? nick = await gvaNick(pubKey);
@@ -68,7 +68,7 @@ Future<Contact> getProfile(String pubKey) async {
     return c.copyWith(nick: nick);
   } catch (e) {
     logger('Error in getProfile $e');
-    return Contact(pubkey: pubKey);
+    return Contact(pubKey: pubKey);
   }
 }
 
@@ -100,7 +100,7 @@ Future<List<Contact>> searchWot(String searchTerm) async {
         final String pubKey = resultMap['pubkey'] as String;
         // ignore: avoid_dynamic_calls
         final String nick = resultMap['uids'][0]['uid']! as String;
-        contacts.add(Contact(nick: nick, pubkey: pubKey));
+        contacts.add(Contact(nick: nick, pubKey: pubKey));
       }
     }
   }
@@ -110,7 +110,7 @@ Future<List<Contact>> searchWot(String searchTerm) async {
 
 Future<Contact> getWot(Contact contact) async {
   final Response response = await requestDuniterWithRetry(
-      '/wot/lookup/${contact.pubkey}',
+      '/wot/lookup/${contact.pubKey}',
       retryWith404: false);
   // Will be better to analyze the 404 response (to detect faulty node)
   if (response.statusCode == HttpStatus.ok) {
diff --git a/lib/ui/contacts_cache.dart b/lib/ui/contacts_cache.dart
index 8568ff6349d5b25c7068ed16b02b6d42ba90d544..d92ba064e9ef4d047cc6587f9e808c410fb36bd9 100644
--- a/lib/ui/contacts_cache.dart
+++ b/lib/ui/contacts_cache.dart
@@ -1,3 +1,4 @@
+import 'dart:async';
 import 'dart:convert';
 import 'dart:html';
 
@@ -7,34 +8,6 @@ import '../data/models/contact.dart';
 import '../g1/api.dart';
 import 'logger.dart';
 
-class ContactsCacheBasic {
-  factory ContactsCacheBasic() {
-    _instance ??= ContactsCacheBasic._internal();
-    return _instance!;
-  }
-
-  ContactsCacheBasic._internal();
-
-  static ContactsCacheBasic? _instance;
-
-  final Map<String, Contact> _cache = <String, Contact>{};
-
-  Future<Contact> getContact(String pubKey) async {
-    final String cacheKey = 'avatar-$pubKey';
-
-    final Contact? cachedContact = _cache[cacheKey];
-    if (cachedContact != null) {
-      return cachedContact;
-    }
-
-    final Contact contact = await getProfile(pubKey);
-
-    _cache[cacheKey] = contact;
-
-    return contact;
-  }
-}
-
 class ContactsCache {
   factory ContactsCache() {
     _instance ??= ContactsCache._internal();
@@ -44,6 +17,7 @@ class ContactsCache {
   ContactsCache._internal();
 
   static ContactsCache? _instance;
+  final Map<String, List<Completer<Contact>>> _pendingRequests = {};
 
   Future<Contact> getContact(String pubKey) async {
     final String cacheKey = 'avatar-$pubKey';
@@ -53,13 +27,13 @@ class ContactsCache {
       final String? cachedValue = window.localStorage[cacheKey];
       if (cachedValue != null) {
         final Map<String, dynamic> decodedValue =
-        json.decode(cachedValue) as Map<String, dynamic>;
+            json.decode(cachedValue) as Map<String, dynamic>;
         final DateTime timestamp =
-        DateTime.parse(decodedValue['timestamp'] as String);
+            DateTime.parse(decodedValue['timestamp'] as String);
 
         if (DateTime.now().isBefore(timestamp.add(duration))) {
           final Contact contact =
-          Contact.fromJson(decodedValue['data'] as Map<String, dynamic>);
+              Contact.fromJson(decodedValue['data'] as Map<String, dynamic>);
           if (!kReleaseMode) {
             logger('Returning cached contact $contact');
           }
@@ -70,16 +44,40 @@ class ContactsCache {
       logger('Error while retrieving contact from cache: $e, $pubKey');
     }
 
-    final Contact contact = await getProfile(pubKey);
+    if (_pendingRequests.containsKey(pubKey)) {
+      final Completer<Contact> completer = Completer<Contact>();
+      _pendingRequests[pubKey]!.add(completer);
+      return completer.future;
+    }
+
+    final Completer<Contact> completer = Completer<Contact>();
+    _pendingRequests[pubKey] = <Completer<Contact>>[completer];
+    try {
+      final Contact contact = await getProfile(pubKey);
+
+      final String encodedValue = json.encode(<String, dynamic>{
+        'timestamp': DateTime.now().toIso8601String(),
+        'data': contact.toJson(),
+      });
+      window.localStorage[cacheKey] = encodedValue;
+      if (!kReleaseMode) {
+        logger('Returning non cached contact $contact');
+      }
+      // Send to listeners
+      for (final Completer<Contact> completer in _pendingRequests[pubKey]!) {
+        completer.complete(contact);
+      }
+      _pendingRequests.remove(pubKey);
+
+      return contact;
+    } catch (e) {
+      // Send error to listeners
+      for (final Completer<Contact> completer in _pendingRequests[pubKey]!) {
+        completer.completeError(e);
+      }
+      _pendingRequests.remove(pubKey);
 
-    final String encodedValue = json.encode(<String, dynamic>{
-      'timestamp': DateTime.now().toIso8601String(),
-      'data': contact.toJson(),
-    });
-    window.localStorage[cacheKey] = encodedValue;
-    if (!kReleaseMode) {
-      logger('Returning non cached contact $contact');
+      rethrow;
     }
-    return contact;
   }
 }
diff --git a/lib/ui/ui_helpers.dart b/lib/ui/ui_helpers.dart
index c96580962f902b2176d555955b2b41602cdbf4c9..0115eda8aae525103e6e540f831f7d4607c4cad1 100644
--- a/lib/ui/ui_helpers.dart
+++ b/lib/ui/ui_helpers.dart
@@ -124,7 +124,7 @@ Contact contactFromResultSearch(Map<String, dynamic> record) {
   final Map<String, dynamic> source = record['_source'] as Map<String, dynamic>;
   final Uint8List? avatarBase64 = _getAvatarFromResults(source);
   return Contact(
-      pubkey: record['_id'] as String,
+      pubKey: record['_id'] as String,
       name: source['title'] as String,
       avatar: avatarBase64);
 }
@@ -132,7 +132,7 @@ Contact contactFromResultSearch(Map<String, dynamic> record) {
 Contact contactFromUserProfile(Map<String, dynamic> source) {
   final Uint8List? avatarBase64 = _getAvatarFromResults(source);
   return Contact(
-      pubkey: source['issuer'] as String,
+      pubKey: source['issuer'] as String,
       name: source['title'] as String,
       avatar: avatarBase64);
 }
diff --git a/lib/ui/widgets/first_screen/pay_contact_search_page.dart b/lib/ui/widgets/first_screen/pay_contact_search_page.dart
index 9f32790af25ac2c3a6b9f6a3a364e1a7f5bc69bb..3b4e83876e44c038e7584e07a9d608f83b63c877 100644
--- a/lib/ui/widgets/first_screen/pay_contact_search_page.dart
+++ b/lib/ui/widgets/first_screen/pay_contact_search_page.dart
@@ -66,7 +66,7 @@ class _PayContactSearchPageState extends State<PayContactSearchPage> {
       logger('$_searchTerm looks like a plain pub key');
       setState(() {
         _isLoading = true;
-        final Contact contact = Contact(pubkey: _searchTerm);
+        final Contact contact = Contact(pubKey: _searchTerm);
         _results.add(contact);
         _isLoading = false;
       });
@@ -107,7 +107,7 @@ class _PayContactSearchPageState extends State<PayContactSearchPage> {
                   if (_results.length == 1 && pay != null) {
                     final Contact contact = _results[0];
                     paymentCubit.selectUser(
-                        contact.pubkey,
+                        contact.pubKey,
                         contact.nick ?? contact.name,
                         contact.avatar,
                         pay.amount);
@@ -191,7 +191,7 @@ class _PayContactSearchPageState extends State<PayContactSearchPage> {
 
   Widget _buildItem(Contact contact, int index, BuildContext context) {
     logger('Contact retrieved $contact');
-    final String pubKey = contact.pubkey;
+    final String pubKey = contact.pubKey;
     final String title = contact.nick ?? contact.name ?? humanizePubKey(pubKey);
     final Widget? subtitle = (contact.nick != null || contact.name != null)
         ? Text(humanizePubKey(pubKey))
@@ -226,7 +226,7 @@ class _PayContactSearchPageState extends State<PayContactSearchPage> {
                   contactsCubit.addContact(contact);
                 } else {
                   contactsCubit.removeContact(Contact(
-                    pubkey: pubKey,
+                    pubKey: pubKey,
                   ));
                 }
               });
diff --git a/lib/ui/widgets/fourth_screen/transaction_item.dart b/lib/ui/widgets/fourth_screen/transaction_item.dart
index 4d6f23cf561bf14d86f375dde44e97a9fcb8e48b..8bd13dfc751545d86cef6640d1a3160128deded6 100644
--- a/lib/ui/widgets/fourth_screen/transaction_item.dart
+++ b/lib/ui/widgets/fourth_screen/transaction_item.dart
@@ -194,7 +194,7 @@ class TransactionListItem extends StatelessWidget {
               }));
 
   Future<Contact> _fetchContact(String pubKey, Transaction transaction) async {
-    return Contact(pubkey: pubKey);
+    return Contact(pubKey: pubKey);
     if (pubKey == transaction.from) {
       return ContactsCache().getContact(transaction.to);
     } else {
diff --git a/lib/ui/widgets/third_screen/contacts_page.dart b/lib/ui/widgets/third_screen/contacts_page.dart
index 19c0bdd892f7932446dc489bb02830e48ee74d6f..be8cf150fee2ba325886e30f546a8102bacbf723 100644
--- a/lib/ui/widgets/third_screen/contacts_page.dart
+++ b/lib/ui/widgets/third_screen/contacts_page.dart
@@ -104,7 +104,7 @@ class _ContactsPageState extends State<ContactsPage> {
                         children: <SlidableAction>[
                           SlidableAction(
                             onPressed: (BuildContext c) {
-                              FlutterClipboard.copy(contact.pubkey).then(
+                              FlutterClipboard.copy(contact.pubKey).then(
                                   (dynamic value) => ScaffoldMessenger.of(
                                           context)
                                       .showSnackBar(SnackBar(
@@ -132,9 +132,9 @@ class _ContactsPageState extends State<ContactsPage> {
                             ? Text(contact.nick!)
                             : contact.name != null
                                 ? Text(contact.name!)
-                                : humanizePubKeyAsWidget(contact.pubkey),
+                                : humanizePubKeyAsWidget(contact.pubKey),
                         subtitle: contact.nick != null || contact.name != null
-                            ? humanizePubKeyAsWidget(contact.pubkey)
+                            ? humanizePubKeyAsWidget(contact.pubKey)
                             : null,
                         leading: avatar(
                           contact.avatar,
@@ -155,7 +155,7 @@ class _ContactsPageState extends State<ContactsPage> {
   void onSent(BuildContext c, Contact contact) {
     c
         .read<PaymentCubit>()
-        .selectUser(contact.pubkey, contact.nick, contact.avatar);
+        .selectUser(contact.pubKey, contact.nick, contact.avatar);
     c.read<BottomNavCubit>().updateIndex(0);
   }
 }