2023-01-24 18:24:46 +00:00
|
|
|
import 'package:cake_wallet/core/address_validator.dart';
|
2022-03-15 09:11:53 +00:00
|
|
|
import 'package:cake_wallet/core/yat_service.dart';
|
2023-09-25 13:47:39 +00:00
|
|
|
import 'package:cake_wallet/entities/ens_record.dart';
|
2021-07-07 13:50:55 +00:00
|
|
|
import 'package:cake_wallet/entities/openalias_record.dart';
|
2021-07-07 14:31:16 +00:00
|
|
|
import 'package:cake_wallet/entities/parsed_address.dart';
|
2021-07-07 13:50:55 +00:00
|
|
|
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
|
2022-03-15 09:11:53 +00:00
|
|
|
import 'package:cake_wallet/entities/emoji_string_extension.dart';
|
2023-10-05 12:18:35 +00:00
|
|
|
import 'package:cake_wallet/mastodon/mastodon_api.dart';
|
2024-01-27 02:34:38 +00:00
|
|
|
import 'package:cake_wallet/nostr/nostr_api.dart';
|
2023-11-03 19:23:11 +00:00
|
|
|
import 'package:cake_wallet/store/settings_store.dart';
|
2023-01-24 18:24:46 +00:00
|
|
|
import 'package:cake_wallet/twitter/twitter_api.dart';
|
|
|
|
import 'package:cw_core/crypto_currency.dart';
|
2023-10-03 14:55:38 +00:00
|
|
|
import 'package:cw_core/wallet_base.dart';
|
2022-06-28 15:46:32 +00:00
|
|
|
import 'package:cw_core/wallet_type.dart';
|
2022-06-13 11:41:46 +00:00
|
|
|
import 'package:cake_wallet/entities/fio_address_provider.dart';
|
2024-01-27 02:34:38 +00:00
|
|
|
import 'package:flutter/cupertino.dart';
|
2022-03-15 09:11:53 +00:00
|
|
|
|
|
|
|
class AddressResolver {
|
2023-11-03 19:23:11 +00:00
|
|
|
AddressResolver({required this.yatService, required this.wallet, required this.settingsStore})
|
|
|
|
: walletType = wallet.type;
|
2023-01-31 19:39:08 +00:00
|
|
|
|
2022-03-15 09:11:53 +00:00
|
|
|
final YatService yatService;
|
2022-06-28 15:46:32 +00:00
|
|
|
final WalletType walletType;
|
2023-10-03 17:07:05 +00:00
|
|
|
final WalletBase wallet;
|
2023-11-03 19:23:11 +00:00
|
|
|
final SettingsStore settingsStore;
|
2023-01-24 18:24:46 +00:00
|
|
|
|
2022-03-15 09:11:53 +00:00
|
|
|
static const unstoppableDomains = [
|
2023-01-31 19:39:08 +00:00
|
|
|
'crypto',
|
|
|
|
'zil',
|
|
|
|
'x',
|
|
|
|
'wallet',
|
|
|
|
'bitcoin',
|
|
|
|
'888',
|
|
|
|
'nft',
|
|
|
|
'dao',
|
2023-03-14 15:16:20 +00:00
|
|
|
'blockchain',
|
2023-08-10 12:38:53 +00:00
|
|
|
'polygon',
|
|
|
|
'klever',
|
|
|
|
'hi',
|
|
|
|
'kresus',
|
|
|
|
'anime',
|
|
|
|
'manga',
|
|
|
|
'binanceus'
|
2023-01-31 19:39:08 +00:00
|
|
|
];
|
2021-07-07 13:50:55 +00:00
|
|
|
|
2023-01-24 18:24:46 +00:00
|
|
|
static String? extractAddressByType({required String raw, required CryptoCurrency type}) {
|
|
|
|
final addressPattern = AddressValidator.getAddressFromStringPattern(type);
|
|
|
|
|
|
|
|
if (addressPattern == null) {
|
2023-04-21 18:36:47 +00:00
|
|
|
throw Exception('Unexpected token: $type for getAddressFromStringPattern');
|
2023-01-24 18:24:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
final match = RegExp(addressPattern).firstMatch(raw);
|
2023-10-17 15:59:41 +00:00
|
|
|
return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_'), (Match match) {
|
|
|
|
String group = match.group(0)!;
|
|
|
|
if (group.startsWith('bitcoincash:') || group.startsWith('nano_')) {
|
|
|
|
return group;
|
|
|
|
}
|
|
|
|
return '';
|
|
|
|
});
|
2023-01-24 18:24:46 +00:00
|
|
|
}
|
|
|
|
|
2024-01-27 02:34:38 +00:00
|
|
|
bool isEmailFormat(String address) {
|
|
|
|
final RegExp emailRegex = RegExp(
|
|
|
|
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
|
|
|
|
caseSensitive: false,
|
|
|
|
);
|
|
|
|
return emailRegex.hasMatch(address);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-03-01 19:38:48 +00:00
|
|
|
Future<ParsedAddress> resolve(BuildContext context, String text, String ticker) async {
|
2022-03-15 09:11:53 +00:00
|
|
|
try {
|
2023-01-24 18:24:46 +00:00
|
|
|
if (text.startsWith('@') && !text.substring(1).contains('@')) {
|
2024-03-01 19:38:48 +00:00
|
|
|
if (settingsStore.lookupsTwitter) {
|
2023-11-03 19:23:11 +00:00
|
|
|
final formattedName = text.substring(1);
|
|
|
|
final twitterUser = await TwitterApi.lookupUserByName(userName: formattedName);
|
|
|
|
final addressFromBio = extractAddressByType(
|
|
|
|
raw: twitterUser.description, type: CryptoCurrency.fromString(ticker));
|
|
|
|
if (addressFromBio != null) {
|
2024-03-01 19:38:48 +00:00
|
|
|
return ParsedAddress.fetchTwitterAddress(
|
|
|
|
address: addressFromBio,
|
|
|
|
name: text,
|
|
|
|
profileImageUrl: twitterUser.profileImageUrl,
|
|
|
|
profileName: twitterUser.name);
|
2023-11-03 19:23:11 +00:00
|
|
|
}
|
2023-02-12 22:38:12 +00:00
|
|
|
|
2023-11-03 19:23:11 +00:00
|
|
|
final pinnedTweet = twitterUser.pinnedTweet?.text;
|
|
|
|
if (pinnedTweet != null) {
|
|
|
|
final addressFromPinnedTweet =
|
|
|
|
extractAddressByType(raw: pinnedTweet, type: CryptoCurrency.fromString(ticker));
|
|
|
|
if (addressFromPinnedTweet != null) {
|
2024-03-01 19:38:48 +00:00
|
|
|
return ParsedAddress.fetchTwitterAddress(
|
|
|
|
address: addressFromPinnedTweet,
|
|
|
|
name: text,
|
|
|
|
profileImageUrl: twitterUser.profileImageUrl,
|
|
|
|
profileName: twitterUser.name);
|
2023-11-03 19:23:11 +00:00
|
|
|
}
|
2023-02-12 22:38:12 +00:00
|
|
|
}
|
2023-01-24 18:24:46 +00:00
|
|
|
}
|
|
|
|
}
|
2023-10-05 12:18:35 +00:00
|
|
|
|
|
|
|
if (text.startsWith('@') && text.contains('@', 1) && text.contains('.', 1)) {
|
2023-11-03 19:23:11 +00:00
|
|
|
if (settingsStore.lookupsMastodon) {
|
|
|
|
final subText = text.substring(1);
|
|
|
|
final hostNameIndex = subText.indexOf('@');
|
|
|
|
final hostName = subText.substring(hostNameIndex + 1);
|
|
|
|
final userName = subText.substring(0, hostNameIndex);
|
|
|
|
|
|
|
|
final mastodonUser =
|
|
|
|
await MastodonAPI.lookupUserByUserName(userName: userName, apiHost: hostName);
|
|
|
|
|
|
|
|
if (mastodonUser != null) {
|
|
|
|
String? addressFromBio =
|
|
|
|
extractAddressByType(raw: mastodonUser.note, type: CryptoCurrency.fromString(ticker));
|
|
|
|
|
|
|
|
if (addressFromBio != null) {
|
2024-03-01 19:38:48 +00:00
|
|
|
return ParsedAddress.fetchMastodonAddress(
|
|
|
|
address: addressFromBio,
|
|
|
|
name: text,
|
|
|
|
profileImageUrl: mastodonUser.profileImageUrl,
|
|
|
|
profileName: mastodonUser.username);
|
2023-11-03 19:23:11 +00:00
|
|
|
} else {
|
|
|
|
final pinnedPosts =
|
|
|
|
await MastodonAPI.getPinnedPosts(userId: mastodonUser.id, apiHost: hostName);
|
|
|
|
|
|
|
|
if (pinnedPosts.isNotEmpty) {
|
|
|
|
final userPinnedPostsText = pinnedPosts.map((item) => item.content).join('\n');
|
|
|
|
String? addressFromPinnedPost = extractAddressByType(
|
|
|
|
raw: userPinnedPostsText, type: CryptoCurrency.fromString(ticker));
|
|
|
|
|
|
|
|
if (addressFromPinnedPost != null) {
|
|
|
|
return ParsedAddress.fetchMastodonAddress(
|
2024-03-01 19:38:48 +00:00
|
|
|
address: addressFromPinnedPost,
|
|
|
|
name: text,
|
|
|
|
profileImageUrl: mastodonUser.profileImageUrl,
|
|
|
|
profileName: mastodonUser.username);
|
2023-11-03 19:23:11 +00:00
|
|
|
}
|
2023-10-05 12:18:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-24 18:24:46 +00:00
|
|
|
if (!text.startsWith('@') && text.contains('@') && !text.contains('.')) {
|
2022-06-13 11:41:46 +00:00
|
|
|
final bool isFioRegistered = await FioAddressProvider.checkAvail(text);
|
|
|
|
if (isFioRegistered) {
|
|
|
|
final address = await FioAddressProvider.getPubAddress(text, ticker);
|
2023-01-31 19:39:08 +00:00
|
|
|
return ParsedAddress.fetchFioAddress(address: address, name: text);
|
|
|
|
}
|
2022-06-13 11:41:46 +00:00
|
|
|
}
|
2022-03-15 09:11:53 +00:00
|
|
|
if (text.hasOnlyEmojis) {
|
2023-11-03 19:23:11 +00:00
|
|
|
if(settingsStore.lookupsYatService) {
|
|
|
|
if (walletType != WalletType.haven) {
|
|
|
|
final addresses = await yatService.fetchYatAddress(text, ticker);
|
|
|
|
return ParsedAddress.fetchEmojiAddress(addresses: addresses, name: text);
|
|
|
|
}
|
2022-06-28 15:46:32 +00:00
|
|
|
}
|
2021-08-27 17:46:24 +00:00
|
|
|
}
|
2022-03-15 09:11:53 +00:00
|
|
|
final formattedName = OpenaliasRecord.formatDomainName(text);
|
|
|
|
final domainParts = formattedName.split('.');
|
|
|
|
final name = domainParts.last;
|
2021-07-07 13:50:55 +00:00
|
|
|
|
2022-03-15 09:11:53 +00:00
|
|
|
if (domainParts.length <= 1 || domainParts.first.isEmpty || name.isEmpty) {
|
|
|
|
return ParsedAddress(addresses: [text]);
|
2021-07-07 13:50:55 +00:00
|
|
|
}
|
|
|
|
|
2022-11-11 13:55:21 +00:00
|
|
|
if (unstoppableDomains.any((domain) => name.trim() == domain)) {
|
2023-11-03 19:23:11 +00:00
|
|
|
if(settingsStore.lookupsUnstoppableDomains) {
|
|
|
|
final address = await fetchUnstoppableDomainAddress(text, ticker);
|
|
|
|
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
|
|
|
|
}
|
2022-03-15 09:11:53 +00:00
|
|
|
}
|
2021-07-07 13:50:55 +00:00
|
|
|
|
2023-09-29 15:58:19 +00:00
|
|
|
if (text.endsWith(".eth")) {
|
2023-11-03 19:23:11 +00:00
|
|
|
if (settingsStore.lookupsENS) {
|
|
|
|
final address = await EnsRecord.fetchEnsAddress(text, wallet: wallet);
|
|
|
|
if (address.isNotEmpty && address != "0x0000000000000000000000000000000000000000") {
|
|
|
|
return ParsedAddress.fetchEnsAddress(name: text, address: address);
|
|
|
|
}
|
2023-09-25 13:47:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-31 19:39:08 +00:00
|
|
|
if (formattedName.contains(".")) {
|
2023-11-03 19:23:11 +00:00
|
|
|
if(settingsStore.lookupsOpenAlias) {
|
|
|
|
final txtRecord = await OpenaliasRecord.lookupOpenAliasRecord(formattedName);
|
|
|
|
if (txtRecord != null) {
|
|
|
|
final record = await OpenaliasRecord.fetchAddressAndName(
|
|
|
|
formattedName: formattedName, ticker: ticker, txtRecord: txtRecord);
|
|
|
|
return ParsedAddress.fetchOpenAliasAddress(record: record, name: text);
|
|
|
|
}
|
2023-01-31 19:39:08 +00:00
|
|
|
}
|
|
|
|
}
|
2024-01-27 02:34:38 +00:00
|
|
|
if (isEmailFormat(text)) {
|
|
|
|
final nostrProfile = await NostrProfileHandler.queryProfile(context, text);
|
|
|
|
if (nostrProfile?.relays != null) {
|
|
|
|
final nostrUserData =
|
|
|
|
await NostrProfileHandler.processRelays(context, nostrProfile!, text);
|
|
|
|
|
|
|
|
if (nostrUserData != null) {
|
|
|
|
String? addressFromBio = extractAddressByType(
|
|
|
|
raw: nostrUserData.about, type: CryptoCurrency.fromString(ticker));
|
|
|
|
if (addressFromBio != null) {
|
|
|
|
return ParsedAddress.nostrAddress(address: addressFromBio, name: text);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-03-15 09:11:53 +00:00
|
|
|
} catch (e) {
|
|
|
|
print(e.toString());
|
2021-07-07 13:50:55 +00:00
|
|
|
}
|
|
|
|
|
2022-03-15 09:11:53 +00:00
|
|
|
return ParsedAddress(addresses: [text]);
|
2021-07-07 13:50:55 +00:00
|
|
|
}
|
2022-01-14 13:18:03 +00:00
|
|
|
}
|