CakeWallet/lib/entities/parse_address_from_domain.dart
Omar Hatem df3a26dc15
Zano with passphrase (#1971)
* CW-685 Add passphrase restore for xmr/wow (#1552)

* CW-685 Add passphrase restore for xmr/wow

* add support for polyseed passphrase

* disable 14 word seed passphrase (not supported in wownero-seed)
fix: Getting grayed screen on latest passphrase build after having restored a 14-word wownero seed (+passphrase) and attempting to restore a XMR seed, legacy or otherwise.

* fix pointer when restoring depracated wownero seed

* Fix polyseed encryption

* changes from review

* remove unused code

* add passphrase back to the screen
add passphrase to qr code backup export

* fix settings leaking through currencies on seed restore

* fix monero.com builds, make passphrase a getter on WalletBase

* add support for weird polyseed

* store passphrase for weird polyseed

* show encrypted seed only when passphrase is not empty

* force set restore height

* fix build issues

* fix build errors

* fix configure script

* print -> printV

* Update lib/view_model/wallet_keys_view_model.dart [skip ci]

* Update lib/view_model/wallet_keys_view_model.dart [skip ci]

* Update tool/configure.dart [skip ci]

* Update lib/view_model/wallet_new_vm.dart

* reuse existing passphrase field

* remove unused passphrase field

* make workflow run on pullrequests only [skip ci] [skip slack]

---------

Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com>
Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

* Zano (#1793)

* my experiments

* Inital code for Zano integration

* Added missing android log lib

* added dummy wallet & some zano implementation

* fixing api for zano

* fixed zano build script

* attempt tp fix namespace problem

* added copy script for Zano files

* changes for zano wallet

* last updates

* zano.dart test app

* wallet recovery

* added pending transfer, some cleanup of unused

* some cleanup

* send + receive qr code

* last upd

* updated build_zano.sh

* updated zano ApiCalls, removed dummy

* updated zano ApiCalls, removed dummy

* added logging for get status/get info

* restored old wallet.dart

* restoring original versions of files

* restoring original versions of files

* restored get_height_by_date.dart, removed unnecessary calls for zano get height

* restoring original versions

* added multiple destinations, send all flag; some refactoring

* logging

* removed the duplicate

* fixed syncing sync status, decimal division, safe null json parsing

* some fixes after merge

* added multibalance/asset support for zano (ui)

* adding/removing from whitelist

* transfers in different assets

* transfers for multiple destinations and send all, some refactoring

* whitelists, some refactoring

* added different digits (decimal points) for formatters, some refactoring

* open, create, restore wallet refactoring; whitelists

* whitelists

* getting and updating transaction list; restoring a wallet from QR code

* several attempts to close wallet

* some refactoring

* added seed phrase

* changed fields to BigInt, some fixes

* modified build scripts for android

* build scripts

* restored accidently removed cw_haven.dart

* inital ios integration(zano libs built)

* update in script

* latest changes

* Applied a patch for iOS build (Boost and Zano scripts)

* Removed zano.dart (script-generated) and some unnecessary files

* Revert "Removed zano.dart (script-generated) and some unnecessary files"

This reverts commit 367c86398e.

* Removed zano.dart (generated by scripts), some files restored to initial versions

* added timer library

* changed paths in build_zano.sh

* build_zano.sh

* edit_token_page.dart - removed flag skipZanoAddressValidation

Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

* lib/core/address_validator.dart - updated zano address regex
lib/src/screens/dashboard/edit_token_page.dart - using AddressValidator().call

* fix zano build issues on android

* remove contrib/depends to save space

* move async call to a synchronouse one

* call sync call in isolate to make it async
generate framework for iOS as well
fix UR issues

* zano changes from monero_c repo

* update monero_c hash

* fix invalid zano imports, add support for linux, speed up CI builds

* update monero_c hash

* bump monero_c commit (yes, again, I know)

* fix wallet resttore, fix hardcoded IP

* fix regex, don't throw error when opening wallet, fix tx history, fix async calls, move stuff to isolate

* fix api calls in async transaction creation

* update build scripts

* fix some build issues

* update dependencies

* fix dependencies

* update ci scripts

* Improve multithread use of zano api

* Fix build issue

* fix zano node selection, move other zano calls to separate isolate

* update moneroc hash
WIP fixes for zano

* update monero_c

* fix monero.com builds

* sync wallet after connecting

* update monero_c

* Fix windows builds

* update monero_c

* update monero_c

* unshallow submodule

* cherry pick CW-867 Wownero fixes (#1881)

* fix wownero syntax error

* remove print statements in zano

* update zano node URL

* [PATCH] Apply new CI script (https://github.com/cake-tech/cake_wallet/pull/1948)

* drop env -i to fix cmake build errors on newer system

* [skip ci] Revert "[PATCH] Apply new CI script (https://github.com/cake-tech/cake_wallet/pull/1948)"

This reverts commit 5acb5bfe57.

* [run tests] [skip slack] Fix env in build

* Dynamically detect number of cores used to build monero_c, since it appears that zano requires more memory to link (and it reliably fails for first couple builds due to OOM on CI/VM with memory constrains).
Drop unshallowing of all modules
[run tests]

* Changes from review [run tests]

* drop zano on linux (missing symbols)
fix wownero on linux
add aarch64-linux-gnu
[run tests]

* - remove duplicate entry in addToken()
- use walletPassword in createZanoNewWalletCredentials
- remove createZanoRestoreWalletFromKeysCredentials
[run tests]

* [skip ci] update dockerfile

* fix parameter issue

---------

Co-authored-by: leo <leonid.ivanov@gmail.com>
Co-authored-by: cr.zoidberg <crypto.zoidberg@gmail.com>
Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

* - Add Zano Aliases
- Enable simpleswap [skip ci]
- Fix settings migration versions

* push missing file [skip ci]

* Zano pr with CW-685 passphrase (#1969)

* my experiments

* Inital code for Zano integration

* Added missing android log lib

* added dummy wallet & some zano implementation

* fixing api for zano

* fixed zano build script

* attempt tp fix namespace problem

* added copy script for Zano files

* changes for zano wallet

* last updates

* zano.dart test app

* wallet recovery

* added pending transfer, some cleanup of unused

* some cleanup

* send + receive qr code

* last upd

* updated build_zano.sh

* updated zano ApiCalls, removed dummy

* updated zano ApiCalls, removed dummy

* added logging for get status/get info

* restored old wallet.dart

* restoring original versions of files

* restoring original versions of files

* restored get_height_by_date.dart, removed unnecessary calls for zano get height

* restoring original versions

* added multiple destinations, send all flag; some refactoring

* logging

* removed the duplicate

* fixed syncing sync status, decimal division, safe null json parsing

* some fixes after merge

* added multibalance/asset support for zano (ui)

* adding/removing from whitelist

* transfers in different assets

* transfers for multiple destinations and send all, some refactoring

* whitelists, some refactoring

* added different digits (decimal points) for formatters, some refactoring

* open, create, restore wallet refactoring; whitelists

* whitelists

* getting and updating transaction list; restoring a wallet from QR code

* several attempts to close wallet

* some refactoring

* added seed phrase

* CW-685 Add passphrase restore for xmr/wow

* add support for polyseed passphrase

* disable 14 word seed passphrase (not supported in wownero-seed)
fix: Getting grayed screen on latest passphrase build after having restored a 14-word wownero seed (+passphrase) and attempting to restore a XMR seed, legacy or otherwise.

* fix pointer when restoring depracated wownero seed

* Fix polyseed encryption

* changed fields to BigInt, some fixes

* modified build scripts for android

* build scripts

* restored accidently removed cw_haven.dart

* inital ios integration(zano libs built)

* update in script

* latest changes

* changes from review

* remove unused code

* add passphrase back to the screen
add passphrase to qr code backup export

* fix settings leaking through currencies on seed restore

* fix monero.com builds, make passphrase a getter on WalletBase

* add support for weird polyseed

* store passphrase for weird polyseed

* show encrypted seed only when passphrase is not empty

* force set restore height

* Applied a patch for iOS build (Boost and Zano scripts)

* Removed zano.dart (script-generated) and some unnecessary files

* Revert "Removed zano.dart (script-generated) and some unnecessary files"

This reverts commit 367c86398e.

* Removed zano.dart (generated by scripts), some files restored to initial versions

* fix build issues

* fix build errors

* added timer library

* changed paths in build_zano.sh

* build_zano.sh

* edit_token_page.dart - removed flag skipZanoAddressValidation

Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

* lib/core/address_validator.dart - updated zano address regex
lib/src/screens/dashboard/edit_token_page.dart - using AddressValidator().call

* fix zano build issues on android

* remove contrib/depends to save space

* move async call to a synchronouse one

* call sync call in isolate to make it async
generate framework for iOS as well
fix UR issues

* zano changes from monero_c repo

* update monero_c hash

* fix invalid zano imports, add support for linux, speed up CI builds

* update monero_c hash

* bump monero_c commit (yes, again, I know)

* fix wallet resttore, fix hardcoded IP

* fix regex, don't throw error when opening wallet, fix tx history, fix async calls, move stuff to isolate

* fix api calls in async transaction creation

* fix configure script

* update build scripts

* fix some build issues

* update dependencies

* fix dependencies

* update ci scripts

* Improve multithread use of zano api

* Fix build issue

* fix zano node selection, move other zano calls to separate isolate

* update moneroc hash
WIP fixes for zano

* update monero_c

* fix monero.com builds

* sync wallet after connecting

* update monero_c

* Fix windows builds

* update monero_c

* print -> printV

* update monero_c

* unshallow submodule

* cherry pick CW-867 Wownero fixes (#1881)

* fix wownero syntax error

* remove print statements in zano

* update zano node URL

* [PATCH] Apply new CI script (https://github.com/cake-tech/cake_wallet/pull/1948)

* drop env -i to fix cmake build errors on newer system

* Update lib/view_model/wallet_keys_view_model.dart [skip ci]

* Update lib/view_model/wallet_keys_view_model.dart [skip ci]

* Update tool/configure.dart [skip ci]

* Update lib/view_model/wallet_new_vm.dart

* [skip ci] Revert "[PATCH] Apply new CI script (https://github.com/cake-tech/cake_wallet/pull/1948)"

This reverts commit 5acb5bfe57.

* [run tests] [skip slack] Fix env in build

* Dynamically detect number of cores used to build monero_c, since it appears that zano requires more memory to link (and it reliably fails for first couple builds due to OOM on CI/VM with memory constrains).
Drop unshallowing of all modules
[run tests]

* Changes from review [run tests]

* drop zano on linux (missing symbols)
fix wownero on linux
add aarch64-linux-gnu
[run tests]

* - remove duplicate entry in addToken()
- use walletPassword in createZanoNewWalletCredentials
- remove createZanoRestoreWalletFromKeysCredentials
[run tests]

* [skip ci] update dockerfile

* reuse existing passphrase field

* add passphrase support for zano

* Drop aarch64-linux-gnu for now.

* fix passphrase display, fix gray screen

* catch errors in polyseed encryption, encrypt only polyseed, fix coin in wownero

* update monero_c
update wownero to 0.11.3.0

* Show passphrase only when non-empty, fix passphrase being displayed as view key private.

* fix NanoAccountListPage showing up instead of MoneroAccountListPage for wownero

* build zano dependencies on android

* fix parameter issue

* minor merge leftover [skip ci]

* minor cleanup [skip ci]

* fix zano alias
update eth url for ens lookup
change $MAKE_JOB_COUNT to $NPROC

* minor cleanup [skip ci]

* fix zano alias

* Disable passphrase for creation of xmr/wow/zano
minor fixes

* fix zano on iOS

* - Fix get token data
- Enable unavailable balance
- Enable confirmations count
- Adjust explorer link

---------

Co-authored-by: leo <leonid.ivanov@gmail.com>
Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com>
Co-authored-by: cr.zoidberg <crypto.zoidberg@gmail.com>
Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>

---------

Co-authored-by: cyan <cyjan@mrcyjanek.net>
Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com>
Co-authored-by: leo <leonid.ivanov@gmail.com>
Co-authored-by: cr.zoidberg <crypto.zoidberg@gmail.com>
2025-01-24 20:33:24 +02:00

320 lines
11 KiB
Dart

import 'package:cake_wallet/core/address_validator.dart';
import 'package:cake_wallet/core/yat_service.dart';
import 'package:cake_wallet/entities/ens_record.dart';
import 'package:cake_wallet/entities/openalias_record.dart';
import 'package:cake_wallet/entities/parsed_address.dart';
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
import 'package:cake_wallet/entities/emoji_string_extension.dart';
import 'package:cake_wallet/entities/wellknown_record.dart';
import 'package:cake_wallet/entities/zano_alias.dart';
import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart';
import 'package:cake_wallet/mastodon/mastodon_api.dart';
import 'package:cake_wallet/nostr/nostr_api.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/twitter/twitter_api.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/entities/fio_address_provider.dart';
import 'package:flutter/cupertino.dart';
class AddressResolver {
AddressResolver({required this.yatService, required this.wallet, required this.settingsStore})
: walletType = wallet.type;
final YatService yatService;
final WalletType walletType;
final WalletBase wallet;
final SettingsStore settingsStore;
static const unstoppableDomains = [
"888",
"altimist",
"anime",
"austin",
"bald",
"benji",
"bet",
"binanceus",
"bitcoin",
"bitget",
"blockchain",
"ca",
"chomp",
"clay",
"co",
"com",
"crypto",
"dao",
"dfz",
"digital",
"dream",
"eth",
"ethermail",
"farms",
"fun",
"go",
"group",
"hi",
"host",
"info",
"io",
"klever",
"kresus",
"kryptic",
"lfg",
"life",
"live",
"ltd",
"manga",
"metropolis",
"moon",
"mumu",
"net",
"nft",
"online",
"org",
"pog",
"polygon",
"press",
"pro",
"propykeys",
"pudgy",
"pw",
"raiin",
"secret",
"site",
"smobler",
"space",
"stepn",
"store",
"tball",
"tech",
"ubu",
"uno",
"unstoppable",
"wallet",
"website",
"wifi",
"witg",
"wrkx",
"x",
"xmr",
"xyz",
"zil",
];
static String? extractAddressByType({required String raw, required CryptoCurrency type}) {
final addressPattern = AddressValidator.getAddressFromStringPattern(type);
if (addressPattern == null) {
throw Exception('Unexpected token: $type for getAddressFromStringPattern');
}
final match = RegExp(addressPattern, multiLine: true).firstMatch(raw);
return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_|ban_'),
(Match match) {
String group = match.group(0)!;
if (group.startsWith('bitcoincash:') ||
group.startsWith('nano_') ||
group.startsWith('ban_')) {
return group;
}
return '';
});
}
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);
}
Future<ParsedAddress> resolve(BuildContext context, String text, CryptoCurrency currency) async {
final ticker = currency.title;
try {
// twitter handle example: @username
if (text.startsWith('@') && !text.substring(1).contains('@')) {
if (currency == CryptoCurrency.zano && settingsStore.lookupsZanoAlias) {
final formattedName = text.substring(1);
final zanoAddress = await ZanoAlias.fetchZanoAliasAddress(formattedName);
if (zanoAddress != null) {
return ParsedAddress.zanoAddress(
address: zanoAddress,
name: text,
);
}
}
if (settingsStore.lookupsTwitter) {
final formattedName = text.substring(1);
final twitterUser = await TwitterApi.lookupUserByName(userName: formattedName);
final addressFromBio = extractAddressByType(
raw: twitterUser.description,
type: CryptoCurrency.fromString(ticker, walletCurrency: wallet.currency));
if (addressFromBio != null) {
return ParsedAddress.fetchTwitterAddress(
address: addressFromBio,
name: text,
profileImageUrl: twitterUser.profileImageUrl,
profileName: twitterUser.name);
}
final pinnedTweet = twitterUser.pinnedTweet?.text;
if (pinnedTweet != null) {
final addressFromPinnedTweet = extractAddressByType(
raw: pinnedTweet,
type: CryptoCurrency.fromString(ticker, walletCurrency: wallet.currency));
if (addressFromPinnedTweet != null) {
return ParsedAddress.fetchTwitterAddress(
address: addressFromPinnedTweet,
name: text,
profileImageUrl: twitterUser.profileImageUrl,
profileName: twitterUser.name);
}
}
}
}
// Mastodon example: @username@hostname.xxx
if (text.startsWith('@') && text.contains('@', 1) && text.contains('.', 1)) {
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: currency);
if (addressFromBio != null) {
return ParsedAddress.fetchMastodonAddress(
address: addressFromBio,
name: text,
profileImageUrl: mastodonUser.profileImageUrl,
profileName: mastodonUser.username);
} 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: currency);
if (addressFromPinnedPost != null) {
return ParsedAddress.fetchMastodonAddress(
address: addressFromPinnedPost,
name: text,
profileImageUrl: mastodonUser.profileImageUrl,
profileName: mastodonUser.username);
}
}
}
}
}
}
// .well-known scheme:
if (text.contains('.') && text.contains('@')) {
if (settingsStore.lookupsWellKnown) {
final record =
await WellKnownRecord.fetchAddressAndName(formattedName: text, currency: currency);
if (record != null) {
return ParsedAddress.fetchWellKnownAddress(address: record.address, name: text);
}
}
}
if (!text.startsWith('@') && text.contains('@') && !text.contains('.')) {
final bool isFioRegistered = await FioAddressProvider.checkAvail(text);
if (isFioRegistered) {
final address = await FioAddressProvider.getPubAddress(text, ticker);
return ParsedAddress.fetchFioAddress(address: address, name: text);
}
}
if (text.hasOnlyEmojis) {
if (settingsStore.lookupsYatService) {
if (walletType != WalletType.haven) {
final addresses = await yatService.fetchYatAddress(text, ticker);
return ParsedAddress.fetchEmojiAddress(addresses: addresses, name: text);
}
}
}
final thorChainAddress = await ThorChainExchangeProvider.lookupAddressByName(text);
if (thorChainAddress != null) {
String? address =
thorChainAddress[ticker] ?? (ticker == 'RUNE' ? thorChainAddress['THOR'] : null);
if (address != null) {
return ParsedAddress.thorChainAddress(address: address, name: text);
}
}
final formattedName = OpenaliasRecord.formatDomainName(text);
final domainParts = formattedName.split('.');
final name = domainParts.last;
if (domainParts.length <= 1 || domainParts.first.isEmpty || name.isEmpty) {
return ParsedAddress(addresses: [text]);
}
if (unstoppableDomains.any((domain) => name.trim() == domain)) {
if (settingsStore.lookupsUnstoppableDomains) {
final address = await fetchUnstoppableDomainAddress(text, ticker);
if (address.isNotEmpty) {
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
}
}
}
if (text.endsWith(".eth")) {
if (settingsStore.lookupsENS) {
final address = await EnsRecord.fetchEnsAddress(text, wallet: wallet);
if (address.isNotEmpty && address != "0x0000000000000000000000000000000000000000") {
return ParsedAddress.fetchEnsAddress(name: text, address: address);
}
}
}
if (formattedName.contains(".")) {
if (settingsStore.lookupsOpenAlias) {
final txtRecord = await OpenaliasRecord.lookupOpenAliasRecord(formattedName);
if (txtRecord != null) {
final record = await OpenaliasRecord.fetchAddressAndName(
formattedName: formattedName, ticker: ticker.toLowerCase(), txtRecord: txtRecord);
return ParsedAddress.fetchOpenAliasAddress(record: record, name: text);
}
}
}
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: currency);
if (addressFromBio != null) {
return ParsedAddress.nostrAddress(
address: addressFromBio,
name: text,
profileImageUrl: nostrUserData.picture,
profileName: nostrUserData.name);
}
}
}
}
} catch (e) {
printV(e.toString());
}
return ParsedAddress(addresses: [text]);
}
}