Fiat api fix (#1070)

* Cw 474 linux swapping wallets btc then xmr still shows btc receive qr code (#1068) * feat: improve address page txt field * fix: switching wallets from the desktop dropdown updates dashboard pages * Revert "feat: improve address page txt field" This reverts commit 0a30e6d9e1d13795219b66a6fdf2c1d218479089. * refactor: rename to WalletChangeListener * fix: _init also behaves on wallet change * Fix Fiat conversion API parsing Cherry pick fix for Desktop switching wallets not updating dashboard screens * Minor indentations fix [skip ci] --------- Co-authored-by: Rafael Saes <76502841+saltrafael@users.noreply.github.com>

Omar Hatem committed Sep 1, 2023 at 18:06 UTC 68a821cc0e293e38dccdc6cc0e015ed86f087489
7 files changed +208 -200
cw_monero/ios/Classes/monero_api.cpp
+7 -7
@@ -139,7 +139,7 @@ extern "C"
139 int8_t direction;
140 int8_t isPending;
141 uint32_t subaddrIndex;
142 -
142 +
143 char *hash;
144 char *paymentId;
145
@@ -154,7 +154,7 @@ extern "C"
154 std::set<uint32_t>::iterator it = transaction->subaddrIndex().begin();
155 subaddrIndex = *it;
156 confirmations = transaction->confirmations();
157 - datetime = static_cast<int64_t>(transaction->timestamp());
157 + datetime = static_cast<int64_t>(transaction->timestamp());
158 direction = transaction->direction();
159 isPending = static_cast<int8_t>(transaction->isPending());
160 std::string *hash_str = new std::string(transaction->hash());
@@ -234,7 +234,7 @@ extern "C"
234 }
235
236 void setUnlocked(bool unlocked);
237 -
237 +
238 };
239
240 Monero::Coins *m_coins;
@@ -254,7 +254,7 @@ extern "C"
254 {
255 m_wallet = wallet;
256 m_listener = nullptr;
257 -
257 +
258
259 if (wallet != nullptr)
260 {
@@ -479,7 +479,7 @@ extern "C"
479 {
480 nice(19);
481 Monero::Wallet *wallet = get_current_wallet();
482 -
482 +
483 std::string _login = "";
484 std::string _password = "";
485 std::string _socksProxyAddress = "";
@@ -568,7 +568,7 @@ extern "C"
568 _preferred_inputs.insert(std::string(*preferred_inputs));
569 preferred_inputs++;
570 }
571 -
571 +
572 auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
573 std::string _payment_id;
574 Monero::PendingTransaction *transaction;
@@ -587,7 +587,7 @@ extern "C"
587 {
588 transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(), m_wallet->defaultMixin(), priority, subaddr_account, {}, _preferred_inputs);
589 }
590 -
590 +
591 int status = transaction->status();
592
593 if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
lib/core/fiat_conversion_service.dart
+4 -4
@@ -21,7 +21,7 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
21 'key': secrets.fiatApiKey,
22 };
23
24 - double price = 0.0;
24 + num price = 0.0;
25
26 try {
27 late final Uri uri;
@@ -41,12 +41,12 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
41 final results = responseJSON['results'] as Map<String, dynamic>;
42
43 if (results.isNotEmpty) {
44 - price = results.values.first as double;
44 + price = results.values.first as num;
45 }
46
47 - return price;
47 + return price.toDouble();
48 } catch (e) {
49 - return price;
49 + return price.toDouble();
50 }
51 }
52
lib/core/wallet_change_listener_view_model.dart new
+30
@@ -0,0 +1,30 @@
1 +import 'package:cw_core/balance.dart';
2 +import 'package:cw_core/transaction_history.dart';
3 +import 'package:cw_core/transaction_info.dart';
4 +import 'package:mobx/mobx.dart';
5 +import 'package:cw_core/wallet_base.dart';
6 +import 'package:cake_wallet/store/app_store.dart';
7 +
8 +part 'wallet_change_listener_view_model.g.dart';
9 +
10 +class WalletChangeListenerViewModel = WalletChangeListenerViewModelBase
11 + with _$WalletChangeListenerViewModel;
12 +
13 +abstract class WalletChangeListenerViewModelBase with Store {
14 + WalletChangeListenerViewModelBase({
15 + required AppStore appStore,
16 + }) : _wallet = appStore.wallet! {
17 + reaction((_) => appStore.wallet, (WalletBase? wallet) {
18 + _wallet = wallet!;
19 + onWalletChange(wallet);
20 + });
21 + }
22 +
23 + void onWalletChange(WalletBase wallet) {}
24 +
25 + @observable
26 + WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> _wallet;
27 + @computed
28 + WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> get wallet =>
29 + _wallet;
30 +}
lib/di.dart
+2 -3
@@ -523,8 +523,7 @@ Future<void> setup({
523
524 getIt.registerFactory<SendViewModel>(
525 () => SendViewModel(
526 - getIt.get<AppStore>().wallet!,
527 - getIt.get<AppStore>().settingsStore,
526 + getIt.get<AppStore>(),
527 getIt.get<SendTemplateViewModel>(),
528 getIt.get<FiatConversionStore>(),
529 getIt.get<BalanceViewModel>(),
@@ -702,7 +701,7 @@ Future<void> setup({
701 ));
702
703 getIt.registerFactory(() => ExchangeViewModel(
705 - getIt.get<AppStore>().wallet!,
704 + getIt.get<AppStore>(),
705 _tradesSource,
706 getIt.get<ExchangeTemplateStore>(),
707 getIt.get<TradesStore>(),
lib/view_model/exchange/exchange_view_model.dart
+70 -94
@@ -2,6 +2,7 @@ import 'dart:async';
2 import 'dart:collection';
3 import 'dart:convert';
4
5 +import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
6 import 'package:cake_wallet/entities/exchange_api_mode.dart';
7 import 'package:cake_wallet/entities/preferences_key.dart';
8 import 'package:cake_wallet/entities/wallet_contact.dart';
@@ -13,7 +14,7 @@ import 'package:cake_wallet/exchange/trocador/trocador_exchange_provider.dart';
14 import 'package:cake_wallet/exchange/trocador/trocador_request.dart';
15 import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
16 import 'package:cw_core/transaction_priority.dart';
16 -import 'package:cw_core/wallet_base.dart';
17 +import 'package:cake_wallet/store/app_store.dart';
18 import 'package:cw_core/crypto_currency.dart';
19 import 'package:cw_core/sync_status.dart';
20 import 'package:cw_core/wallet_type.dart';
@@ -45,16 +46,22 @@ part 'exchange_view_model.g.dart';
46
47 class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel;
48
48 -abstract class ExchangeViewModelBase with Store {
49 +abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with Store {
50 + @override
51 + void onWalletChange(wallet) {
52 + receiveCurrency = wallet.currency;
53 + depositCurrency = wallet.currency;
54 + }
55 +
56 ExchangeViewModelBase(
50 - this.wallet,
51 - this.trades,
52 - this._exchangeTemplateStore,
53 - this.tradesStore,
54 - this._settingsStore,
55 - this.sharedPreferences,
56 - this.contactListViewModel)
57 - : _cryptoNumberFormat = NumberFormat(),
57 + AppStore appStore,
58 + this.trades,
59 + this._exchangeTemplateStore,
60 + this.tradesStore,
61 + this._settingsStore,
62 + this.sharedPreferences,
63 + this.contactListViewModel,
64 + ) : _cryptoNumberFormat = NumberFormat(),
65 isFixedRateMode = false,
66 isReceiveAmountEntered = false,
67 depositAmount = '',
@@ -70,10 +77,11 @@ abstract class ExchangeViewModelBase with Store {
77 limits = Limits(min: 0, max: 0),
78 tradeState = ExchangeTradeStateInitial(),
79 limitsState = LimitsInitialState(),
73 - receiveCurrency = wallet.currency,
74 - depositCurrency = wallet.currency,
80 + receiveCurrency = appStore.wallet!.currency,
81 + depositCurrency = appStore.wallet!.currency,
82 providerList = [],
76 - selectedProviders = ObservableList<ExchangeProvider>() {
83 + selectedProviders = ObservableList<ExchangeProvider>(),
84 + super(appStore: appStore) {
85 _useTorOnly = _settingsStore.exchangeStatus == ExchangeApiMode.torOnly;
86 _setProviders();
87 const excludeDepositCurrencies = [CryptoCurrency.btt, CryptoCurrency.nano];
@@ -86,10 +94,9 @@ abstract class ExchangeViewModelBase with Store {
94 ];
95 _initialPairBasedOnWallet();
96
89 - final Map<String, dynamic> exchangeProvidersSelection = json.decode(
90 - sharedPreferences
91 - .getString(PreferencesKey.exchangeProvidersSelection) ??
92 - "{}") as Map<String, dynamic>;
97 + final Map<String, dynamic> exchangeProvidersSelection =
98 + json.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}")
99 + as Map<String, dynamic>;
100
101 /// if the provider is not in the user settings (user's first time or newly added provider)
102 /// then use its default value decided by us
@@ -102,34 +109,28 @@ abstract class ExchangeViewModelBase with Store {
109 _setAvailableProviders();
110 _calculateBestRate();
111
105 - bestRateSync =
106 - Timer.periodic(Duration(seconds: 10), (timer) => _calculateBestRate());
112 + bestRateSync = Timer.periodic(Duration(seconds: 10), (timer) => _calculateBestRate());
113
114 isDepositAddressEnabled = !(depositCurrency == wallet.currency);
115 isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
116 depositAmount = '';
117 receiveAmount = '';
118 receiveAddress = '';
113 - depositAddress = depositCurrency == wallet.currency
114 - ? wallet.walletAddresses.address
115 - : '';
119 + depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.address : '';
120 provider = providersForCurrentPair().first;
121 final initialProvider = provider;
122 provider!.checkIsAvailable().then((bool isAvailable) {
123 if (!isAvailable && provider == initialProvider) {
120 - provider = providerList.firstWhere(
121 - (provider) => provider is ChangeNowExchangeProvider,
124 + provider = providerList.firstWhere((provider) => provider is ChangeNowExchangeProvider,
125 orElse: () => providerList.last);
126 _onPairChange();
127 }
128 });
129 receiveCurrencies = CryptoCurrency.all
127 - .where((cryptoCurrency) =>
128 - !excludeReceiveCurrencies.contains(cryptoCurrency))
130 + .where((cryptoCurrency) => !excludeReceiveCurrencies.contains(cryptoCurrency))
131 .toList();
132 depositCurrencies = CryptoCurrency.all
131 - .where((cryptoCurrency) =>
132 - !excludeDepositCurrencies.contains(cryptoCurrency))
133 + .where((cryptoCurrency) => !excludeDepositCurrencies.contains(cryptoCurrency))
134 .toList();
135 _defineIsReceiveAmountEditable();
136 loadLimits();
@@ -140,7 +141,6 @@ abstract class ExchangeViewModelBase with Store {
141 });
142 }
143 bool _useTorOnly;
143 - final WalletBase wallet;
144 final Box<Trade> trades;
145 final ExchangeTemplateStore _exchangeTemplateStore;
146 final TradesStore tradesStore;
@@ -165,8 +165,7 @@ abstract class ExchangeViewModelBase with Store {
165 /// initialize with descending comparator
166 /// since we want largest rate first
167 final SplayTreeMap<double, ExchangeProvider> _sortedAvailableProviders =
168 - SplayTreeMap<double, ExchangeProvider>(
169 - (double a, double b) => b.compareTo(a));
168 + SplayTreeMap<double, ExchangeProvider>((double a, double b) => b.compareTo(a));
169
170 final List<ExchangeProvider> _tradeAvailableProviders = [];
171
@@ -222,21 +221,17 @@ abstract class ExchangeViewModelBase with Store {
221 SyncStatus get status => wallet.syncStatus;
222
223 @computed
225 - ObservableList<ExchangeTemplate> get templates =>
226 - _exchangeTemplateStore.templates;
224 + ObservableList<ExchangeTemplate> get templates => _exchangeTemplateStore.templates;
225
226 @computed
229 - List<WalletContact> get walletContactsToShow =>
230 - contactListViewModel.walletContacts
231 - .where((element) =>
232 - receiveCurrency == null || element.type == receiveCurrency)
233 - .toList();
227 + List<WalletContact> get walletContactsToShow => contactListViewModel.walletContacts
228 + .where((element) => receiveCurrency == null || element.type == receiveCurrency)
229 + .toList();
230
231 @action
232 bool checkIfWalletIsAnInternalWallet(String address) {
237 - final walletContactList = walletContactsToShow
238 - .where((element) => element.address == address)
239 - .toList();
233 + final walletContactList =
234 + walletContactsToShow.where((element) => element.address == address).toList();
235
236 return walletContactList.isNotEmpty;
237 }
@@ -256,7 +251,6 @@ abstract class ExchangeViewModelBase with Store {
251 return false;
252 }
253
259 -
254 @computed
255 TransactionPriority get transactionPriority {
256 final priority = _settingsStore.priority[wallet.type];
@@ -269,7 +263,8 @@ abstract class ExchangeViewModelBase with Store {
263 }
264
265 bool get hasAllAmount =>
272 - (wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) && depositCurrency == wallet.currency;
266 + (wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) &&
267 + depositCurrency == wallet.currency;
268
269 bool get isMoneroWallet => wallet.type == WalletType.monero;
270
@@ -277,14 +272,11 @@ abstract class ExchangeViewModelBase with Store {
272 switch (wallet.type) {
273 case WalletType.monero:
274 case WalletType.haven:
280 - return transactionPriority ==
281 - monero!.getMoneroTransactionPrioritySlow();
275 + return transactionPriority == monero!.getMoneroTransactionPrioritySlow();
276 case WalletType.bitcoin:
283 - return transactionPriority ==
284 - bitcoin!.getBitcoinTransactionPrioritySlow();
277 + return transactionPriority == bitcoin!.getBitcoinTransactionPrioritySlow();
278 case WalletType.litecoin:
286 - return transactionPriority ==
287 - bitcoin!.getLitecoinTransactionPrioritySlow();
279 + return transactionPriority == bitcoin!.getLitecoinTransactionPrioritySlow();
280 default:
281 return false;
282 }
@@ -390,20 +382,18 @@ abstract class ExchangeViewModelBase with Store {
382 }
383
384 Future<void> _calculateBestRate() async {
393 - final amount =
394 - double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1;
385 + final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1;
386
387 final _providers = _tradeAvailableProviders
388 .where((element) => !isFixedRateMode || element.supportsFixedRate)
389 .toList();
390
400 - final result = await Future.wait<double>(_providers.map((element) =>
401 - element.fetchRate(
402 - from: depositCurrency,
403 - to: receiveCurrency,
404 - amount: amount,
405 - isFixedRateMode: isFixedRateMode,
406 - isReceiveAmount: isFixedRateMode)));
391 + final result = await Future.wait<double>(_providers.map((element) => element.fetchRate(
392 + from: depositCurrency,
393 + to: receiveCurrency,
394 + amount: amount,
395 + isFixedRateMode: isFixedRateMode,
396 + isReceiveAmount: isFixedRateMode)));
397
398 _sortedAvailableProviders.clear();
399
@@ -445,14 +435,13 @@ abstract class ExchangeViewModelBase with Store {
435 }
436
437 try {
448 - final tempLimits = await provider.fetchLimits(
449 - from: from, to: to, isFixedRateMode: isFixedRateMode);
438 + final tempLimits =
439 + await provider.fetchLimits(from: from, to: to, isFixedRateMode: isFixedRateMode);
440
441 if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) {
442 lowestMin = tempLimits.min;
443 }
454 - if (highestMax != null &&
455 - (tempLimits.max ?? double.maxFinite) > highestMax) {
444 + if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax) {
445 highestMax = tempLimits.max;
446 }
447 } catch (e) {
@@ -568,8 +557,8 @@ abstract class ExchangeViewModelBase with Store {
557 } else {
558 try {
559 tradeState = TradeIsCreating();
571 - final trade = await provider.createTrade(
572 - request: request!, isFixedRateMode: isFixedRateMode);
560 + final trade =
561 + await provider.createTrade(request: request!, isFixedRateMode: isFixedRateMode);
562 trade.walletId = wallet.id;
563 tradesStore.setTrade(trade);
564 await trades.add(trade);
@@ -604,12 +593,8 @@ abstract class ExchangeViewModelBase with Store {
593 isReceiveAmountEntered = false;
594 depositAmount = '';
595 receiveAmount = '';
607 - depositAddress = depositCurrency == wallet.currency
608 - ? wallet.walletAddresses.address
609 - : '';
610 - receiveAddress = receiveCurrency == wallet.currency
611 - ? wallet.walletAddresses.address
612 - : '';
596 + depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.address : '';
597 + receiveAddress = receiveCurrency == wallet.currency ? wallet.walletAddresses.address : '';
598 isDepositAddressEnabled = !(depositCurrency == wallet.currency);
599 isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
600 isFixedRateMode = false;
@@ -628,8 +613,7 @@ abstract class ExchangeViewModelBase with Store {
613 }
614
615 final amount = availableBalance - fee;
631 - changeDepositAmount(
632 - amount: bitcoin!.formatterBitcoinAmountToString(amount: amount));
616 + changeDepositAmount(amount: bitcoin!.formatterBitcoinAmountToString(amount: amount));
617 }
618 }
619
@@ -664,9 +648,8 @@ abstract class ExchangeViewModelBase with Store {
648 List<ExchangeProvider> _providersForPair(
649 {required CryptoCurrency from, required CryptoCurrency to}) {
650 final providers = providerList
667 - .where((provider) => provider.pairList
668 - .where((pair) => pair.from == from && pair.to == to)
669 - .isNotEmpty)
651 + .where((provider) =>
652 + provider.pairList.where((pair) => pair.from == from && pair.to == to).isNotEmpty)
653 .toList();
654
655 return providers;
@@ -746,14 +729,12 @@ abstract class ExchangeViewModelBase with Store {
729 _bestRate = 0;
730 _calculateBestRate();
731
749 - final Map<String, dynamic> exchangeProvidersSelection = json.decode(
750 - sharedPreferences
751 - .getString(PreferencesKey.exchangeProvidersSelection) ??
752 - "{}") as Map<String, dynamic>;
732 + final Map<String, dynamic> exchangeProvidersSelection =
733 + json.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}")
734 + as Map<String, dynamic>;
735
736 for (var provider in providerList) {
755 - exchangeProvidersSelection[provider.title] =
756 - selectedProviders.contains(provider);
737 + exchangeProvidersSelection[provider.title] = selectedProviders.contains(provider);
738 }
739
740 sharedPreferences.setString(
@@ -764,15 +745,15 @@ abstract class ExchangeViewModelBase with Store {
745
746 bool get isAvailableInSelected {
747 final providersForPair = providersForCurrentPair();
767 - return selectedProviders.any(
768 - (element) => element.isAvailable && providersForPair.contains(element));
748 + return selectedProviders
749 + .any((element) => element.isAvailable && providersForPair.contains(element));
750 }
751
752 void _setAvailableProviders() {
753 _tradeAvailableProviders.clear();
754
774 - _tradeAvailableProviders.addAll(selectedProviders
775 - .where((provider) => providersForCurrentPair().contains(provider)));
755 + _tradeAvailableProviders.addAll(
756 + selectedProviders.where((provider) => providersForCurrentPair().contains(provider)));
757 }
758
759 @action
@@ -780,16 +761,13 @@ abstract class ExchangeViewModelBase with Store {
761 switch (wallet.type) {
762 case WalletType.monero:
763 case WalletType.haven:
783 - _settingsStore.priority[wallet.type] =
784 - monero!.getMoneroTransactionPriorityAutomatic();
764 + _settingsStore.priority[wallet.type] = monero!.getMoneroTransactionPriorityAutomatic();
765 break;
766 case WalletType.bitcoin:
787 - _settingsStore.priority[wallet.type] =
788 - bitcoin!.getBitcoinTransactionPriorityMedium();
767 + _settingsStore.priority[wallet.type] = bitcoin!.getBitcoinTransactionPriorityMedium();
768 break;
769 case WalletType.litecoin:
791 - _settingsStore.priority[wallet.type] =
792 - bitcoin!.getLitecoinTransactionPriorityMedium();
770 + _settingsStore.priority[wallet.type] = bitcoin!.getLitecoinTransactionPriorityMedium();
771 break;
772 default:
773 break;
@@ -798,9 +776,7 @@ abstract class ExchangeViewModelBase with Store {
776
777 void _setProviders() {
778 if (_settingsStore.exchangeStatus == ExchangeApiMode.torOnly) {
801 - providerList = _allProviders
802 - .where((provider) => provider.supportsOnionAddress)
803 - .toList();
779 + providerList = _allProviders.where((provider) => provider.supportsOnionAddress).toList();
780 } else {
781 providerList = _allProviders;
782 }
lib/view_model/send/send_view_model.dart
+69 -62
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
2 import 'package:cake_wallet/entities/contact_record.dart';
3 import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
4 import 'package:cake_wallet/entities/transaction_description.dart';
@@ -15,7 +16,7 @@ import 'package:cake_wallet/core/address_validator.dart';
16 import 'package:cake_wallet/core/amount_validator.dart';
17 import 'package:cw_core/pending_transaction.dart';
18 import 'package:cake_wallet/core/validator.dart';
18 -import 'package:cw_core/wallet_base.dart';
19 +import 'package:cake_wallet/store/app_store.dart';
20 import 'package:cake_wallet/core/execution_state.dart';
21 import 'package:cake_wallet/monero/monero.dart';
22 import 'package:cw_core/sync_status.dart';
@@ -34,30 +35,38 @@ part 'send_view_model.g.dart';
35
36 class SendViewModel = SendViewModelBase with _$SendViewModel;
37
37 -abstract class SendViewModelBase with Store {
38 +abstract class SendViewModelBase extends WalletChangeListenerViewModel with Store {
39 + @override
40 + void onWalletChange(wallet) {
41 + currencies = wallet.balance.keys.toList();
42 + selectedCryptoCurrency = wallet.currency;
43 + hasMultipleTokens = wallet.type == WalletType.ethereum;
44 + }
45 +
46 SendViewModelBase(
39 - this._wallet,
40 - this._settingsStore,
41 - this.sendTemplateViewModel,
42 - this._fiatConversationStore,
43 - this.balanceViewModel,
44 - this.contactListViewModel,
45 - this.transactionDescriptionBox)
46 - : state = InitialExecutionState(),
47 - currencies = _wallet.balance.keys.toList(),
48 - selectedCryptoCurrency = _wallet.currency,
49 - hasMultipleTokens = _wallet.type == WalletType.ethereum,
47 + AppStore appStore,
48 + this.sendTemplateViewModel,
49 + this._fiatConversationStore,
50 + this.balanceViewModel,
51 + this.contactListViewModel,
52 + this.transactionDescriptionBox,
53 + ) : state = InitialExecutionState(),
54 + currencies = appStore.wallet!.balance.keys.toList(),
55 + selectedCryptoCurrency = appStore.wallet!.currency,
56 + hasMultipleTokens = appStore.wallet!.type == WalletType.ethereum,
57 outputs = ObservableList<Output>(),
51 - fiatFromSettings = _settingsStore.fiatCurrency {
52 - final priority = _settingsStore.priority[_wallet.type];
53 - final priorities = priorityForWalletType(_wallet.type);
54 -
55 - if (!priorityForWalletType(_wallet.type).contains(priority)) {
56 - _settingsStore.priority[_wallet.type] = priorities.first;
58 + _settingsStore = appStore.settingsStore,
59 + fiatFromSettings = appStore.settingsStore.fiatCurrency,
60 + super(appStore: appStore) {
61 + final priority = _settingsStore.priority[wallet.type];
62 + final priorities = priorityForWalletType(wallet.type);
63 +
64 + if (!priorityForWalletType(wallet.type).contains(priority)) {
65 + _settingsStore.priority[wallet.type] = priorities.first;
66 }
67
68 outputs
60 - .add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency));
69 + .add(Output(wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency));
70 }
71
72 @observable
@@ -68,7 +77,7 @@ abstract class SendViewModelBase with Store {
77 @action
78 void addOutput() {
79 outputs
71 - .add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency));
80 + .add(Output(wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency));
81 }
82
83 @action
@@ -107,9 +116,8 @@ abstract class SendViewModelBase with Store {
116 String get pendingTransactionFeeFiatAmount {
117 try {
118 if (pendingTransaction != null) {
110 - final currency = walletType == WalletType.ethereum
111 - ? _wallet.currency
112 - : selectedCryptoCurrency;
119 + final currency =
120 + walletType == WalletType.ethereum ? wallet.currency : selectedCryptoCurrency;
121 final fiat = calculateFiatAmount(
122 price: _fiatConversationStore.prices[currency]!,
123 cryptoAmount: pendingTransaction!.feeFormatted);
@@ -125,19 +133,19 @@ abstract class SendViewModelBase with Store {
133 FiatCurrency get fiat => _settingsStore.fiatCurrency;
134
135 TransactionPriority get transactionPriority {
128 - final priority = _settingsStore.priority[_wallet.type];
136 + final priority = _settingsStore.priority[wallet.type];
137
138 if (priority == null) {
131 - throw Exception('Unexpected type ${_wallet.type}');
139 + throw Exception('Unexpected type ${wallet.type}');
140 }
141
142 return priority;
143 }
144
137 - CryptoCurrency get currency => _wallet.currency;
145 + CryptoCurrency get currency => wallet.currency;
146
147 Validator<String> get amountValidator =>
140 - AmountValidator(currency: walletTypeToCryptoCurrency(_wallet.type));
148 + AmountValidator(currency: walletTypeToCryptoCurrency(wallet.type));
149
150 Validator<String> get allAmountValidator => AllAmountValidator();
151
@@ -151,7 +159,7 @@ abstract class SendViewModelBase with Store {
159 PendingTransaction? pendingTransaction;
160
161 @computed
154 - String get balance => _wallet.balance[selectedCryptoCurrency]!.formattedAvailableBalance;
162 + String get balance => wallet.balance[selectedCryptoCurrency]!.formattedAvailableBalance;
163
164 @computed
165 bool get isFiatDisabled => balanceViewModel.isFiatDisabled;
@@ -165,7 +173,7 @@ abstract class SendViewModelBase with Store {
173 isFiatDisabled ? '' : pendingTransactionFeeFiatAmount + ' ' + fiat.title;
174
175 @computed
168 - bool get isReadyForSend => _wallet.syncStatus is SyncedSyncStatus;
176 + bool get isReadyForSend => wallet.syncStatus is SyncedSyncStatus;
177
178 @computed
179 List<Template> get templates => sendTemplateViewModel.templates
@@ -174,39 +182,40 @@ abstract class SendViewModelBase with Store {
182
183 @computed
184 bool get hasCoinControl =>
177 - _wallet.type == WalletType.bitcoin || _wallet.type == WalletType.litecoin || _wallet.type == WalletType.monero;
185 + wallet.type == WalletType.bitcoin ||
186 + wallet.type == WalletType.litecoin ||
187 + wallet.type == WalletType.monero;
188
189 @computed
190 bool get isElectrumWallet =>
181 - _wallet.type == WalletType.bitcoin || _wallet.type == WalletType.litecoin;
191 + wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin;
192
193 @observable
194 CryptoCurrency selectedCryptoCurrency;
195
196 List<CryptoCurrency> currencies;
197
188 - bool get hasYat => outputs.any((out) =>
189 - out.isParsedAddress &&
190 - out.parsedAddress.parseFrom == ParseFrom.yatRecord);
198 + bool get hasYat => outputs
199 + .any((out) => out.isParsedAddress && out.parsedAddress.parseFrom == ParseFrom.yatRecord);
200
192 - WalletType get walletType => _wallet.type;
201 + WalletType get walletType => wallet.type;
202
194 - String? get walletCurrencyName =>
195 - _wallet.currency.fullName?.toLowerCase() ?? _wallet.currency.name;
203 + String? get walletCurrencyName => wallet.currency.fullName?.toLowerCase() ?? wallet.currency.name;
204
205 bool get hasCurrecyChanger => walletType == WalletType.haven;
206
207 @computed
208 FiatCurrency get fiatCurrency => _settingsStore.fiatCurrency;
209
202 - final WalletBase _wallet;
210 final SettingsStore _settingsStore;
211 final SendTemplateViewModel sendTemplateViewModel;
212 final BalanceViewModel balanceViewModel;
213 final ContactListViewModel contactListViewModel;
214 final FiatConversionStore _fiatConversationStore;
215 final Box<TransactionDescription> transactionDescriptionBox;
209 - final bool hasMultipleTokens;
216 +
217 + @observable
218 + bool hasMultipleTokens;
219
220 @computed
221 List<ContactRecord> get contactsToShow => contactListViewModel.contacts
@@ -275,7 +284,7 @@ abstract class SendViewModelBase with Store {
284 Future<void> createTransaction() async {
285 try {
286 state = IsExecutingState();
278 - pendingTransaction = await _wallet.createTransaction(_credentials());
287 + pendingTransaction = await wallet.createTransaction(_credentials());
288 state = ExecutedSuccessfullyState();
289 } catch (e) {
290 state = FailureState(e.toString());
@@ -322,61 +331,60 @@ abstract class SendViewModelBase with Store {
331
332 @action
333 void setTransactionPriority(TransactionPriority priority) =>
325 - _settingsStore.priority[_wallet.type] = priority;
334 + _settingsStore.priority[wallet.type] = priority;
335
336 Object _credentials() {
328 - switch (_wallet.type) {
337 + switch (wallet.type) {
338 case WalletType.bitcoin:
330 - final priority = _settingsStore.priority[_wallet.type];
339 + final priority = _settingsStore.priority[wallet.type];
340
341 if (priority == null) {
333 - throw Exception('Priority is null for wallet type: ${_wallet.type}');
342 + throw Exception('Priority is null for wallet type: ${wallet.type}');
343 }
344
345 return bitcoin!.createBitcoinTransactionCredentials(outputs, priority: priority);
346 case WalletType.litecoin:
338 - final priority = _settingsStore.priority[_wallet.type];
347 + final priority = _settingsStore.priority[wallet.type];
348
349 if (priority == null) {
341 - throw Exception('Priority is null for wallet type: ${_wallet.type}');
350 + throw Exception('Priority is null for wallet type: ${wallet.type}');
351 }
352
353 return bitcoin!.createBitcoinTransactionCredentials(outputs, priority: priority);
354 case WalletType.monero:
346 - final priority = _settingsStore.priority[_wallet.type];
355 + final priority = _settingsStore.priority[wallet.type];
356
357 if (priority == null) {
349 - throw Exception('Priority is null for wallet type: ${_wallet.type}');
358 + throw Exception('Priority is null for wallet type: ${wallet.type}');
359 }
360
361 return monero!
362 .createMoneroTransactionCreationCredentials(outputs: outputs, priority: priority);
363 case WalletType.haven:
355 - final priority = _settingsStore.priority[_wallet.type];
364 + final priority = _settingsStore.priority[wallet.type];
365
366 if (priority == null) {
358 - throw Exception('Priority is null for wallet type: ${_wallet.type}');
367 + throw Exception('Priority is null for wallet type: ${wallet.type}');
368 }
369
370 return haven!.createHavenTransactionCreationCredentials(
371 outputs: outputs, priority: priority, assetType: selectedCryptoCurrency.title);
372 case WalletType.ethereum:
364 - final priority = _settingsStore.priority[_wallet.type];
373 + final priority = _settingsStore.priority[wallet.type];
374
375 if (priority == null) {
367 - throw Exception('Priority is null for wallet type: ${_wallet.type}');
376 + throw Exception('Priority is null for wallet type: ${wallet.type}');
377 }
378
370 - return ethereum!.createEthereumTransactionCredentials(
371 - outputs, priority: priority, currency: selectedCryptoCurrency);
379 + return ethereum!.createEthereumTransactionCredentials(outputs,
380 + priority: priority, currency: selectedCryptoCurrency);
381 default:
373 - throw Exception('Unexpected wallet type: ${_wallet.type}');
382 + throw Exception('Unexpected wallet type: ${wallet.type}');
383 }
384 }
385
386 String displayFeeRate(dynamic priority) {
387 final _priority = priority as TransactionPriority;
379 - final wallet = _wallet;
388
389 if (isElectrumWallet) {
390 final rate = bitcoin!.getFeeRate(wallet, _priority);
@@ -387,22 +395,21 @@ abstract class SendViewModelBase with Store {
395 }
396
397 bool _isEqualCurrency(String currency) =>
390 - _wallet.balance.keys.any((e) => currency.toLowerCase() == e.title.toLowerCase());
398 + wallet.balance.keys.any((e) => currency.toLowerCase() == e.title.toLowerCase());
399
400 @action
401 void onClose() => _settingsStore.fiatCurrency = fiatFromSettings;
402
403 @action
396 - void setFiatCurrency(FiatCurrency fiat) =>
397 - _settingsStore.fiatCurrency = fiat;
404 + void setFiatCurrency(FiatCurrency fiat) => _settingsStore.fiatCurrency = fiat;
405
406 @action
407 void setSelectedCryptoCurrency(String cryptoCurrency) {
408 try {
402 - selectedCryptoCurrency = _wallet.balance.keys
409 + selectedCryptoCurrency = wallet.balance.keys
410 .firstWhere((e) => cryptoCurrency.toLowerCase() == e.title.toLowerCase());
411 } catch (e) {
405 - selectedCryptoCurrency = _wallet.currency;
412 + selectedCryptoCurrency = wallet.currency;
413 }
414 }
415 }
lib/view_model/wallet_address_list/wallet_address_list_view_model.dart
+26 -30
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
2 import 'package:cake_wallet/ethereum/ethereum.dart';
3 import 'package:cake_wallet/entities/fiat_currency.dart';
4 import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
@@ -5,16 +6,12 @@ import 'package:cake_wallet/store/yat/yat_store.dart';
6 import 'package:cw_core/currency.dart';
7 import 'package:intl/intl.dart';
8 import 'package:mobx/mobx.dart';
8 -import 'package:cw_core/wallet_base.dart';
9 import 'package:cake_wallet/utils/list_item.dart';
10 import 'package:cake_wallet/view_model/wallet_address_list/wallet_account_list_header.dart';
11 import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_header.dart';
12 import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
13 import 'package:cw_core/wallet_type.dart';
14 import 'package:cake_wallet/bitcoin/bitcoin.dart';
15 -import 'package:cw_core/transaction_history.dart';
16 -import 'package:cw_core/balance.dart';
17 -import 'package:cw_core/transaction_info.dart';
15 import 'package:cake_wallet/store/app_store.dart';
16 import 'package:cake_wallet/monero/monero.dart';
17 import 'package:cake_wallet/haven/haven.dart';
@@ -110,29 +107,36 @@ class EthereumURI extends PaymentURI {
107 }
108 }
109
113 -abstract class WalletAddressListViewModelBase with Store {
110 +abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewModel with Store {
111 WalletAddressListViewModelBase({
112 required AppStore appStore,
113 required this.yatStore,
114 required this.fiatConversionStore,
118 - }) : _appStore = appStore,
119 - _baseItems = <ListItem>[],
120 - _wallet = appStore.wallet!,
115 + }) : _baseItems = <ListItem>[],
116 selectedCurrency = walletTypeToCryptoCurrency(appStore.wallet!.type),
117 _cryptoNumberFormat = NumberFormat(_cryptoNumberPattern),
118 hasAccounts =
119 appStore.wallet!.type == WalletType.monero || appStore.wallet!.type == WalletType.haven,
125 - amount = '' {
120 + amount = '',
121 + super(appStore: appStore) {
122 _init();
123 }
124
125 + @override
126 + void onWalletChange(wallet) {
127 + _init();
128 +
129 + selectedCurrency = walletTypeToCryptoCurrency(wallet.type);
130 + hasAccounts = wallet.type == WalletType.monero || wallet.type == WalletType.haven;
131 + }
132 +
133 static const String _cryptoNumberPattern = '0.00000000';
134
135 final NumberFormat _cryptoNumberFormat;
136
137 final FiatConversionStore fiatConversionStore;
138
135 - List<Currency> get currencies => [walletTypeToCryptoCurrency(_wallet.type), ...FiatCurrency.all];
139 + List<Currency> get currencies => [walletTypeToCryptoCurrency(wallet.type), ...FiatCurrency.all];
140
141 @observable
142 Currency selectedCurrency;
@@ -144,31 +148,31 @@ abstract class WalletAddressListViewModelBase with Store {
148 String amount;
149
150 @computed
147 - WalletType get type => _wallet.type;
151 + WalletType get type => wallet.type;
152
153 @computed
154 WalletAddressListItem get address =>
151 - WalletAddressListItem(address: _wallet.walletAddresses.address, isPrimary: false);
155 + WalletAddressListItem(address: wallet.walletAddresses.address, isPrimary: false);
156
157 @computed
158 PaymentURI get uri {
155 - if (_wallet.type == WalletType.monero) {
159 + if (wallet.type == WalletType.monero) {
160 return MoneroURI(amount: amount, address: address.address);
161 }
162
159 - if (_wallet.type == WalletType.haven) {
163 + if (wallet.type == WalletType.haven) {
164 return HavenURI(amount: amount, address: address.address);
165 }
166
163 - if (_wallet.type == WalletType.bitcoin) {
167 + if (wallet.type == WalletType.bitcoin) {
168 return BitcoinURI(amount: amount, address: address.address);
169 }
170
167 - if (_wallet.type == WalletType.litecoin) {
171 + if (wallet.type == WalletType.litecoin) {
172 return LitecoinURI(amount: amount, address: address.address);
173 }
174
171 - if (_wallet.type == WalletType.ethereum) {
175 + if (wallet.type == WalletType.ethereum) {
176 return EthereumURI(amount: amount, address: address.address);
177 }
178
@@ -182,7 +186,6 @@ abstract class WalletAddressListViewModelBase with Store {
186
187 @computed
188 ObservableList<ListItem> get addressList {
185 - final wallet = _wallet;
189 final addressList = ObservableList<ListItem>();
190
191 if (wallet.type == WalletType.monero) {
@@ -237,8 +240,6 @@ abstract class WalletAddressListViewModelBase with Store {
240
241 @computed
242 String get accountLabel {
240 - final wallet = _wallet;
241 -
243 if (wallet.type == WalletType.monero) {
244 return monero!.getCurrentAccount(wallet).label;
245 }
@@ -251,29 +252,24 @@ abstract class WalletAddressListViewModelBase with Store {
252 }
253
254 @computed
254 - bool get hasAddressList => _wallet.type == WalletType.monero || _wallet.type == WalletType.haven;
255 + bool get hasAddressList => wallet.type == WalletType.monero || wallet.type == WalletType.haven;
256
257 @computed
258 bool get showElectrumAddressDisclaimer =>
258 - _wallet.type == WalletType.bitcoin || _wallet.type == WalletType.litecoin;
259 -
260 - @observable
261 - WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> _wallet;
259 + wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin;
260
261 List<ListItem> _baseItems;
262
265 - AppStore _appStore;
266 -
263 final YatStore yatStore;
264
265 @action
266 void setAddress(WalletAddressListItem address) =>
271 - _wallet.walletAddresses.address = address.address;
267 + wallet.walletAddresses.address = address.address;
268
269 void _init() {
270 _baseItems = [];
271
276 - if (_wallet.type == WalletType.monero || _wallet.type == WalletType.haven) {
272 + if (wallet.type == WalletType.monero || wallet.type == WalletType.haven) {
273 _baseItems.add(WalletAccountListHeader());
274 }
275
@@ -294,7 +290,7 @@ abstract class WalletAddressListViewModelBase with Store {
290 }
291
292 void _convertAmountToCrypto() {
297 - final cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type);
293 + final cryptoCurrency = walletTypeToCryptoCurrency(wallet.type);
294 try {
295 final crypto =
296 double.parse(amount.replaceAll(',', '.')) / fiatConversionStore.prices[cryptoCurrency]!;