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:
jwinterm
2026-10-24 23:49:29 -04:00
1406 changed files with 81062 additions and 48972 deletions
@@ -9,6 +9,7 @@ import 'package:hash_wallet/store/settings_store.dart';
import 'package:hash_wallet/view_model/dashboard/balance_view_model.dart';
import 'package:hash_wallet/view_model/hardware_wallet/hardware_wallet_view_model.dart';
import 'package:hash_wallet/view_model/send/send_view_model_state.dart';
import 'package:cw_core/amount/money.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/parse_fixed.dart';
import 'package:cw_core/pending_transaction.dart';
@@ -22,7 +23,10 @@ class DEuroViewModel = DEuroViewModelBase with _$DEuroViewModel;
abstract class DEuroViewModelBase with Store {
final AppStore _appStore;
static BigInt get MIN_ACCRUED_INTEREST => BigInt.parse("1000000000000");
static Money get MIN_ACCRUED_INTEREST =>
Money(BigInt.parse("1000000000000"), CryptoCurrency.deuro);
static Money get ZERO => Money.zero(CryptoCurrency.deuro);
DEuroViewModelBase(
this._appStore, this.balanceViewModel, this._settingsStore, this._fiatConversationStore,
@@ -51,13 +55,13 @@ abstract class DEuroViewModelBase with Store {
@computed
String get pendingTransactionFiatAmountFormatted {
final amount = transaction == null ? '0.00' : _getDEuroFiatAmount(transaction!.amountFormatted);
return isFiatDisabled ? '' : '$amount ${fiat.title}';
final amount = transaction == null ? "0.00" : _getDEuroFiatAmount(transaction!.amount);
return isFiatDisabled ? "" : "$amount ${fiat.symbol}";
}
@computed
String get pendingTransactionFeeFiatAmountFormatted {
var amount = '0.00';
var amount = "0.00";
try {
if (transaction != null) {
final feeCurrency = CryptoCurrency.eth;
@@ -67,42 +71,43 @@ abstract class DEuroViewModelBase with Store {
);
}
} catch (_) {}
return isFiatDisabled ? '' : '$amount ${fiat.title}';
return isFiatDisabled ? "" : "$amount ${fiat.symbol}";
}
@computed
String get accountBalanceFormated {
Money get accountBalance {
final dEuroKey = balanceViewModel.balances.keys
.firstWhereOrNull((e) => e.title == CryptoCurrency.deuro.title);
if (dEuroKey == null) return '0.00';
return balanceViewModel.balances[dEuroKey]?.availableBalance ?? '0.00';
if (dEuroKey == null) return ZERO;
return wallet.balance[dEuroKey]?.available ?? ZERO;
}
@observable
BigInt savingsBalance = BigInt.zero;
Money savingsBalance = ZERO;
@computed
String get savingsBalanceFormated =>
evm!.formatterEVMAmountToDouble(amount: savingsBalance).toStringAsFixed(6);
String get fiatSavingsBalanceFormated => _getDEuroFiatAmount(savingsBalance);
@observable
Money? savingsBalanceV1 = null;
@computed
String get fiatSavingsBalanceFormated => _getDEuroFiatAmount(savingsBalanceFormated);
String get fiatSavingsBalanceV1Formated => _getDEuroFiatAmount(savingsBalanceV1);
@observable
ExecutionState state = InitialExecutionState();
@observable
String interestRateFormated = '0';
String interestRateFormated = "0";
@observable
BigInt accruedInterest = BigInt.zero;
Money accruedInterest = ZERO;
@computed
String get accruedInterestFormated =>
evm!.formatterEVMAmountToDouble(amount: accruedInterest).toStringAsFixed(6);
String get accruedInterestFormated => accruedInterest.toStringWithPrecision(fractionalDigits: 6);
@computed
String get fiatAccruedInterestFormated => _getDEuroFiatAmount(accruedInterestFormated);
String get fiatAccruedInterestFormated => _getDEuroFiatAmount(accruedInterest);
@observable
BigInt approvedTokens = BigInt.zero;
@@ -128,8 +133,12 @@ abstract class DEuroViewModelBase with Store {
@action
Future<void> reloadSavingsUserData() async {
approvedTokens = await evm!.getDEuroSavingsApproved(_appStore.wallet!) ?? BigInt.zero;
savingsBalance = await evm!.getDEuroSavingsBalance(_appStore.wallet!) ?? BigInt.zero;
accruedInterest = await evm!.getDEuroAccruedInterest(_appStore.wallet!) ?? BigInt.zero;
savingsBalance = await evm!.getDEuroSavingsBalance(_appStore.wallet!) ?? ZERO;
accruedInterest = await evm!.getDEuroAccruedInterest(_appStore.wallet!) ?? ZERO;
final v1Balance = await evm!.getDEuroSavingsV1Balance(_appStore.wallet!) ?? ZERO;
savingsBalanceV1 = v1Balance.isZero ? null : v1Balance;
isLoading = false;
}
@@ -151,9 +160,8 @@ abstract class DEuroViewModelBase with Store {
state = TransactionCommitting();
final priority = _appStore.settingsStore.getPriority(wallet.type, chainId: wallet.chainId)!;
final approval = await evm!.enableDEuroSaving(_appStore.wallet!, priority);
if (approval == null) {
throw Exception('DEuro saving not available');
}
if (approval == null) throw Exception("DEuro saving not available");
approvalTransaction = approval;
state = InitialExecutionState();
} catch (e) {
@@ -167,13 +175,13 @@ abstract class DEuroViewModelBase with Store {
state = TransactionCommitting();
if (amountRaw.isEmpty || amountRaw.trim().isEmpty) {
throw Exception('Invalid amount: amount cannot be empty');
throw Exception("Invalid amount: amount cannot be empty");
}
final amount = tryParseFixed(amountRaw, 18);
if (amount == BigInt.zero || amount == null) {
throw Exception('Invalid amount: amount cannot be zero');
throw Exception("Invalid amount: amount cannot be zero");
}
final priority = _appStore.settingsStore.getPriority(wallet.type, chainId: wallet.chainId)!;
@@ -181,9 +189,24 @@ abstract class DEuroViewModelBase with Store {
final tx = await (isAdding
? evm!.addDEuroSaving(_appStore.wallet!, amount, priority)
: evm!.removeDEuroSaving(_appStore.wallet!, amount, priority));
if (tx == null) {
throw Exception('DEuro saving not available');
}
if (tx == null) throw Exception("DEuro saving not available");
transaction = tx;
state = InitialExecutionState();
} catch (e) {
state = FailureState(e.toString());
}
}
@action
Future<void> prepareSavingsV1Withdraw() async {
try {
state = TransactionCommitting();
actionType = DEuroActionType.withdraw;
final priority = _appStore.settingsStore.getPriority(wallet.type, chainId: wallet.chainId)!;
final tx = await evm!.withdrawDEuroSavingV1(_appStore.wallet!, priority);
if (tx == null) throw Exception("DEuro saving not available");
transaction = tx;
state = InitialExecutionState();
} catch (e) {
@@ -193,13 +216,13 @@ abstract class DEuroViewModelBase with Store {
Future<void> prepareCollectInterest() async {
if (accruedInterest < MIN_ACCRUED_INTEREST) {
state = FailureState('Accrued interest is below minimum threshold');
state = FailureState("Accrued interest is below minimum threshold");
return;
}
final formatted = accruedInterestFormated;
if (formatted.isEmpty || formatted == '0.000000') {
state = FailureState('Invalid accrued interest amount');
if (formatted.isEmpty || formatted == "0.000000") {
state = FailureState("Invalid accrued interest amount");
return;
}
@@ -212,9 +235,8 @@ abstract class DEuroViewModelBase with Store {
actionType = DEuroActionType.reinvest;
final priority = _appStore.settingsStore.getPriority(wallet.type, chainId: wallet.chainId)!;
final tx = await evm!.reinvestDEuroInterest(_appStore.wallet!, priority);
if (tx == null) {
throw Exception('DEuro saving not available');
}
if (tx == null) throw Exception("DEuro saving not available");
transaction = tx;
state = InitialExecutionState();
} catch (e) {
@@ -261,7 +283,9 @@ abstract class DEuroViewModelBase with Store {
state = InitialExecutionState();
}
String _getDEuroFiatAmount(String amount) {
String _getDEuroFiatAmount(Money? amount) {
if (amount == null) return "0.00";
try {
var dEuro = CryptoCurrency.deuro;
final keys = _fiatConversationStore.prices.keys.toList();
@@ -270,19 +294,14 @@ abstract class DEuroViewModelBase with Store {
}
return calculateFiatAmount(
price: _fiatConversationStore.prices[dEuro]!,
cryptoAmount: amount,
cryptoAmount: amount.toStringWithPrecision(fractionalDigits: 6),
);
} catch (_) {
return '0.00';
return "0.00";
}
}
}
class NoEtherState extends ExecutionState {}
enum DEuroActionType {
deposit,
withdraw,
reinvest,
none;
}
enum DEuroActionType { deposit, withdraw, reinvest, none }