seed generation fixes

This commit is contained in:
fosse 2023-08-04 10:54:20 -04:00
parent 6688682096
commit 32dd14a53e
4 changed files with 125 additions and 114 deletions

View file

@ -23,6 +23,10 @@ class NanoUtil {
NanoAccountType.NANO, privateKeyToPublic(seedToPrivate(seed, index))); NanoAccountType.NANO, privateKeyToPublic(seedToPrivate(seed, index)));
} }
static String seedToMnemonic(String seed) {
return NanoMnemomics.seedToMnemonic(seed).join(" ");
}
// static String createPublicKey(String privateKey) { // static String createPublicKey(String privateKey) {
// return NanoHelpers.byteToHex(Ed25519Blake2b.getPubkey(NanoHelpers.hexToBytes(privateKey))!); // return NanoHelpers.byteToHex(Ed25519Blake2b.getPubkey(NanoHelpers.hexToBytes(privateKey))!);
// } // }
@ -207,5 +211,4 @@ class NanoUtil {
final Decimal rawDecimal = Decimal.parse(rawPerCur.toString()); final Decimal rawDecimal = Decimal.parse(rawPerCur.toString());
return (asDecimal * rawDecimal).toString(); return (asDecimal * rawDecimal).toString();
} }
} }

View file

@ -59,9 +59,10 @@ abstract class NanoWalletBase
final String _password; final String _password;
final DerivationType _derivationType; final DerivationType _derivationType;
late final String _privateKey; String? _privateKey;
late final String _publicAddress; String? _publicAddress;
late final String _seedKey; String? _seedKey;
String? _representativeAddress; String? _representativeAddress;
Timer? _receiveTimer; Timer? _receiveTimer;
@ -82,11 +83,10 @@ abstract class NanoWalletBase
// initialize the different forms of private / public key we'll need: // initialize the different forms of private / public key we'll need:
Future<void> init() async { Future<void> init() async {
final String type = (_derivationType == DerivationType.nano) ? "standard" : "hd"; final String type = (_derivationType == DerivationType.nano) ? "standard" : "hd";
_seedKey = bip39.mnemonicToEntropy(_mnemonic).toUpperCase(); _seedKey = bip39.mnemonicToEntropy(_mnemonic).toUpperCase();
_privateKey = await NanoUtil.uniSeedToPrivate(_seedKey, 0, type); _privateKey = await NanoUtil.uniSeedToPrivate(_seedKey!, 0, type);
_publicAddress = await NanoUtil.uniSeedToAddress(_seedKey, 0, type); _publicAddress = await NanoUtil.uniSeedToAddress(_seedKey!, 0, type);
this.walletInfo.address = _publicAddress; this.walletInfo.address = _publicAddress!;
await walletAddresses.init(); await walletAddresses.init();
await transactionHistory.init(); await transactionHistory.init();
@ -158,7 +158,7 @@ abstract class NanoWalletBase
final block = await _client.constructSendBlock( final block = await _client.constructSendBlock(
amountRaw: amt.toString(), amountRaw: amt.toString(),
destinationAddress: txOut.address, destinationAddress: txOut.address,
privateKey: _privateKey, privateKey: _privateKey!,
balanceAfterTx: runningBalance, balanceAfterTx: runningBalance,
previousHash: previousHash, previousHash: previousHash,
); );
@ -195,8 +195,8 @@ abstract class NanoWalletBase
Future<void> _receiveAll() async { Future<void> _receiveAll() async {
await _updateBalance(); await _updateBalance();
int blocksReceived = await this._client.confirmAllReceivable( int blocksReceived = await this._client.confirmAllReceivable(
destinationAddress: _publicAddress, destinationAddress: _publicAddress!,
privateKey: _privateKey, privateKey: _privateKey!,
); );
if (blocksReceived > 0) { if (blocksReceived > 0) {
@ -224,7 +224,7 @@ abstract class NanoWalletBase
@override @override
Future<Map<String, NanoTransactionInfo>> fetchTransactions() async { Future<Map<String, NanoTransactionInfo>> fetchTransactions() async {
String address = _publicAddress; String address = _publicAddress!;
final transactions = await _client.fetchTransactions(address); final transactions = await _client.fetchTransactions(address);
@ -249,7 +249,7 @@ abstract class NanoWalletBase
@override @override
NanoWalletKeys get keys { NanoWalletKeys get keys {
return NanoWalletKeys(seedKey: _seedKey); return NanoWalletKeys(seedKey: _seedKey!);
} }
@override @override
@ -303,7 +303,8 @@ abstract class NanoWalletBase
String toJSON() => json.encode({ String toJSON() => json.encode({
'seedKey': _seedKey, 'seedKey': _seedKey,
'mnemonic': _mnemonic, 'mnemonic': _mnemonic,
// 'balance': balance[currency]!.toJSON(), 'currentBalance': balance[currency]?.currentBalance.toString() ?? "0",
'receivableBalance': balance[currency]?.receivableBalance.toString() ?? "0",
'derivationType': _derivationType.toString() 'derivationType': _derivationType.toString()
}); });
@ -314,11 +315,12 @@ abstract class NanoWalletBase
}) async { }) async {
final path = await pathForWallet(name: name, type: walletInfo.type); final path = await pathForWallet(name: name, type: walletInfo.type);
final jsonSource = await read(path: path, password: password); final jsonSource = await read(path: path, password: password);
final data = json.decode(jsonSource) as Map; final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String; final mnemonic = data['mnemonic'] as String;
final balance = NanoBalance.fromString( final balance = NanoBalance.fromString(
formattedCurrentBalance: data['balance'] as String? ?? "0", formattedCurrentBalance: data['currentBalance'] as String? ?? "0",
formattedReceivableBalance: "0"); formattedReceivableBalance: data['receivableBalance'] as String? ?? "0");
DerivationType derivationType = DerivationType.bip39; DerivationType derivationType = DerivationType.bip39;
if (data['derivationType'] == "DerivationType.nano") { if (data['derivationType'] == "DerivationType.nano") {
@ -336,16 +338,17 @@ abstract class NanoWalletBase
mnemonic: mnemonic, mnemonic: mnemonic,
initialBalance: balance, initialBalance: balance,
); );
// init() should always be run after this!
} }
Future<void> _updateBalance() async { Future<void> _updateBalance() async {
balance[currency] = await _client.getBalance(_publicAddress); balance[currency] = await _client.getBalance(_publicAddress!);
await save(); await save();
} }
Future<void> _updateRep() async { Future<void> _updateRep() async {
try { try {
final accountInfo = await _client.getAccountInfo(_publicAddress); final accountInfo = await _client.getAccountInfo(_publicAddress!);
_representativeAddress = accountInfo["representative"] as String; _representativeAddress = accountInfo["representative"] as String;
} catch (e) { } catch (e) {
throw Exception("Failed to get representative address $e"); throw Exception("Failed to get representative address $e");
@ -355,9 +358,9 @@ abstract class NanoWalletBase
Future<void> changeRep(String address) async { Future<void> changeRep(String address) async {
try { try {
final String hash = await _client.changeRep( final String hash = await _client.changeRep(
privateKey: _privateKey, privateKey: _privateKey!,
repAddress: address, repAddress: address,
ourAddress: _publicAddress, ourAddress: _publicAddress!,
); );
if (hash.isNotEmpty) { if (hash.isNotEmpty) {
_representativeAddress = address; _representativeAddress = address;

View file

@ -9,12 +9,13 @@ import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:cw_nano/nano_balance.dart'; import 'package:cw_nano/nano_balance.dart';
import 'package:cw_nano/nano_client.dart'; import 'package:cw_nano/nano_client.dart';
import 'package:cw_nano/nano_mnemonic.dart'; import 'package:cw_nano/nano_mnemonic.dart' as nm;
import 'package:cw_nano/nano_util.dart'; import 'package:cw_nano/nano_util.dart';
import 'package:cw_nano/nano_wallet.dart'; import 'package:cw_nano/nano_wallet.dart';
import 'package:cw_nano/nano_wallet_info.dart'; import 'package:cw_nano/nano_wallet_info.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:bip39/bip39.dart' as bip39; import 'package:bip39/bip39.dart' as bip39;
import 'package:nanodart/nanodart.dart';
class NanoNewWalletCredentials extends WalletCredentials { class NanoNewWalletCredentials extends WalletCredentials {
NanoNewWalletCredentials({required String name, String? password}) NanoNewWalletCredentials({required String name, String? password})
@ -65,10 +66,18 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
@override @override
Future<WalletBase> create(NanoNewWalletCredentials credentials) async { Future<WalletBase> create(NanoNewWalletCredentials credentials) async {
final mnemonic = bip39.generateMnemonic(); // nano standard:
DerivationType derivationType = DerivationType.nano;
String seedKey = NanoSeeds.generateSeed();
String mnemonic = NanoUtil.seedToMnemonic(seedKey);
// bip39:
// derivationType derivationType = DerivationType.bip39;
// String mnemonic = bip39.generateMnemonic();
final nanoWalletInfo = NanoWalletInfo( final nanoWalletInfo = NanoWalletInfo(
walletInfo: credentials.walletInfo!, walletInfo: credentials.walletInfo!,
derivationType: DerivationType.nano, derivationType: derivationType,
); );
final wallet = NanoWallet( final wallet = NanoWallet(
@ -76,6 +85,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
mnemonic: mnemonic, mnemonic: mnemonic,
password: credentials.password!, password: credentials.password!,
); );
wallet.init();
return wallet; return wallet;
} }
@ -178,11 +188,11 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
@override @override
Future<NanoWallet> restoreFromSeed(NanoRestoreWalletFromSeedCredentials credentials) async { Future<NanoWallet> restoreFromSeed(NanoRestoreWalletFromSeedCredentials credentials) async {
if (!bip39.validateMnemonic(credentials.mnemonic)) { if (!bip39.validateMnemonic(credentials.mnemonic)) {
throw NanoMnemonicIsIncorrectException(); throw nm.NanoMnemonicIsIncorrectException();
} }
if (!NanoMnemomics.validateMnemonic(credentials.mnemonic.split(' '))) { if (!NanoMnemomics.validateMnemonic(credentials.mnemonic.split(' '))) {
throw NanoMnemonicIsIncorrectException(); throw nm.NanoMnemonicIsIncorrectException();
} }
DerivationType derivationType = credentials.derivationType ?? DerivationType derivationType = credentials.derivationType ??

View file

@ -44,42 +44,48 @@ part 'exchange_view_model.g.dart';
class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel; class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel;
abstract class ExchangeViewModelBase with Store { abstract class ExchangeViewModelBase with Store {
ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore, ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore, this.tradesStore,
this.tradesStore, this._settingsStore, this.sharedPreferences) this._settingsStore, this.sharedPreferences)
: _cryptoNumberFormat = NumberFormat(), : _cryptoNumberFormat = NumberFormat(),
isFixedRateMode = false, isFixedRateMode = false,
isReceiveAmountEntered = false, isReceiveAmountEntered = false,
depositAmount = '', depositAmount = '',
receiveAmount = '', receiveAmount = '',
receiveAddress = '', receiveAddress = '',
depositAddress = '', depositAddress = '',
isDepositAddressEnabled = false, isDepositAddressEnabled = false,
isReceiveAddressEnabled = false, isReceiveAddressEnabled = false,
isReceiveAmountEditable = false, isReceiveAmountEditable = false,
_useTorOnly = false, _useTorOnly = false,
receiveCurrencies = <CryptoCurrency>[], receiveCurrencies = <CryptoCurrency>[],
depositCurrencies = <CryptoCurrency>[], depositCurrencies = <CryptoCurrency>[],
limits = Limits(min: 0, max: 0), limits = Limits(min: 0, max: 0),
tradeState = ExchangeTradeStateInitial(), tradeState = ExchangeTradeStateInitial(),
limitsState = LimitsInitialState(), limitsState = LimitsInitialState(),
receiveCurrency = wallet.currency, receiveCurrency = wallet.currency,
depositCurrency = wallet.currency, depositCurrency = wallet.currency,
providerList = [], providerList = [],
selectedProviders = ObservableList<ExchangeProvider>() { selectedProviders = ObservableList<ExchangeProvider>() {
_useTorOnly = _settingsStore.exchangeStatus == ExchangeApiMode.torOnly; _useTorOnly = _settingsStore.exchangeStatus == ExchangeApiMode.torOnly;
_setProviders(); _setProviders();
const excludeDepositCurrencies = [CryptoCurrency.btt, CryptoCurrency.nano]; const excludeDepositCurrencies = [CryptoCurrency.btt, CryptoCurrency.nano];
const excludeReceiveCurrencies = [CryptoCurrency.xlm, CryptoCurrency.xrp, const excludeReceiveCurrencies = [
CryptoCurrency.bnb, CryptoCurrency.btt, CryptoCurrency.nano]; CryptoCurrency.xlm,
CryptoCurrency.xrp,
CryptoCurrency.bnb,
CryptoCurrency.btt,
CryptoCurrency.nano
];
_initialPairBasedOnWallet(); _initialPairBasedOnWallet();
final Map<String, dynamic> exchangeProvidersSelection = json final Map<String, dynamic> exchangeProvidersSelection =
.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}") as Map<String, dynamic>; json.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}")
as Map<String, dynamic>;
/// if the provider is not in the user settings (user's first time or newly added provider) /// if the provider is not in the user settings (user's first time or newly added provider)
/// then use its default value decided by us /// then use its default value decided by us
selectedProviders = ObservableList.of(providersForCurrentPair().where( selectedProviders = ObservableList.of(providersForCurrentPair()
(element) => exchangeProvidersSelection[element.title] == null .where((element) => exchangeProvidersSelection[element.title] == null
? element.isEnabled ? element.isEnabled
: (exchangeProvidersSelection[element.title] as bool)) : (exchangeProvidersSelection[element.title] as bool))
.toList()); .toList());
@ -94,33 +100,29 @@ abstract class ExchangeViewModelBase with Store {
depositAmount = ''; depositAmount = '';
receiveAmount = ''; receiveAmount = '';
receiveAddress = ''; receiveAddress = '';
depositAddress = depositCurrency == wallet.currency depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.address : '';
? wallet.walletAddresses.address : '';
provider = providersForCurrentPair().first; provider = providersForCurrentPair().first;
final initialProvider = provider; final initialProvider = provider;
provider!.checkIsAvailable().then((bool isAvailable) { provider!.checkIsAvailable().then((bool isAvailable) {
if (!isAvailable && provider == initialProvider) { if (!isAvailable && provider == initialProvider) {
provider = providerList.firstWhere( provider = providerList.firstWhere((provider) => provider is ChangeNowExchangeProvider,
(provider) => provider is ChangeNowExchangeProvider,
orElse: () => providerList.last); orElse: () => providerList.last);
_onPairChange(); _onPairChange();
} }
}); });
receiveCurrencies = CryptoCurrency.all receiveCurrencies = CryptoCurrency.all
.where((cryptoCurrency) => !excludeReceiveCurrencies.contains(cryptoCurrency)) .where((cryptoCurrency) => !excludeReceiveCurrencies.contains(cryptoCurrency))
.toList(); .toList();
depositCurrencies = CryptoCurrency.all depositCurrencies = CryptoCurrency.all
.where((cryptoCurrency) => !excludeDepositCurrencies.contains(cryptoCurrency)) .where((cryptoCurrency) => !excludeDepositCurrencies.contains(cryptoCurrency))
.toList(); .toList();
_defineIsReceiveAmountEditable(); _defineIsReceiveAmountEditable();
loadLimits(); loadLimits();
reaction( reaction((_) => isFixedRateMode, (Object _) {
(_) => isFixedRateMode, loadLimits();
(Object _) { _bestRate = 0;
loadLimits(); _calculateBestRate();
_bestRate = 0; });
_calculateBestRate();
});
} }
bool _useTorOnly; bool _useTorOnly;
final WalletBase wallet; final WalletBase wallet;
@ -148,7 +150,7 @@ abstract class ExchangeViewModelBase with Store {
/// initialize with descending comparator /// initialize with descending comparator
/// since we want largest rate first /// since we want largest rate first
final SplayTreeMap<double, ExchangeProvider> _sortedAvailableProviders = final SplayTreeMap<double, ExchangeProvider> _sortedAvailableProviders =
SplayTreeMap<double, ExchangeProvider>((double a, double b) => b.compareTo(a)); SplayTreeMap<double, ExchangeProvider>((double a, double b) => b.compareTo(a));
final List<ExchangeProvider> _tradeAvailableProviders = []; final List<ExchangeProvider> _tradeAvailableProviders = [];
@ -204,9 +206,7 @@ abstract class ExchangeViewModelBase with Store {
SyncStatus get status => wallet.syncStatus; SyncStatus get status => wallet.syncStatus;
@computed @computed
ObservableList<ExchangeTemplate> get templates => ObservableList<ExchangeTemplate> get templates => _exchangeTemplateStore.templates;
_exchangeTemplateStore.templates;
@computed @computed
TransactionPriority get transactionPriority { TransactionPriority get transactionPriority {
@ -219,13 +219,13 @@ abstract class ExchangeViewModelBase with Store {
return priority; return priority;
} }
bool get hasAllAmount => bool get hasAllAmount =>
(wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) && depositCurrency == wallet.currency; (wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) &&
depositCurrency == wallet.currency;
bool get isMoneroWallet => wallet.type == WalletType.monero; bool get isMoneroWallet => wallet.type == WalletType.monero;
bool get isLowFee { bool get isLowFee {
switch (wallet.type) { switch (wallet.type) {
case WalletType.monero: case WalletType.monero:
case WalletType.haven: case WalletType.haven:
@ -340,20 +340,19 @@ abstract class ExchangeViewModelBase with Store {
final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1; final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1;
final _providers = _tradeAvailableProviders final _providers = _tradeAvailableProviders
.where((element) => !isFixedRateMode || element.supportsFixedRate).toList(); .where((element) => !isFixedRateMode || element.supportsFixedRate)
.toList();
final result = await Future.wait<double>( final result = await Future.wait<double>(_providers.map((element) => element.fetchRate(
_providers.map((element) => element.fetchRate( from: depositCurrency,
from: depositCurrency, to: receiveCurrency,
to: receiveCurrency, amount: amount,
amount: amount, isFixedRateMode: isFixedRateMode,
isFixedRateMode: isFixedRateMode, isReceiveAmount: isFixedRateMode)));
isReceiveAmount: isFixedRateMode))
);
_sortedAvailableProviders.clear(); _sortedAvailableProviders.clear();
for (int i=0;i<result.length;i++) { for (int i = 0; i < result.length; i++) {
if (result[i] != 0) { if (result[i] != 0) {
/// add this provider as its valid for this trade /// add this provider as its valid for this trade
try { try {
@ -377,12 +376,8 @@ abstract class ExchangeViewModelBase with Store {
limitsState = LimitsIsLoading(); limitsState = LimitsIsLoading();
final from = isFixedRateMode final from = isFixedRateMode ? receiveCurrency : depositCurrency;
? receiveCurrency final to = isFixedRateMode ? depositCurrency : receiveCurrency;
: depositCurrency;
final to = isFixedRateMode
? depositCurrency
: receiveCurrency;
double? lowestMin = double.maxFinite; double? lowestMin = double.maxFinite;
double? highestMax = 0.0; double? highestMax = 0.0;
@ -395,10 +390,8 @@ abstract class ExchangeViewModelBase with Store {
} }
try { try {
final tempLimits = await provider.fetchLimits( final tempLimits =
from: from, await provider.fetchLimits(from: from, to: to, isFixedRateMode: isFixedRateMode);
to: to,
isFixedRateMode: isFixedRateMode);
if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) { if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) {
lowestMin = tempLimits.min; lowestMin = tempLimits.min;
@ -519,12 +512,13 @@ abstract class ExchangeViewModelBase with Store {
} else { } else {
try { try {
tradeState = TradeIsCreating(); tradeState = TradeIsCreating();
final trade = await provider.createTrade( final trade =
request: request!, isFixedRateMode: isFixedRateMode); await provider.createTrade(request: request!, isFixedRateMode: isFixedRateMode);
trade.walletId = wallet.id; trade.walletId = wallet.id;
tradesStore.setTrade(trade); tradesStore.setTrade(trade);
await trades.add(trade); await trades.add(trade);
tradeState = TradeIsCreatedSuccessfully(trade: trade); tradeState = TradeIsCreatedSuccessfully(trade: trade);
/// return after the first successful trade /// return after the first successful trade
return; return;
} catch (e) { } catch (e) {
@ -554,10 +548,8 @@ abstract class ExchangeViewModelBase with Store {
isReceiveAmountEntered = false; isReceiveAmountEntered = false;
depositAmount = ''; depositAmount = '';
receiveAmount = ''; receiveAmount = '';
depositAddress = depositCurrency == wallet.currency depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.address : '';
? wallet.walletAddresses.address : ''; receiveAddress = receiveCurrency == wallet.currency ? wallet.walletAddresses.address : '';
receiveAddress = receiveCurrency == wallet.currency
? wallet.walletAddresses.address : '';
isDepositAddressEnabled = !(depositCurrency == wallet.currency); isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency); isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
isFixedRateMode = false; isFixedRateMode = false;
@ -611,10 +603,8 @@ abstract class ExchangeViewModelBase with Store {
List<ExchangeProvider> _providersForPair( List<ExchangeProvider> _providersForPair(
{required CryptoCurrency from, required CryptoCurrency to}) { {required CryptoCurrency from, required CryptoCurrency to}) {
final providers = providerList final providers = providerList
.where((provider) => provider.pairList .where((provider) =>
.where((pair) => provider.pairList.where((pair) => pair.from == from && pair.to == to).isNotEmpty)
pair.from == from && pair.to == to)
.isNotEmpty)
.toList(); .toList();
return providers; return providers;
@ -651,6 +641,10 @@ abstract class ExchangeViewModelBase with Store {
depositCurrency = CryptoCurrency.eth; depositCurrency = CryptoCurrency.eth;
receiveCurrency = CryptoCurrency.xmr; receiveCurrency = CryptoCurrency.xmr;
break; break;
case WalletType.nano:
depositCurrency = CryptoCurrency.nano;
receiveCurrency = CryptoCurrency.xmr;
break;
default: default:
break; break;
} }
@ -694,8 +688,9 @@ abstract class ExchangeViewModelBase with Store {
_bestRate = 0; _bestRate = 0;
_calculateBestRate(); _calculateBestRate();
final Map<String, dynamic> exchangeProvidersSelection = json final Map<String, dynamic> exchangeProvidersSelection =
.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}") as Map<String, dynamic>; json.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}")
as Map<String, dynamic>;
for (var provider in providerList) { for (var provider in providerList) {
exchangeProvidersSelection[provider.title] = selectedProviders.contains(provider); exchangeProvidersSelection[provider.title] = selectedProviders.contains(provider);
@ -709,15 +704,15 @@ abstract class ExchangeViewModelBase with Store {
bool get isAvailableInSelected { bool get isAvailableInSelected {
final providersForPair = providersForCurrentPair(); final providersForPair = providersForCurrentPair();
return selectedProviders.any((element) => element.isAvailable && providersForPair.contains(element)); return selectedProviders
.any((element) => element.isAvailable && providersForPair.contains(element));
} }
void _setAvailableProviders() { void _setAvailableProviders() {
_tradeAvailableProviders.clear(); _tradeAvailableProviders.clear();
_tradeAvailableProviders.addAll( _tradeAvailableProviders.addAll(
selectedProviders selectedProviders.where((provider) => providersForCurrentPair().contains(provider)));
.where((provider) => providersForCurrentPair().contains(provider)));
} }
@action @action
@ -738,7 +733,7 @@ abstract class ExchangeViewModelBase with Store {
} }
} }
void _setProviders(){ void _setProviders() {
if (_settingsStore.exchangeStatus == ExchangeApiMode.torOnly) { if (_settingsStore.exchangeStatus == ExchangeApiMode.torOnly) {
providerList = _allProviders.where((provider) => provider.supportsOnionAddress).toList(); providerList = _allProviders.where((provider) => provider.supportsOnionAddress).toList();
} else { } else {