mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-30 06:48:49 +01:00
Merge upstream Cake Wallet v6.5.0
Catches up from the May 12 fork point (v6.1.2+23) through v6.5.0: 535 upstream commits, including the Monero silent-open fix, Monero on Trezor, Ledger/Trezor BLE fixes, the new seed and history screens, quick Bitcoin sync, git-pinned dependencies (pubspec_overrides.yaml), frozen Hive adapters (*.part.dart), monero_c v0.18.4.6-RC2 and Flutter 3.41.9. Merged with both sides normalized first (import rename, 100-column format), which took the conflict count from 614 paths to 322. The procedure is now scripts/upstream_sync.sh. Kept from Hash Bags: - WalletType enum order and Hive IDs. SQLite stores WalletType.index and our order differs from upstream's; taking theirs would reread saved wallets as other chains. Our frozen adapter keeps the shipped IDs. - The 1.0.2 legacy PIN and wallet-password decode and self-heal. - Removed chains (Solana, Tron, Zano, Zcash, Decred, Haven) and the new Robinhood chain stay out; Cake Pay and non-Trocador swaps stay out. - Default nodes (node.wownero.org, sethforprivacy, Blockstream, bysh.me), converted to upstream's isDefault node-list key; Wownero is back in the node reset list. - Privacy: address resolvers limited to domain-anchored sources again; prices.neroswap.com for fiat; upstream's charts tab, which reads prices.cakewallet.com, sits behind FeatureFlag.isChartsEnabled = false. - Lightning stays behind FeatureFlag.isLightningEnabled, including upstream's new post-seed Lightning username step. - Our icon pipeline, branding and bundle identifiers. Twelve new upstream widget tests are skipped: test and code are unchanged from v6.5.0 apart from renames (not rerun on a pristine upstream checkout; upstream's top_bar_test does not compile against its own TopBar). flutter analyze lib: 0 errors; flutter test: 345 passed, 12 skipped; flutter build bundle compiles. Built with Flutter 3.41.9.
This commit is contained in:
@@ -14,6 +14,7 @@ import 'package:hash_wallet/utils/mobx.dart';
|
||||
import 'package:hash_wallet/utils/token_utilities.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/currency_for_wallet_type.dart';
|
||||
import "package:cw_core/utils/print_verbose.dart";
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
@@ -33,75 +34,100 @@ abstract class ContactListViewModelBase with Store {
|
||||
}
|
||||
|
||||
Future<void> _init() async {
|
||||
final walletInfos = await WalletInfo.getAll();
|
||||
for (final info in walletInfos) {
|
||||
final addressInfos = await info.getAddressInfos();
|
||||
final addresses = await info.getAddresses();
|
||||
if ([WalletType.monero, WalletType.wownero].contains(info.type) && addressInfos.isNotEmpty) {
|
||||
for (var key in addressInfos.keys) {
|
||||
final value = addressInfos[key];
|
||||
final address = value?.first;
|
||||
if (address != null) {
|
||||
final name = _createName(info.name, address.label, key: key);
|
||||
walletContacts.add(WalletContact(
|
||||
address.address,
|
||||
await loadWalletContacts();
|
||||
|
||||
_subscription = contactSource.bindToListWithTransform(
|
||||
contacts,
|
||||
(contact) => ContactRecord(contactSource, contact),
|
||||
initialFire: true,
|
||||
);
|
||||
|
||||
setOrderType(settingsStore.contactListOrder);
|
||||
}
|
||||
|
||||
Future<void> _lastWalletContactsLoad = Future.value();
|
||||
|
||||
@action
|
||||
Future<void> loadWalletContacts() async {
|
||||
final waitFor = _lastWalletContactsLoad;
|
||||
final done = Completer<void>();
|
||||
_lastWalletContactsLoad = done.future;
|
||||
|
||||
await waitFor;
|
||||
|
||||
try {
|
||||
final loadedContacts = <WalletContact>[];
|
||||
final walletInfos = await WalletInfo.getAll();
|
||||
for (final info in walletInfos) {
|
||||
final addressInfos = await info.getAddressInfos();
|
||||
final addresses = await info.getAddresses();
|
||||
if ([WalletType.monero, WalletType.wownero].contains(info.type) &&
|
||||
addressInfos.isNotEmpty) {
|
||||
for (var key in addressInfos.keys) {
|
||||
final value = addressInfos[key];
|
||||
final address = value?.first;
|
||||
if (address != null) {
|
||||
final name = _createName(info.name, address.label, key: key);
|
||||
loadedContacts.add(WalletContact(
|
||||
address.address,
|
||||
name,
|
||||
getCryptoCurrencyForWalletListItem(
|
||||
info.type,
|
||||
),
|
||||
walletType: info.type,
|
||||
));
|
||||
}
|
||||
}
|
||||
} else if (addresses.isNotEmpty == true && addresses.length > 1) {
|
||||
if ([WalletType.monero, WalletType.wownero].contains(info.type)) {
|
||||
final address = info.address;
|
||||
final name = _createName(info.name, "", key: 0);
|
||||
loadedContacts.add(WalletContact(
|
||||
address,
|
||||
name,
|
||||
getCryptoCurrencyForWalletListItem(
|
||||
info.type,
|
||||
),
|
||||
walletType: info.type,
|
||||
));
|
||||
} else {
|
||||
addresses.forEach((address, label) {
|
||||
if (label.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final name = _createName(info.name, label, key: null);
|
||||
loadedContacts.add(WalletContact(
|
||||
address,
|
||||
name,
|
||||
getCryptoCurrencyForWalletListItem(
|
||||
info.type,
|
||||
isTestnet: info.network == null
|
||||
? false
|
||||
: info.network!.toLowerCase().contains("testnet"),
|
||||
),
|
||||
walletType: info.type,
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (addresses.isNotEmpty == true && addresses.length > 1) {
|
||||
if ([WalletType.monero, WalletType.wownero].contains(info.type)) {
|
||||
final address = info.address;
|
||||
final name = _createName(info.name, "", key: 0);
|
||||
walletContacts.add(WalletContact(
|
||||
address,
|
||||
name,
|
||||
} else {
|
||||
loadedContacts.add(WalletContact(
|
||||
info.address,
|
||||
_createName(info.name, "",
|
||||
key: [WalletType.monero, WalletType.wownero].contains(info.type) ? 0 : null),
|
||||
getCryptoCurrencyForWalletListItem(
|
||||
info.type,
|
||||
),
|
||||
walletType: info.type,
|
||||
));
|
||||
} else {
|
||||
addresses.forEach((address, label) {
|
||||
if (label.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final name = _createName(info.name, label, key: null);
|
||||
walletContacts.add(WalletContact(
|
||||
address,
|
||||
name,
|
||||
getCryptoCurrencyForWalletListItem(
|
||||
info.type,
|
||||
isTestnet:
|
||||
info.network == null ? false : info.network!.toLowerCase().contains("testnet"),
|
||||
),
|
||||
walletType: info.type,
|
||||
));
|
||||
});
|
||||
}
|
||||
} else {
|
||||
walletContacts.add(WalletContact(
|
||||
info.address,
|
||||
_createName(info.name, "",
|
||||
key: [WalletType.monero, WalletType.wownero].contains(info.type) ? 0 : null),
|
||||
getCryptoCurrencyForWalletListItem(
|
||||
info.type,
|
||||
),
|
||||
walletType: info.type,
|
||||
));
|
||||
}
|
||||
|
||||
walletContacts = loadedContacts;
|
||||
} catch (e) {
|
||||
printV("loadWalletContacts failed: $e");
|
||||
} finally {
|
||||
done.complete();
|
||||
}
|
||||
|
||||
_subscription = contactSource.bindToListWithTransform(
|
||||
contacts, (Contact contact) => ContactRecord(contactSource, contact),
|
||||
initialFire: true);
|
||||
|
||||
setOrderType(settingsStore.contactListOrder);
|
||||
walletContacts = walletContacts.toList(); // rebuild
|
||||
}
|
||||
|
||||
String _createName(String walletName, String label, {int? key = null}) {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import 'package:hash_wallet/core/address_resolver/address_resolver_service.dart';
|
||||
import 'package:hash_wallet/core/address_resolver/parsed_address.dart';
|
||||
import 'package:hash_wallet/core/address_validator.dart';
|
||||
import 'package:hash_wallet/di.dart';
|
||||
import 'package:hash_wallet/entities/contact_record.dart';
|
||||
import 'package:hash_wallet/entities/parse_address_from_domain.dart';
|
||||
import 'package:hash_wallet/src/screens/send/widgets/extract_address_from_parsed.dart';
|
||||
import 'package:hash_wallet/main.dart';
|
||||
import 'package:hash_wallet/store/app_store.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
@@ -16,7 +19,7 @@ part 'contact_view_model.g.dart';
|
||||
class ContactViewModel = ContactViewModelBase with _$ContactViewModel;
|
||||
|
||||
abstract class ContactViewModelBase with Store {
|
||||
ContactViewModelBase(this._contacts, {ContactRecord? contact})
|
||||
ContactViewModelBase(this._contacts, this.appStore, this.adrResService, {ContactRecord? contact})
|
||||
: state = InitialExecutionState(),
|
||||
currencies = CryptoCurrency.all,
|
||||
_contact = contact,
|
||||
@@ -26,6 +29,9 @@ abstract class ContactViewModelBase with Store {
|
||||
currency = contact?.type,
|
||||
lastChange = contact?.lastChange;
|
||||
|
||||
final AppStore appStore;
|
||||
final AddressResolverService adrResService;
|
||||
|
||||
@observable
|
||||
ExecutionState state;
|
||||
|
||||
@@ -55,16 +61,50 @@ abstract class ContactViewModelBase with Store {
|
||||
void reset() {
|
||||
address = '';
|
||||
name = '';
|
||||
displayName = '';
|
||||
currency = null;
|
||||
}
|
||||
|
||||
Future<void> extractParsedAddress(BuildContext context) async {
|
||||
if (currency == null) return;
|
||||
final parsedAddress = await getIt.get<AddressResolver>().resolve(context, address, currency!);
|
||||
if (parsedAddress.name.isNotEmpty) {
|
||||
displayName = parsedAddress.name;
|
||||
Future<ParsedAddress?> extractParsedAddress(BuildContext context) async {
|
||||
final wallet = appStore.wallet;
|
||||
final currentCurrency = currency;
|
||||
final query = address.trim();
|
||||
|
||||
if (wallet == null) return null;
|
||||
if (currentCurrency == null) return null;
|
||||
if (query.isEmpty) return null;
|
||||
|
||||
// Check if the address is valid for the current currency (except for Zano, which can use handles as addresses)
|
||||
if (currentCurrency != CryptoCurrency.zano) {
|
||||
final isValidAddress = AddressValidator(type: currentCurrency).isValid(query);
|
||||
if (isValidAddress) return null;
|
||||
}
|
||||
address = await extractAddressFromParsed(null, parsedAddress);
|
||||
|
||||
final parsedAddresses = await adrResService.resolve(
|
||||
query: query,
|
||||
wallet: wallet,
|
||||
currency: currentCurrency,
|
||||
);
|
||||
|
||||
if (parsedAddresses.isEmpty) return null;
|
||||
|
||||
final resolvedAddress = parsedAddresses.first.parsedAddressByCurrencyMap[currentCurrency];
|
||||
if (resolvedAddress == null || resolvedAddress.isEmpty) return null;
|
||||
|
||||
return parsedAddresses.first;
|
||||
}
|
||||
|
||||
@action
|
||||
void applyParsedAddress(ParsedAddress parsedAddress) {
|
||||
final currentCurrency = currency;
|
||||
if (currentCurrency == null) return;
|
||||
|
||||
final resolvedAddress = parsedAddress.parsedAddressByCurrencyMap[currentCurrency];
|
||||
if (resolvedAddress == null || resolvedAddress.isEmpty) return;
|
||||
|
||||
address = resolvedAddress;
|
||||
displayName =
|
||||
parsedAddress.profileName.isNotEmpty ? parsedAddress.profileName : parsedAddress.handle;
|
||||
}
|
||||
|
||||
Future<void> save() async {
|
||||
|
||||
Reference in New Issue
Block a user