Fix fiat rate on receive screen. (#1754)
Some checks failed
Cache Dependencies / test (push) Has been cancelled

* Fix fiat rate on receive screen.

* Code cleanup

* Update Receive QR on currency change
This commit is contained in:
Konstantin Ullrich 2024-10-17 14:52:55 +02:00 committed by GitHub
parent cd5a1277a7
commit 6c9de67599
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,14 +1,15 @@
import 'dart:math';
import 'dart:developer' as dev;
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/core/fiat_conversion_service.dart';
import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/haven/haven.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/solana/solana.dart';
import 'package:cake_wallet/store/app_store.dart';
@ -24,16 +25,14 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_i
import 'package:cake_wallet/wownero/wownero.dart';
import 'package:cw_core/amount_converter.dart';
import 'package:cw_core/currency.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cw_monero/api/wallet.dart';
import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
import 'package:mobx/mobx.dart';
part 'wallet_address_list_view_model.g.dart';
class WalletAddressListViewModel = WalletAddressListViewModelBase with _$WalletAddressListViewModel;
class WalletAddressListViewModel = WalletAddressListViewModelBase
with _$WalletAddressListViewModel;
abstract class PaymentURI {
PaymentURI({required this.amount, required this.address});
@ -43,12 +42,11 @@ abstract class PaymentURI {
}
class MoneroURI extends PaymentURI {
MoneroURI({required String amount, required String address})
: super(amount: amount, address: address);
MoneroURI({required super.amount, required super.address});
@override
String toString() {
var base = 'monero:' + address;
var base = 'monero:$address';
if (amount.isNotEmpty) {
base += '?tx_amount=${amount.replaceAll(',', '.')}';
@ -59,12 +57,11 @@ class MoneroURI extends PaymentURI {
}
class HavenURI extends PaymentURI {
HavenURI({required String amount, required String address})
: super(amount: amount, address: address);
HavenURI({required super.amount, required super.address});
@override
String toString() {
var base = 'haven:' + address;
var base = 'haven:$address';
if (amount.isNotEmpty) {
base += '?tx_amount=${amount.replaceAll(',', '.')}';
@ -75,12 +72,11 @@ class HavenURI extends PaymentURI {
}
class BitcoinURI extends PaymentURI {
BitcoinURI({required String amount, required String address})
: super(amount: amount, address: address);
BitcoinURI({required super.amount, required super.address});
@override
String toString() {
var base = 'bitcoin:' + address;
var base = 'bitcoin:$address';
if (amount.isNotEmpty) {
base += '?amount=${amount.replaceAll(',', '.')}';
@ -91,12 +87,11 @@ class BitcoinURI extends PaymentURI {
}
class LitecoinURI extends PaymentURI {
LitecoinURI({required String amount, required String address})
: super(amount: amount, address: address);
LitecoinURI({required super.amount, required super.address});
@override
String toString() {
var base = 'litecoin:' + address;
var base = 'litecoin:$address';
if (amount.isNotEmpty) {
base += '?amount=${amount.replaceAll(',', '.')}';
@ -107,12 +102,11 @@ class LitecoinURI extends PaymentURI {
}
class EthereumURI extends PaymentURI {
EthereumURI({required String amount, required String address})
: super(amount: amount, address: address);
EthereumURI({required super.amount, required super.address});
@override
String toString() {
var base = 'ethereum:' + address;
var base = 'ethereum:$address';
if (amount.isNotEmpty) {
base += '?amount=${amount.replaceAll(',', '.')}';
@ -123,8 +117,7 @@ class EthereumURI extends PaymentURI {
}
class BitcoinCashURI extends PaymentURI {
BitcoinCashURI({required String amount, required String address})
: super(amount: amount, address: address);
BitcoinCashURI({required super.amount, required super.address});
@override
String toString() {
@ -139,12 +132,11 @@ class BitcoinCashURI extends PaymentURI {
}
class NanoURI extends PaymentURI {
NanoURI({required String amount, required String address})
: super(amount: amount, address: address);
NanoURI({required super.amount, required super.address});
@override
String toString() {
var base = 'nano:' + address;
var base = 'nano:$address';
if (amount.isNotEmpty) {
base += '?amount=${amount.replaceAll(',', '.')}';
}
@ -154,12 +146,11 @@ class NanoURI extends PaymentURI {
}
class PolygonURI extends PaymentURI {
PolygonURI({required String amount, required String address})
: super(amount: amount, address: address);
PolygonURI({required super.amount, required super.address});
@override
String toString() {
var base = 'polygon:' + address;
var base = 'polygon:$address';
if (amount.isNotEmpty) {
base += '?amount=${amount.replaceAll(',', '.')}';
@ -170,12 +161,12 @@ class PolygonURI extends PaymentURI {
}
class SolanaURI extends PaymentURI {
SolanaURI({required String amount, required String address})
: super(amount: amount, address: address);
SolanaURI({required super.amount, required super.address});
@override
String toString() {
var base = 'solana:' + address;
var base = 'solana:$address';
if (amount.isNotEmpty) {
base += '?amount=${amount.replaceAll(',', '.')}';
}
@ -185,12 +176,12 @@ class SolanaURI extends PaymentURI {
}
class TronURI extends PaymentURI {
TronURI({required String amount, required String address})
: super(amount: amount, address: address);
TronURI({required super.amount, required super.address});
@override
String toString() {
var base = 'tron:' + address;
var base = 'tron:$address';
if (amount.isNotEmpty) {
base += '?amount=${amount.replaceAll(',', '.')}';
}
@ -200,12 +191,11 @@ class TronURI extends PaymentURI {
}
class WowneroURI extends PaymentURI {
WowneroURI({required String amount, required String address})
: super(amount: amount, address: address);
WowneroURI({required super.amount, required super.address});
@override
String toString() {
var base = 'wownero:' + address;
var base = 'wownero:$address';
if (amount.isNotEmpty) {
base += '?tx_amount=${amount.replaceAll(',', '.')}';
@ -215,7 +205,8 @@ class WowneroURI extends PaymentURI {
}
}
abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewModel with Store {
abstract class WalletAddressListViewModelBase
extends WalletChangeListenerViewModel with Store {
WalletAddressListViewModelBase({
required AppStore appStore,
required this.yatStore,
@ -223,9 +214,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
}) : _baseItems = <ListItem>[],
selectedCurrency = walletTypeToCryptoCurrency(appStore.wallet!.type),
_cryptoNumberFormat = NumberFormat(_cryptoNumberPattern),
hasAccounts = appStore.wallet!.type == WalletType.monero ||
appStore.wallet!.type == WalletType.wownero ||
appStore.wallet!.type == WalletType.haven,
hasAccounts = [WalletType.monero, WalletType.wownero, WalletType.haven]
.contains(appStore.wallet!.type),
amount = '',
_settingsStore = appStore.settingsStore,
super(appStore: appStore) {
@ -237,9 +227,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
_init();
selectedCurrency = walletTypeToCryptoCurrency(wallet.type);
hasAccounts = wallet.type == WalletType.monero ||
wallet.type == WalletType.wownero ||
wallet.type == WalletType.haven;
hasAccounts = [WalletType.monero, WalletType.wownero, WalletType.haven]
.contains(wallet.type);
}
static const String _cryptoNumberPattern = '0.00000000';
@ -249,7 +238,11 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
final FiatConversionStore fiatConversionStore;
final SettingsStore _settingsStore;
List<Currency> get currencies => [walletTypeToCryptoCurrency(wallet.type), ...FiatCurrency.all];
double? _fiatRate;
String _rawAmount = '';
List<Currency> get currencies =>
[walletTypeToCryptoCurrency(wallet.type), ...FiatCurrency.all];
String get buttonTitle {
if (isElectrumWallet) {
@ -275,9 +268,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
WalletType get type => wallet.type;
@computed
WalletAddressListItem get address {
return WalletAddressListItem(address: wallet.walletAddresses.address, isPrimary: false);
}
WalletAddressListItem get address => WalletAddressListItem(
address: wallet.walletAddresses.address, isPrimary: false);
@computed
PaymentURI get uri {
@ -321,8 +313,10 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
final addressList = ObservableList<ListItem>();
if (wallet.type == WalletType.monero) {
final primaryAddress = monero!.getSubaddressList(wallet).subaddresses.first;
final addressItems = monero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
final primaryAddress =
monero!.getSubaddressList(wallet).subaddresses.first;
final addressItems =
monero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
final isPrimary = subaddress == primaryAddress;
return WalletAddressListItem(
@ -338,8 +332,10 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
}
if (wallet.type == WalletType.wownero) {
final primaryAddress = wownero!.getSubaddressList(wallet).subaddresses.first;
final addressItems = wownero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
final primaryAddress =
wownero!.getSubaddressList(wallet).subaddresses.first;
final addressItems =
wownero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
final isPrimary = subaddress == primaryAddress;
return WalletAddressListItem(
@ -352,8 +348,10 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
}
if (wallet.type == WalletType.haven) {
final primaryAddress = haven!.getSubaddressList(wallet).subaddresses.first;
final addressItems = haven!.getSubaddressList(wallet).subaddresses.map((subaddress) {
final primaryAddress =
haven!.getSubaddressList(wallet).subaddresses.first;
final addressItems =
haven!.getSubaddressList(wallet).subaddresses.map((subaddress) {
final isPrimary = subaddress == primaryAddress;
return WalletAddressListItem(
@ -367,7 +365,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
if (isElectrumWallet) {
if (bitcoin!.hasSelectedSilentPayments(wallet)) {
final addressItems = bitcoin!.getSilentPaymentAddresses(wallet).map((address) {
final addressItems =
bitcoin!.getSilentPaymentAddresses(wallet).map((address) {
final isPrimary = address.id == 0;
return WalletAddressListItem(
@ -418,7 +417,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
if (wallet.type == WalletType.litecoin && addressItems.length >= 1000) {
// find the index of the last item with a txCount > 0
final addressItemsList = addressItems.toList();
int index = addressItemsList.lastIndexWhere((item) => (item.txCount ?? 0) > 0);
int index = addressItemsList
.lastIndexWhere((item) => (item.txCount ?? 0) > 0);
if (index == -1) {
index = 0;
}
@ -432,19 +432,22 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
if (wallet.type == WalletType.ethereum) {
final primaryAddress = ethereum!.getAddress(wallet);
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
addressList.add(WalletAddressListItem(
isPrimary: true, name: null, address: primaryAddress));
}
if (wallet.type == WalletType.polygon) {
final primaryAddress = polygon!.getAddress(wallet);
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
addressList.add(WalletAddressListItem(
isPrimary: true, name: null, address: primaryAddress));
}
if (wallet.type == WalletType.solana) {
final primaryAddress = solana!.getAddress(wallet);
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
addressList.add(WalletAddressListItem(
isPrimary: true, name: null, address: primaryAddress));
}
if (wallet.type == WalletType.nano) {
@ -458,18 +461,21 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
if (wallet.type == WalletType.tron) {
final primaryAddress = tron!.getAddress(wallet);
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
addressList.add(WalletAddressListItem(
isPrimary: true, name: null, address: primaryAddress));
}
for (var i = 0; i < addressList.length; i++) {
if (!(addressList[i] is WalletAddressListItem)) continue;
(addressList[i] as WalletAddressListItem).isHidden = wallet.walletAddresses.hiddenAddresses
(addressList[i] as WalletAddressListItem).isHidden = wallet
.walletAddresses.hiddenAddresses
.contains((addressList[i] as WalletAddressListItem).address);
}
for (var i = 0; i < addressList.length; i++) {
if (!(addressList[i] is WalletAddressListItem)) continue;
(addressList[i] as WalletAddressListItem).isManual = wallet.walletAddresses.manualAddresses
(addressList[i] as WalletAddressListItem).isManual = wallet
.walletAddresses.manualAddresses
.contains((addressList[i] as WalletAddressListItem).address);
}
@ -487,7 +493,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
Future<void> toggleHideAddress(WalletAddressListItem item) async {
if (item.isHidden) {
wallet.walletAddresses.hiddenAddresses.removeWhere((element) => element == item.address);
wallet.walletAddresses.hiddenAddresses
.removeWhere((element) => element == item.address);
} else {
wallet.walletAddresses.hiddenAddresses.add(item.address);
}
@ -512,57 +519,58 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
@computed
String get accountLabel {
if (wallet.type == WalletType.monero) {
return monero!.getCurrentAccount(wallet).label;
switch (wallet.type) {
case WalletType.monero:
return monero!.getCurrentAccount(wallet).label;
case WalletType.wownero:
wownero!.getCurrentAccount(wallet).label;
case WalletType.haven:
return haven!.getCurrentAccount(wallet).label;
default:
return '';
}
if (wallet.type == WalletType.wownero) {
return wownero!.getCurrentAccount(wallet).label;
}
if (wallet.type == WalletType.haven) {
return haven!.getCurrentAccount(wallet).label;
}
return '';
}
@computed
bool get hasAddressList =>
wallet.type == WalletType.monero ||
wallet.type == WalletType.wownero ||
wallet.type == WalletType.haven ||
wallet.type == WalletType.bitcoinCash ||
wallet.type == WalletType.bitcoin ||
wallet.type == WalletType.litecoin;
bool get hasAddressList => [
WalletType.monero,
WalletType.wownero,
WalletType.haven,
WalletType.bitcoinCash,
WalletType.bitcoin,
WalletType.litecoin
].contains(wallet.type);
@computed
bool get isElectrumWallet =>
wallet.type == WalletType.bitcoin ||
wallet.type == WalletType.litecoin ||
wallet.type == WalletType.bitcoinCash;
bool get isElectrumWallet => [
WalletType.bitcoin,
WalletType.litecoin,
WalletType.bitcoinCash
].contains(wallet.type);
@computed
bool get isBalanceAvailable => isElectrumWallet;
@computed
bool get isReceivedAvailable =>
wallet.type == WalletType.monero || wallet.type == WalletType.wownero;
[WalletType.monero, WalletType.wownero].contains(wallet.type);
@computed
bool get isSilentPayments =>
wallet.type == WalletType.bitcoin && bitcoin!.hasSelectedSilentPayments(wallet);
wallet.type == WalletType.bitcoin &&
bitcoin!.hasSelectedSilentPayments(wallet);
@computed
bool get isAutoGenerateSubaddressEnabled =>
_settingsStore.autoGenerateSubaddressStatus != AutoGenerateSubaddressStatus.disabled &&
_settingsStore.autoGenerateSubaddressStatus !=
AutoGenerateSubaddressStatus.disabled &&
!isSilentPayments;
@computed
bool get showAddManualAddresses =>
!isAutoGenerateSubaddressEnabled ||
wallet.type == WalletType.monero ||
wallet.type == WalletType.wownero;
[WalletType.monero, WalletType.wownero].contains(wallet.type);
List<ListItem> _baseItems;
@ -574,7 +582,7 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
@action
Future<void> setAddressType(dynamic option) async {
if (wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) {
if ([WalletType.bitcoin, WalletType.litecoin].contains(wallet.type)) {
await bitcoin!.setAddressType(wallet, option);
}
}
@ -586,13 +594,15 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
_baseItems.add(WalletAddressHiddenListHeader());
}
if (wallet.type == WalletType.monero ||
wallet.type == WalletType.wownero ||
wallet.type == WalletType.haven) {
if ([
WalletType.monero,
WalletType.wownero,
WalletType.haven,
].contains(wallet.type)) {
_baseItems.add(WalletAccountListHeader());
}
if (wallet.type != WalletType.nano && wallet.type != WalletType.banano) {
if (![WalletType.nano, WalletType.banano].contains(wallet.type)) {
_baseItems.add(WalletAddressListHeader());
}
if (wallet.isEnabledAutoGenerateSubaddress) {
@ -603,11 +613,27 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
@action
void selectCurrency(Currency currency) {
selectedCurrency = currency;
if (currency is FiatCurrency && _settingsStore.fiatCurrency != currency) {
final cryptoCurrency = walletTypeToCryptoCurrency(wallet.type);
dev.log("Requesting Fiat rate for $cryptoCurrency-$currency");
FiatConversionService.fetchPrice(
crypto: cryptoCurrency,
fiat: currency,
torOnly: _settingsStore.fiatApiMode == FiatApiMode.torOnly,
).then((value) {
dev.log("Received Fiat rate 1 $cryptoCurrency = $value $currency");
_fiatRate = value;
_convertAmountToCrypto();
});
}
}
@action
void changeAmount(String amount) {
this.amount = amount;
this._rawAmount = amount;
if (selectedCurrency is FiatCurrency) {
_convertAmountToCrypto();
}
@ -618,11 +644,20 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
searchText = text;
}
@action
void _convertAmountToCrypto() {
final cryptoCurrency = walletTypeToCryptoCurrency(wallet.type);
final fiatRate =
_fiatRate ?? (fiatConversionStore.prices[cryptoCurrency] ?? 0.0);
if (fiatRate <= 0.0) {
dev.log("Invalid Fiat Rate $fiatRate");
amount = '';
return;
}
try {
final crypto =
double.parse(amount.replaceAll(',', '.')) / fiatConversionStore.prices[cryptoCurrency]!;
final crypto = double.parse(_rawAmount.replaceAll(',', '.')) / fiatRate;
final cryptoAmountTmp = _cryptoNumberFormat.format(crypto);
if (amount != cryptoAmountTmp) {
amount = cryptoAmountTmp;