2022-10-20 17:47:36 +00:00
|
|
|
import 'dart:async';
|
2022-09-01 14:12:38 +00:00
|
|
|
import 'dart:collection';
|
|
|
|
import 'dart:convert';
|
|
|
|
|
2024-03-28 12:41:11 +00:00
|
|
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
2024-04-25 01:14:11 +00:00
|
|
|
import 'package:cake_wallet/core/create_trade_result.dart';
|
|
|
|
import 'package:cw_core/crypto_currency.dart';
|
|
|
|
import 'package:cw_core/sync_status.dart';
|
|
|
|
import 'package:cw_core/transaction_priority.dart';
|
|
|
|
import 'package:cw_core/wallet_type.dart';
|
|
|
|
import 'package:hive/hive.dart';
|
|
|
|
import 'package:http/http.dart' as http;
|
|
|
|
import 'package:intl/intl.dart';
|
|
|
|
import 'package:mobx/mobx.dart';
|
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
|
|
|
|
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
2023-10-25 20:58:25 +00:00
|
|
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
2024-04-25 01:14:11 +00:00
|
|
|
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
2023-09-01 15:06:18 +00:00
|
|
|
import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
|
2023-03-02 15:13:25 +00:00
|
|
|
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
2022-09-01 14:12:38 +00:00
|
|
|
import 'package:cake_wallet/entities/preferences_key.dart';
|
2023-08-04 13:49:26 +00:00
|
|
|
import 'package:cake_wallet/entities/wallet_contact.dart';
|
2023-10-12 22:50:16 +00:00
|
|
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
2024-03-28 12:41:11 +00:00
|
|
|
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
2023-10-25 20:58:25 +00:00
|
|
|
import 'package:cake_wallet/exchange/exchange_template.dart';
|
|
|
|
import 'package:cake_wallet/exchange/exchange_trade_state.dart';
|
2020-09-21 11:50:26 +00:00
|
|
|
import 'package:cake_wallet/exchange/limits.dart';
|
|
|
|
import 'package:cake_wallet/exchange/limits_state.dart';
|
2023-10-25 20:58:25 +00:00
|
|
|
import 'package:cake_wallet/exchange/provider/changenow_exchange_provider.dart';
|
|
|
|
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
|
|
|
|
import 'package:cake_wallet/exchange/provider/exolix_exchange_provider.dart';
|
2024-05-14 02:07:16 +00:00
|
|
|
import 'package:cake_wallet/exchange/provider/quantex_exchange_provider.dart';
|
2023-10-25 20:58:25 +00:00
|
|
|
import 'package:cake_wallet/exchange/provider/sideshift_exchange_provider.dart';
|
|
|
|
import 'package:cake_wallet/exchange/provider/simpleswap_exchange_provider.dart';
|
2024-03-28 12:41:11 +00:00
|
|
|
import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart';
|
2023-10-25 20:58:25 +00:00
|
|
|
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
|
|
|
import 'package:cake_wallet/exchange/trade.dart';
|
|
|
|
import 'package:cake_wallet/exchange/trade_request.dart';
|
|
|
|
import 'package:cake_wallet/generated/i18n.dart';
|
|
|
|
import 'package:cake_wallet/monero/monero.dart';
|
2023-12-02 02:26:43 +00:00
|
|
|
import 'package:cake_wallet/polygon/polygon.dart';
|
2023-10-25 20:58:25 +00:00
|
|
|
import 'package:cake_wallet/store/app_store.dart';
|
2020-08-26 17:31:23 +00:00
|
|
|
import 'package:cake_wallet/store/dashboard/trades_store.dart';
|
2021-01-05 18:31:03 +00:00
|
|
|
import 'package:cake_wallet/store/settings_store.dart';
|
2023-10-25 20:58:25 +00:00
|
|
|
import 'package:cake_wallet/store/templates/exchange_template_store.dart';
|
2023-10-13 11:49:00 +00:00
|
|
|
import 'package:cake_wallet/utils/feature_flag.dart';
|
2023-08-04 13:49:26 +00:00
|
|
|
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
|
2020-07-31 15:29:21 +00:00
|
|
|
|
|
|
|
part 'exchange_view_model.g.dart';
|
|
|
|
|
|
|
|
class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel;
|
|
|
|
|
2023-09-01 15:06:18 +00:00
|
|
|
abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with Store {
|
|
|
|
@override
|
|
|
|
void onWalletChange(wallet) {
|
|
|
|
receiveCurrency = wallet.currency;
|
|
|
|
depositCurrency = wallet.currency;
|
|
|
|
}
|
|
|
|
|
2023-08-04 13:49:26 +00:00
|
|
|
ExchangeViewModelBase(
|
2023-09-01 15:06:18 +00:00
|
|
|
AppStore appStore,
|
|
|
|
this.trades,
|
|
|
|
this._exchangeTemplateStore,
|
|
|
|
this.tradesStore,
|
|
|
|
this._settingsStore,
|
|
|
|
this.sharedPreferences,
|
|
|
|
this.contactListViewModel,
|
|
|
|
) : _cryptoNumberFormat = NumberFormat(),
|
2024-03-21 02:51:57 +00:00
|
|
|
isSendAllEnabled = false,
|
2023-08-04 13:49:26 +00:00
|
|
|
isFixedRateMode = false,
|
|
|
|
isReceiveAmountEntered = false,
|
|
|
|
depositAmount = '',
|
|
|
|
receiveAmount = '',
|
|
|
|
receiveAddress = '',
|
|
|
|
depositAddress = '',
|
|
|
|
isDepositAddressEnabled = false,
|
|
|
|
isReceiveAmountEditable = false,
|
|
|
|
_useTorOnly = false,
|
|
|
|
receiveCurrencies = <CryptoCurrency>[],
|
|
|
|
depositCurrencies = <CryptoCurrency>[],
|
|
|
|
limits = Limits(min: 0, max: 0),
|
|
|
|
tradeState = ExchangeTradeStateInitial(),
|
|
|
|
limitsState = LimitsInitialState(),
|
2023-09-01 15:06:18 +00:00
|
|
|
receiveCurrency = appStore.wallet!.currency,
|
|
|
|
depositCurrency = appStore.wallet!.currency,
|
2023-08-04 13:49:26 +00:00
|
|
|
providerList = [],
|
2023-09-01 15:06:18 +00:00
|
|
|
selectedProviders = ObservableList<ExchangeProvider>(),
|
|
|
|
super(appStore: appStore) {
|
2023-03-02 15:13:25 +00:00
|
|
|
_useTorOnly = _settingsStore.exchangeStatus == ExchangeApiMode.torOnly;
|
2023-03-01 13:50:31 +00:00
|
|
|
_setProviders();
|
2023-10-05 01:09:07 +00:00
|
|
|
const excludeDepositCurrencies = [CryptoCurrency.btt];
|
2023-08-04 13:49:26 +00:00
|
|
|
const excludeReceiveCurrencies = [
|
|
|
|
CryptoCurrency.xlm,
|
|
|
|
CryptoCurrency.xrp,
|
|
|
|
CryptoCurrency.bnb,
|
2023-10-05 01:09:07 +00:00
|
|
|
CryptoCurrency.btt
|
2023-08-04 13:49:26 +00:00
|
|
|
];
|
2022-09-01 18:46:14 +00:00
|
|
|
_initialPairBasedOnWallet();
|
2022-10-20 17:47:36 +00:00
|
|
|
|
2023-09-01 15:06:18 +00:00
|
|
|
final Map<String, dynamic> exchangeProvidersSelection =
|
|
|
|
json.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}")
|
|
|
|
as Map<String, dynamic>;
|
2022-09-01 14:12:38 +00:00
|
|
|
|
|
|
|
/// 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
|
2024-03-28 12:41:11 +00:00
|
|
|
selectedProviders = ObservableList.of(providerList
|
2023-08-04 13:49:26 +00:00
|
|
|
.where((element) => exchangeProvidersSelection[element.title] == null
|
2022-09-01 14:12:38 +00:00
|
|
|
? element.isEnabled
|
|
|
|
: (exchangeProvidersSelection[element.title] as bool))
|
|
|
|
.toList());
|
|
|
|
|
2022-10-20 17:47:36 +00:00
|
|
|
_setAvailableProviders();
|
|
|
|
_calculateBestRate();
|
|
|
|
|
2023-09-01 15:06:18 +00:00
|
|
|
bestRateSync = Timer.periodic(Duration(seconds: 10), (timer) => _calculateBestRate());
|
2022-10-20 17:47:36 +00:00
|
|
|
|
2020-07-31 15:29:21 +00:00
|
|
|
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
|
|
|
depositAmount = '';
|
|
|
|
receiveAmount = '';
|
|
|
|
receiveAddress = '';
|
2023-09-01 15:06:18 +00:00
|
|
|
depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.address : '';
|
2020-09-02 08:47:41 +00:00
|
|
|
provider = providersForCurrentPair().first;
|
2020-11-10 14:58:40 +00:00
|
|
|
final initialProvider = provider;
|
2022-10-12 17:09:57 +00:00
|
|
|
provider!.checkIsAvailable().then((bool isAvailable) {
|
2020-11-10 14:58:40 +00:00
|
|
|
if (!isAvailable && provider == initialProvider) {
|
2023-09-01 15:06:18 +00:00
|
|
|
provider = providerList.firstWhere((provider) => provider is ChangeNowExchangeProvider,
|
2020-11-10 14:58:40 +00:00
|
|
|
orElse: () => providerList.last);
|
|
|
|
_onPairChange();
|
|
|
|
}
|
|
|
|
});
|
2021-05-07 07:36:38 +00:00
|
|
|
receiveCurrencies = CryptoCurrency.all
|
2023-09-01 15:06:18 +00:00
|
|
|
.where((cryptoCurrency) => !excludeReceiveCurrencies.contains(cryptoCurrency))
|
2023-08-04 13:49:26 +00:00
|
|
|
.toList();
|
2022-04-01 13:31:05 +00:00
|
|
|
depositCurrencies = CryptoCurrency.all
|
2023-09-01 15:06:18 +00:00
|
|
|
.where((cryptoCurrency) => !excludeDepositCurrencies.contains(cryptoCurrency))
|
2023-08-04 13:49:26 +00:00
|
|
|
.toList();
|
2022-01-26 15:44:15 +00:00
|
|
|
_defineIsReceiveAmountEditable();
|
2020-07-31 15:29:21 +00:00
|
|
|
loadLimits();
|
2023-08-04 13:49:26 +00:00
|
|
|
reaction((_) => isFixedRateMode, (Object _) {
|
|
|
|
loadLimits();
|
|
|
|
_bestRate = 0;
|
|
|
|
_calculateBestRate();
|
|
|
|
});
|
2020-07-31 15:29:21 +00:00
|
|
|
}
|
2023-10-25 20:58:25 +00:00
|
|
|
|
2023-03-02 15:13:25 +00:00
|
|
|
bool _useTorOnly;
|
2020-07-31 15:29:21 +00:00
|
|
|
final Box<Trade> trades;
|
2020-10-07 05:58:22 +00:00
|
|
|
final ExchangeTemplateStore _exchangeTemplateStore;
|
2020-08-26 17:31:23 +00:00
|
|
|
final TradesStore tradesStore;
|
2022-09-01 14:12:38 +00:00
|
|
|
final SharedPreferences sharedPreferences;
|
2020-07-31 15:29:21 +00:00
|
|
|
|
2023-03-01 21:44:15 +00:00
|
|
|
List<ExchangeProvider> get _allProviders => [
|
2023-07-08 02:30:05 +00:00
|
|
|
ChangeNowExchangeProvider(settingsStore: _settingsStore),
|
2023-03-01 13:50:31 +00:00
|
|
|
SideShiftExchangeProvider(),
|
|
|
|
SimpleSwapExchangeProvider(),
|
2024-03-28 12:41:11 +00:00
|
|
|
ThorChainExchangeProvider(tradesStore: trades),
|
2023-10-13 11:49:00 +00:00
|
|
|
if (FeatureFlag.isExolixEnabled) ExolixExchangeProvider(),
|
2024-05-14 02:07:16 +00:00
|
|
|
QuantexExchangeProvider(),
|
2024-05-23 16:43:05 +00:00
|
|
|
TrocadorExchangeProvider(
|
|
|
|
useTorOnly: _useTorOnly, providerStates: _settingsStore.trocadorProviderStates),
|
2023-03-01 13:50:31 +00:00
|
|
|
];
|
|
|
|
|
2020-07-31 15:29:21 +00:00
|
|
|
@observable
|
2022-10-12 17:09:57 +00:00
|
|
|
ExchangeProvider? provider;
|
2020-07-31 15:29:21 +00:00
|
|
|
|
2022-09-01 14:12:38 +00:00
|
|
|
/// Maps in dart are not sorted by default
|
|
|
|
/// SplayTreeMap is a map sorted by keys
|
|
|
|
/// will use it to sort available providers
|
2022-10-20 17:47:36 +00:00
|
|
|
/// based on the rate they yield for the current trade
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// initialize with descending comparator
|
|
|
|
/// since we want largest rate first
|
|
|
|
final SplayTreeMap<double, ExchangeProvider> _sortedAvailableProviders =
|
2023-09-01 15:06:18 +00:00
|
|
|
SplayTreeMap<double, ExchangeProvider>((double a, double b) => b.compareTo(a));
|
2022-10-20 17:47:36 +00:00
|
|
|
|
|
|
|
final List<ExchangeProvider> _tradeAvailableProviders = [];
|
2022-09-01 14:12:38 +00:00
|
|
|
|
|
|
|
@observable
|
|
|
|
ObservableList<ExchangeProvider> selectedProviders;
|
|
|
|
|
2020-07-31 15:29:21 +00:00
|
|
|
@observable
|
|
|
|
List<ExchangeProvider> providerList;
|
|
|
|
|
|
|
|
@observable
|
|
|
|
CryptoCurrency depositCurrency;
|
|
|
|
|
|
|
|
@observable
|
|
|
|
CryptoCurrency receiveCurrency;
|
|
|
|
|
|
|
|
@observable
|
|
|
|
LimitsState limitsState;
|
|
|
|
|
|
|
|
@observable
|
|
|
|
ExchangeTradeState tradeState;
|
|
|
|
|
|
|
|
@observable
|
|
|
|
String depositAmount;
|
|
|
|
|
|
|
|
@observable
|
|
|
|
String receiveAmount;
|
|
|
|
|
|
|
|
@observable
|
|
|
|
String depositAddress;
|
|
|
|
|
|
|
|
@observable
|
|
|
|
String receiveAddress;
|
|
|
|
|
|
|
|
@observable
|
|
|
|
bool isDepositAddressEnabled;
|
|
|
|
|
2020-10-12 16:47:01 +00:00
|
|
|
@observable
|
2020-09-25 19:55:41 +00:00
|
|
|
bool isReceiveAmountEntered;
|
|
|
|
|
2021-02-16 19:06:23 +00:00
|
|
|
@observable
|
|
|
|
bool isReceiveAmountEditable;
|
|
|
|
|
|
|
|
@observable
|
|
|
|
bool isFixedRateMode;
|
|
|
|
|
2024-03-21 02:51:57 +00:00
|
|
|
@observable
|
|
|
|
bool isSendAllEnabled;
|
|
|
|
|
2023-04-20 01:13:37 +00:00
|
|
|
@observable
|
|
|
|
Limits limits;
|
|
|
|
|
2020-11-02 11:33:45 +00:00
|
|
|
@computed
|
|
|
|
SyncStatus get status => wallet.syncStatus;
|
|
|
|
|
2020-07-31 15:29:21 +00:00
|
|
|
@computed
|
2023-09-01 15:06:18 +00:00
|
|
|
ObservableList<ExchangeTemplate> get templates => _exchangeTemplateStore.templates;
|
2020-07-31 15:29:21 +00:00
|
|
|
|
2023-08-04 13:49:26 +00:00
|
|
|
@computed
|
2023-09-01 15:06:18 +00:00
|
|
|
List<WalletContact> get walletContactsToShow => contactListViewModel.walletContacts
|
2023-09-14 19:14:16 +00:00
|
|
|
.where((element) => element.type == receiveCurrency)
|
2023-09-01 15:06:18 +00:00
|
|
|
.toList();
|
2023-08-04 13:49:26 +00:00
|
|
|
|
|
|
|
@action
|
|
|
|
bool checkIfWalletIsAnInternalWallet(String address) {
|
2023-09-01 15:06:18 +00:00
|
|
|
final walletContactList =
|
|
|
|
walletContactsToShow.where((element) => element.address == address).toList();
|
2023-08-04 13:49:26 +00:00
|
|
|
|
|
|
|
return walletContactList.isNotEmpty;
|
|
|
|
}
|
|
|
|
|
|
|
|
@computed
|
|
|
|
bool get shouldDisplayTOTP2FAForExchangesToInternalWallet =>
|
|
|
|
_settingsStore.shouldRequireTOTP2FAForExchangesToInternalWallets;
|
|
|
|
|
2023-11-02 18:17:52 +00:00
|
|
|
@computed
|
|
|
|
bool get shouldDisplayTOTP2FAForExchangesToExternalWallet =>
|
|
|
|
_settingsStore.shouldRequireTOTP2FAForExchangesToExternalWallets;
|
|
|
|
|
2023-08-04 13:49:26 +00:00
|
|
|
//* Still open to further optimize these checks
|
|
|
|
//* It works but can be made better
|
|
|
|
@action
|
|
|
|
bool shouldDisplayTOTP() {
|
|
|
|
final isInternalWallet = checkIfWalletIsAnInternalWallet(receiveAddress);
|
2023-11-02 18:17:52 +00:00
|
|
|
|
2023-08-04 13:49:26 +00:00
|
|
|
if (isInternalWallet) {
|
|
|
|
return shouldDisplayTOTP2FAForExchangesToInternalWallet;
|
2023-11-02 18:17:52 +00:00
|
|
|
} else {
|
|
|
|
return shouldDisplayTOTP2FAForExchangesToExternalWallet;
|
2023-08-04 13:49:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-25 20:51:07 +00:00
|
|
|
@computed
|
|
|
|
TransactionPriority get transactionPriority {
|
|
|
|
final priority = _settingsStore.priority[wallet.type];
|
|
|
|
|
|
|
|
if (priority == null) {
|
|
|
|
throw Exception('Unexpected type ${wallet.type.toString()}');
|
|
|
|
}
|
|
|
|
|
|
|
|
return priority;
|
|
|
|
}
|
|
|
|
|
2021-01-05 18:31:03 +00:00
|
|
|
bool get hasAllAmount =>
|
2023-10-12 22:50:16 +00:00
|
|
|
(wallet.type == WalletType.bitcoin ||
|
|
|
|
wallet.type == WalletType.litecoin ||
|
|
|
|
wallet.type == WalletType.bitcoinCash) &&
|
2023-09-01 15:06:18 +00:00
|
|
|
depositCurrency == wallet.currency;
|
2021-01-05 18:31:03 +00:00
|
|
|
|
2023-08-04 13:49:26 +00:00
|
|
|
bool get isMoneroWallet => wallet.type == WalletType.monero;
|
2021-07-23 11:05:33 +00:00
|
|
|
|
2023-08-04 13:49:26 +00:00
|
|
|
bool get isLowFee {
|
2022-11-03 19:21:35 +00:00
|
|
|
switch (wallet.type) {
|
|
|
|
case WalletType.monero:
|
Wownero (#1485)
* fix: scanning issues
* fix: sync, storing silent unspents
* chore: deps
* fix: label issues, clear spent utxo
* chore: deps
* fix: build
* fix: missing types
* feat: new electrs API & changes, fixes for last block scanning
* feat: Scan Silent Payments homepage toggle
* chore: build configure
* feat: generic fixes, testnet UI improvements, useSSL on bitcoin nodes
* fix: invalid Object in sendData
* feat: improve addresses page & address book displays
* feat: silent payments labeled addresses disclaimer
* fix: missing i18n
* chore: print
* feat: single block scan, rescan by date working for btc mainnet
* feat: new cake features page replace market page, move sp scan toggle, auto switch node pop up alert
* feat: delete silent addresses
* fix: red dot in non ssl nodes
* fix: inconsistent connection states, fix tx history
* fix: tx & balance displays, cpfp sending
* feat: new rust lib
* chore: node path
* fix: check node based on network
* fix: missing txcount from addresses
* style: padding in feature page cards
* fix: restore not getting all wallet addresses by type
* fix: auto switch node broken
* fix: silent payment txs not being restored
* feat: change scanning to subscription model, sync improvements
* fix: scan re-subscription
* fix: default nodes
* fix: improve scanning by date, fix single block scan
* refactor: common function for input tx selection
* various fixes for build issues
* initial monero.dart implementation
* ...
* multiple wallets
new lib
minor fixes
* other fixes from monero.dart and monero_c
* fix: nodes & build
* update build scripts
fix polyseed
* remove unnecessary code
* Add windows app, build scripts and build guide for it.
* Minor fix in generated monero configs
* fix: send all with multiple outs
* add missing monero_c command
* add android build script
* Merge and fix main
* undo android ndk removal
* Fix modified exception_handler.dart
* Temporarily remove haven
* fix build issues
* fix pr script
* Fixes for build monero.dart (monero_c) for windows.
* monero build script
* wip: ios build script
* refactor: unchanged file
* Added build guides for iOS and macOS. Replaced nproc call on macOS. Added macOS configuration for configure_cake_wallet.sh script.
* Update monero.dart and monero_c versions.
* Add missed windows build scripts
* Update the application configuration for windows build script.
* Update cw_monero pubspec lock file for monero.dart
* Update pr_test_build.yml
* chore: upgrade
* chore: merge changes
* refactor: unchanged files [skip ci]
* Fix conflicts with main
* fix for multiple wallets
* Add tron to windows application configuration.
* Add macOS option for description message in configure_cake_wallet.sh
* Include missed monero dll for windows.
* fix conflicts with main
* Disable haven configuration for iOS as default. Add ability to configure cakewallet for iOS with for configuration script. Remove cw_shared configuration for cw_monero.
* fix: scan fixes, add date, allow sending while scanning
* add missing nano secrets file [skip ci]
* ios library
* don't pull prebuilds android
* Add auto generation of manifest file for android project even for iOS, macOS, Windows.
* feat: sync fixes, sp settings
* feat: fix resyncing
* store crash fix
* make init async so it won't lag
disable print starts
* fix monero_c build issues
* libstdc++
* Fix MacOS saving wallet file issue
Fix Secure Storage issue (somehow)
* update pubspec.lock
* fix build script
* Use dylib as iOS framework. Use custom path for loading of iOS framework for monero.dart. Add script for generate iOS framework for monero wallet.
* fix: date from height logic, status disconnected & chain tip get
* fix: params
* feat: electrum migration if using cake electrum
* fix nodes
update versions
* re-enable tron
* update sp_scanner to work on iOS [skip ci]
* bump monero_c hash
* bump monero_c commit
* bump moneroc version
* bump monero_c commit
* Add ability to build monero wallet lib as universal lib. Update macOS build guide. Change default arch for macOS project to .
* fix: wrong socket for old electrum nodes
* Fix unchecked wallet type call
* get App Dir correctly in default_settings_migration.dart
* handle previous issue with fetching linux documents directory [skip ci]
* backup fix
* fix NTFS issues
* Close the wallet when the wallet gets changed
* fix: double balance
* feat: node domain
* fix: menu name
* bump monero_c commit
* fix: update tip on set scanning
* fix: connection switching back and forth
* feat: check if node is electrs, and supports sp
* chore: fix build
* minor enhancements
* fixes and enhancements
* solve conflicts with main
* Only stop wallet on rename and delete
* fix: status toggle
* minor enhancement
* Monero.com fixes
* bump monero_c commit
* update sp_scanner to include windows and linux
* Update macOS build guide. Change brew dependencies for build unbound locally.
* fix conflicts and update macos build guide
* remove build cache when on gh actions
* update secure storage
* free up even more storage
* free up more storage
* Add initial wownero
* fix conflicts
* fix workflow issue
* build wownero
* ios and windows changes
* macos
* complete wownero flow (app side)
* add keychain group entitlement and update script for RunnerBase on macos
* update secure_storage version to 8.1.0 in configure.dart
* add wownero framework
* update ios builds
* proper path for wownero and monero
* finalizing wownero
* finalizing wownero
* free up even more storage
* revert commenting of build gradle configs
* revert commenting of secrets [skip ci]
* free more storage
* minor fixes
* link android wownero libraries
* bump monero_c commit
* wownero fixes
* rename target
* build_single.sh using clean env
* bump monero_c commit
* minor fix
* Add wownero polyseed
* fix conflicts with main
* fix: wallet seed display
fix: wownero not refreshing
* fix: wallet seed display
fix: wownero not refreshing
* bump monero_c commit
* minor fixes
* fix: incorrectly displaying XMR instead of WOW
* fix: incorrect restore height in wownero
* bump monero_c commit
* Add Inno Setup Script for windows exe installer
* drop libc++_shared.so
* fixes from comments
* Fix CMake for windows
* Merge latest monero dart changes [skip ci]
* bump monero_c commit
* add wownero to build scripts for macos [skip ci]
* add 14 word seed support to wownero
* UI fixes for wownero seed restore
* minor fixes
* reformat code to pass lints
* wownero: fixes
haven: removal popup
* minor iOS fix [skip ci]
* fix: wownero confirmation count (it is spendable after 3 confirms)
fix: transaction history not displaying in WOW and XMR
when tx has 0 confirms,
This is more of a workaround, because I have no idea
why would the cpp code not return pending transaction.
* Update preferences_key.dart [skip ci]
* minor fixes
---------
Co-authored-by: Rafael Saes <git@rafael.saes.dev>
Co-authored-by: Czarek Nakamoto <cyjan@mrcyjanek.net>
Co-authored-by: M <m@cakewallet.com>
Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com>
Co-authored-by: Matthew Fosse <matt@fosse.co>
2024-07-04 19:43:17 +00:00
|
|
|
case WalletType.wownero:
|
2022-11-03 19:21:35 +00:00
|
|
|
case WalletType.haven:
|
2023-09-01 15:06:18 +00:00
|
|
|
return transactionPriority == monero!.getMoneroTransactionPrioritySlow();
|
2022-11-03 19:21:35 +00:00
|
|
|
case WalletType.bitcoin:
|
2023-09-01 15:06:18 +00:00
|
|
|
return transactionPriority == bitcoin!.getBitcoinTransactionPrioritySlow();
|
2022-11-03 19:21:35 +00:00
|
|
|
case WalletType.litecoin:
|
2023-09-01 15:06:18 +00:00
|
|
|
return transactionPriority == bitcoin!.getLitecoinTransactionPrioritySlow();
|
2023-10-12 22:50:16 +00:00
|
|
|
case WalletType.ethereum:
|
2023-11-02 18:17:52 +00:00
|
|
|
return transactionPriority == ethereum!.getEthereumTransactionPrioritySlow();
|
2023-10-12 22:50:16 +00:00
|
|
|
case WalletType.bitcoinCash:
|
2023-11-02 18:17:52 +00:00
|
|
|
return transactionPriority == bitcoinCash!.getBitcoinCashTransactionPrioritySlow();
|
2023-12-02 02:26:43 +00:00
|
|
|
case WalletType.polygon:
|
|
|
|
return transactionPriority == polygon!.getPolygonTransactionPrioritySlow();
|
2023-10-15 13:36:05 +00:00
|
|
|
case WalletType.zano:
|
|
|
|
return transactionPriority == monero!.getMoneroTransactionPrioritySlow();
|
2022-11-03 19:21:35 +00:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-06 17:11:26 +00:00
|
|
|
List<CryptoCurrency> receiveCurrencies;
|
|
|
|
|
2022-04-01 13:31:05 +00:00
|
|
|
List<CryptoCurrency> depositCurrencies;
|
|
|
|
|
2023-05-10 13:58:31 +00:00
|
|
|
final NumberFormat _cryptoNumberFormat;
|
2021-01-05 18:31:03 +00:00
|
|
|
|
2022-09-01 14:12:38 +00:00
|
|
|
final SettingsStore _settingsStore;
|
2020-07-31 15:29:21 +00:00
|
|
|
|
2023-08-04 13:49:26 +00:00
|
|
|
final ContactListViewModel contactListViewModel;
|
|
|
|
|
2022-10-20 17:47:36 +00:00
|
|
|
double _bestRate = 0.0;
|
|
|
|
|
|
|
|
late Timer bestRateSync;
|
|
|
|
|
2020-07-31 15:29:21 +00:00
|
|
|
@action
|
2022-10-12 17:09:57 +00:00
|
|
|
void changeDepositCurrency({required CryptoCurrency currency}) {
|
2020-07-31 15:29:21 +00:00
|
|
|
depositCurrency = currency;
|
2021-02-18 19:08:52 +00:00
|
|
|
isFixedRateMode = false;
|
2020-07-31 15:29:21 +00:00
|
|
|
_onPairChange();
|
|
|
|
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
2022-10-12 17:09:57 +00:00
|
|
|
void changeReceiveCurrency({required CryptoCurrency currency}) {
|
2020-07-31 15:29:21 +00:00
|
|
|
receiveCurrency = currency;
|
2021-02-18 19:08:52 +00:00
|
|
|
isFixedRateMode = false;
|
2020-07-31 15:29:21 +00:00
|
|
|
_onPairChange();
|
|
|
|
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
2022-10-20 17:47:36 +00:00
|
|
|
Future<void> changeReceiveAmount({required String amount}) async {
|
2020-07-31 15:29:21 +00:00
|
|
|
receiveAmount = amount;
|
|
|
|
|
2022-10-20 17:47:36 +00:00
|
|
|
if (amount.isEmpty) {
|
2020-07-31 15:29:21 +00:00
|
|
|
depositAmount = '';
|
|
|
|
receiveAmount = '';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-10-20 17:47:36 +00:00
|
|
|
final _enteredAmount = double.tryParse(amount.replaceAll(',', '.')) ?? 0;
|
2022-09-01 14:12:38 +00:00
|
|
|
|
2022-10-20 17:47:36 +00:00
|
|
|
if (_bestRate == 0) {
|
|
|
|
depositAmount = S.current.fetching;
|
|
|
|
|
|
|
|
await _calculateBestRate();
|
2022-09-01 14:12:38 +00:00
|
|
|
}
|
2023-03-31 09:45:54 +00:00
|
|
|
_cryptoNumberFormat.maximumFractionDigits = depositMaxDigits;
|
2022-10-20 17:47:36 +00:00
|
|
|
|
|
|
|
depositAmount = _cryptoNumberFormat
|
|
|
|
.format(_enteredAmount / _bestRate)
|
|
|
|
.toString()
|
|
|
|
.replaceAll(RegExp('\\,'), '');
|
2020-07-31 15:29:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
2022-10-20 17:47:36 +00:00
|
|
|
Future<void> changeDepositAmount({required String amount}) async {
|
2020-07-31 15:29:21 +00:00
|
|
|
depositAmount = amount;
|
|
|
|
|
2022-10-20 17:47:36 +00:00
|
|
|
if (amount.isEmpty) {
|
2020-07-31 15:29:21 +00:00
|
|
|
depositAmount = '';
|
|
|
|
receiveAmount = '';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-09-01 14:12:38 +00:00
|
|
|
final _enteredAmount = double.tryParse(amount.replaceAll(',', '.')) ?? 0;
|
|
|
|
|
2022-10-20 17:47:36 +00:00
|
|
|
/// in case the best rate was not calculated yet
|
|
|
|
if (_bestRate == 0) {
|
|
|
|
receiveAmount = S.current.fetching;
|
|
|
|
|
|
|
|
await _calculateBestRate();
|
|
|
|
}
|
2023-03-31 09:45:54 +00:00
|
|
|
_cryptoNumberFormat.maximumFractionDigits = receiveMaxDigits;
|
2022-10-20 17:47:36 +00:00
|
|
|
|
|
|
|
receiveAmount = _cryptoNumberFormat
|
|
|
|
.format(_bestRate * _enteredAmount)
|
|
|
|
.toString()
|
|
|
|
.replaceAll(RegExp('\\,'), '');
|
|
|
|
}
|
|
|
|
|
2023-04-20 01:13:37 +00:00
|
|
|
bool checkIfInputMeetsMinOrMaxCondition(String input) {
|
|
|
|
final _enteredAmount = double.tryParse(input.replaceAll(',', '.')) ?? 0;
|
|
|
|
double minLimit = limits.min ?? 0;
|
|
|
|
double? maxLimit = limits.max;
|
|
|
|
|
2023-10-25 20:58:25 +00:00
|
|
|
if (_enteredAmount < minLimit) return false;
|
2023-04-20 01:13:37 +00:00
|
|
|
|
2023-10-25 20:58:25 +00:00
|
|
|
if (maxLimit != null && _enteredAmount > maxLimit) return false;
|
2023-04-20 01:13:37 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-10-20 17:47:36 +00:00
|
|
|
Future<void> _calculateBestRate() async {
|
2023-09-01 15:06:18 +00:00
|
|
|
final amount = double.tryParse(isFixedRateMode ? receiveAmount : depositAmount) ?? 1;
|
2022-12-01 20:11:51 +00:00
|
|
|
|
2023-02-07 21:48:10 +00:00
|
|
|
final _providers = _tradeAvailableProviders
|
2023-08-04 13:49:26 +00:00
|
|
|
.where((element) => !isFixedRateMode || element.supportsFixedRate)
|
|
|
|
.toList();
|
|
|
|
|
2024-07-20 23:26:05 +00:00
|
|
|
final result = await Future.wait<double>(
|
|
|
|
_providers.map(
|
|
|
|
(element) => element
|
|
|
|
.fetchRate(
|
|
|
|
from: depositCurrency,
|
|
|
|
to: receiveCurrency,
|
|
|
|
amount: amount,
|
|
|
|
isFixedRateMode: isFixedRateMode,
|
|
|
|
isReceiveAmount: isFixedRateMode,
|
|
|
|
)
|
|
|
|
.timeout(
|
|
|
|
Duration(seconds: 7),
|
|
|
|
onTimeout: () => 0.0,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
2022-10-20 17:47:36 +00:00
|
|
|
_sortedAvailableProviders.clear();
|
|
|
|
|
2023-08-04 13:49:26 +00:00
|
|
|
for (int i = 0; i < result.length; i++) {
|
2022-10-20 17:47:36 +00:00
|
|
|
if (result[i] != 0) {
|
|
|
|
/// add this provider as its valid for this trade
|
2023-02-07 21:48:10 +00:00
|
|
|
try {
|
|
|
|
_sortedAvailableProviders[result[i]] = _providers[i];
|
|
|
|
} catch (e) {
|
|
|
|
// will throw "Concurrent modification during iteration" error if modified at the same
|
|
|
|
// time [createTrade] is called, as this is not a normal map, but a sorted map
|
|
|
|
}
|
2022-09-07 11:43:03 +00:00
|
|
|
}
|
2022-10-20 17:47:36 +00:00
|
|
|
}
|
2023-10-25 20:58:25 +00:00
|
|
|
if (_sortedAvailableProviders.isNotEmpty) _bestRate = _sortedAvailableProviders.keys.first;
|
2020-07-31 15:29:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
2022-10-20 17:47:36 +00:00
|
|
|
Future<void> loadLimits() async {
|
2023-10-25 20:58:25 +00:00
|
|
|
if (selectedProviders.isEmpty) return;
|
2022-09-01 14:12:38 +00:00
|
|
|
|
2020-07-31 15:29:21 +00:00
|
|
|
limitsState = LimitsIsLoading();
|
|
|
|
|
2023-08-04 13:49:26 +00:00
|
|
|
final from = isFixedRateMode ? receiveCurrency : depositCurrency;
|
|
|
|
final to = isFixedRateMode ? depositCurrency : receiveCurrency;
|
2022-09-01 14:12:38 +00:00
|
|
|
|
2022-12-01 20:37:13 +00:00
|
|
|
double? lowestMin = double.maxFinite;
|
2022-10-20 17:47:36 +00:00
|
|
|
double? highestMax = 0.0;
|
|
|
|
|
2023-05-10 13:58:31 +00:00
|
|
|
try {
|
2024-07-23 00:20:55 +00:00
|
|
|
final result = await Future.wait(
|
|
|
|
selectedProviders.where((provider) => providersForCurrentPair().contains(provider)).map(
|
|
|
|
(provider) => provider
|
|
|
|
.fetchLimits(
|
|
|
|
from: from,
|
|
|
|
to: to,
|
|
|
|
isFixedRateMode: isFixedRateMode,
|
|
|
|
)
|
|
|
|
.onError((error, stackTrace) => Limits(max: 0.0, min: double.maxFinite))
|
|
|
|
.timeout(
|
|
|
|
Duration(seconds: 7),
|
|
|
|
onTimeout: () => Limits(max: 0.0, min: double.maxFinite),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
2024-07-20 23:26:05 +00:00
|
|
|
|
|
|
|
result.forEach((tempLimits) {
|
|
|
|
if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin!) {
|
|
|
|
lowestMin = tempLimits.min;
|
|
|
|
}
|
2023-10-25 20:58:25 +00:00
|
|
|
|
2024-07-20 23:26:05 +00:00
|
|
|
if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax!) {
|
|
|
|
highestMax = tempLimits.max;
|
2022-09-01 14:12:38 +00:00
|
|
|
}
|
2024-07-20 23:26:05 +00:00
|
|
|
});
|
2023-05-10 13:58:31 +00:00
|
|
|
} on ConcurrentModificationError {
|
|
|
|
/// if user changed the selected providers while fetching limits
|
|
|
|
/// then delay the fetching limits a bit and try again
|
|
|
|
///
|
|
|
|
/// this is because the limitation of collections that
|
|
|
|
/// you can't modify it while iterating through it
|
|
|
|
Future.delayed(Duration(milliseconds: 200), loadLimits);
|
2022-10-20 17:47:36 +00:00
|
|
|
}
|
|
|
|
|
2022-12-01 20:37:13 +00:00
|
|
|
if (lowestMin != double.maxFinite) {
|
2022-10-20 17:47:36 +00:00
|
|
|
limits = Limits(min: lowestMin, max: highestMax);
|
2022-09-01 14:12:38 +00:00
|
|
|
|
2020-07-31 15:29:21 +00:00
|
|
|
limitsState = LimitsLoadedSuccessfully(limits: limits);
|
2022-10-20 17:47:36 +00:00
|
|
|
} else {
|
|
|
|
limitsState = LimitsLoadedFailure(error: 'Limits loading failed');
|
2020-07-31 15:29:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
2022-10-12 17:09:57 +00:00
|
|
|
Future<void> createTrade() async {
|
2024-03-29 18:51:34 +00:00
|
|
|
if (isSendAllEnabled) {
|
|
|
|
await calculateDepositAllAmount();
|
|
|
|
final amount = double.tryParse(depositAmount);
|
|
|
|
|
|
|
|
if (limits.min != null && amount != null && amount < limits.min!) {
|
|
|
|
tradeState = TradeIsCreatedFailure(
|
|
|
|
title: S.current.trade_not_created,
|
|
|
|
error: S.current.amount_is_below_minimum_limit(limits.min!.toString()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-22 01:52:03 +00:00
|
|
|
try {
|
2024-07-23 00:20:55 +00:00
|
|
|
for (var i = 0; i < _sortedAvailableProviders.values.length; i++) {
|
|
|
|
final provider = _sortedAvailableProviders.values.toList()[i];
|
|
|
|
final providerRate = _sortedAvailableProviders.keys.toList()[i];
|
|
|
|
|
2023-10-25 20:58:25 +00:00
|
|
|
if (!(await provider.checkIsAvailable())) continue;
|
2022-08-31 15:34:07 +00:00
|
|
|
|
2024-07-23 00:20:55 +00:00
|
|
|
_bestRate = providerRate;
|
|
|
|
await changeDepositAmount(amount: depositAmount);
|
|
|
|
|
2023-10-25 20:58:25 +00:00
|
|
|
final request = TradeRequest(
|
2024-07-23 00:20:55 +00:00
|
|
|
fromCurrency: depositCurrency,
|
|
|
|
toCurrency: receiveCurrency,
|
|
|
|
fromAmount: depositAmount.replaceAll(',', '.'),
|
|
|
|
toAmount: receiveAmount.replaceAll(',', '.'),
|
|
|
|
refundAddress: depositAddress,
|
|
|
|
toAddress: receiveAddress,
|
|
|
|
isFixedRate: isFixedRateMode,
|
|
|
|
);
|
2023-02-06 19:20:43 +00:00
|
|
|
|
2023-10-25 20:58:25 +00:00
|
|
|
var amount = isFixedRateMode ? receiveAmount : depositAmount;
|
2022-11-22 01:52:03 +00:00
|
|
|
amount = amount.replaceAll(',', '.');
|
|
|
|
|
|
|
|
if (limitsState is LimitsLoadedSuccessfully) {
|
2023-10-25 20:58:25 +00:00
|
|
|
if (double.tryParse(amount) == null) continue;
|
|
|
|
|
2024-07-06 14:42:17 +00:00
|
|
|
if (limits.min != null && double.parse(amount) < limits.min!)
|
2022-09-01 14:12:38 +00:00
|
|
|
continue;
|
2023-10-25 20:58:25 +00:00
|
|
|
else if (limits.max != null && double.parse(amount) > limits.max!)
|
2022-11-22 01:52:03 +00:00
|
|
|
continue;
|
2023-10-25 20:58:25 +00:00
|
|
|
else {
|
2022-11-22 01:52:03 +00:00
|
|
|
try {
|
|
|
|
tradeState = TradeIsCreating();
|
2024-03-29 18:51:34 +00:00
|
|
|
final trade = await provider.createTrade(
|
|
|
|
request: request,
|
|
|
|
isFixedRateMode: isFixedRateMode,
|
|
|
|
isSendAll: isSendAllEnabled,
|
|
|
|
);
|
2022-11-22 01:52:03 +00:00
|
|
|
trade.walletId = wallet.id;
|
2023-11-02 15:52:47 +00:00
|
|
|
trade.fromWalletAddress = wallet.walletAddresses.address;
|
2024-03-28 12:41:11 +00:00
|
|
|
|
2024-04-25 01:14:11 +00:00
|
|
|
final canCreateTrade = await isCanCreateTrade(trade);
|
|
|
|
if (!canCreateTrade.result) {
|
2024-03-28 12:41:11 +00:00
|
|
|
tradeState = TradeIsCreatedFailure(
|
2024-04-25 01:14:11 +00:00
|
|
|
title: S.current.trade_not_created,
|
|
|
|
error: canCreateTrade.errorMessage ?? '',
|
|
|
|
);
|
2024-03-28 12:41:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-22 01:52:03 +00:00
|
|
|
tradesStore.setTrade(trade);
|
2024-03-28 12:41:11 +00:00
|
|
|
if (trade.provider != ExchangeProviderDescription.thorChain) await trades.add(trade);
|
2022-11-22 01:52:03 +00:00
|
|
|
tradeState = TradeIsCreatedSuccessfully(trade: trade);
|
2023-08-04 13:49:26 +00:00
|
|
|
|
2022-11-22 01:52:03 +00:00
|
|
|
/// return after the first successful trade
|
|
|
|
return;
|
|
|
|
} catch (e) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-09-01 14:12:38 +00:00
|
|
|
}
|
2020-07-31 15:29:21 +00:00
|
|
|
}
|
|
|
|
}
|
2022-09-01 14:12:38 +00:00
|
|
|
|
2022-11-22 01:52:03 +00:00
|
|
|
/// if the code reached here then none of the providers succeeded
|
|
|
|
tradeState = TradeIsCreatedFailure(
|
|
|
|
title: S.current.trade_not_created,
|
|
|
|
error: S.current.none_of_selected_providers_can_exchange);
|
|
|
|
} on ConcurrentModificationError {
|
|
|
|
/// if create trade happened at the exact same time of the scheduled rate update
|
|
|
|
/// then delay the create trade a bit and try again
|
|
|
|
///
|
|
|
|
/// this is because the limitation of the SplayTreeMap that
|
|
|
|
/// you can't modify it while iterating through it
|
2023-05-10 13:58:31 +00:00
|
|
|
Future.delayed(Duration(milliseconds: 200), createTrade);
|
2022-11-22 01:52:03 +00:00
|
|
|
}
|
2020-07-31 15:29:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
|
|
|
void reset() {
|
2021-02-19 08:37:30 +00:00
|
|
|
_initialPairBasedOnWallet();
|
2020-10-12 16:47:01 +00:00
|
|
|
isReceiveAmountEntered = false;
|
2020-07-31 15:29:21 +00:00
|
|
|
depositAmount = '';
|
|
|
|
receiveAmount = '';
|
2023-09-01 15:06:18 +00:00
|
|
|
depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.address : '';
|
|
|
|
receiveAddress = receiveCurrency == wallet.currency ? wallet.walletAddresses.address : '';
|
2020-07-31 15:29:21 +00:00
|
|
|
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
2021-02-18 19:08:52 +00:00
|
|
|
isFixedRateMode = false;
|
2020-07-31 15:29:21 +00:00
|
|
|
_onPairChange();
|
|
|
|
}
|
|
|
|
|
2021-01-05 18:31:03 +00:00
|
|
|
@action
|
2024-03-21 02:51:57 +00:00
|
|
|
void enableSendAllAmount() {
|
|
|
|
isSendAllEnabled = true;
|
2024-03-29 18:51:34 +00:00
|
|
|
isFixedRateMode = false;
|
2024-03-21 02:51:57 +00:00
|
|
|
calculateDepositAllAmount();
|
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
2024-03-29 18:51:34 +00:00
|
|
|
void enableFixedRateMode() {
|
|
|
|
isSendAllEnabled = false;
|
|
|
|
isFixedRateMode = true;
|
|
|
|
}
|
2021-01-05 18:31:03 +00:00
|
|
|
|
2024-03-29 18:51:34 +00:00
|
|
|
@action
|
|
|
|
Future<void> calculateDepositAllAmount() async {
|
|
|
|
if (wallet.type == WalletType.litecoin ||
|
|
|
|
wallet.type == WalletType.bitcoin ||
|
2023-11-02 18:17:52 +00:00
|
|
|
wallet.type == WalletType.bitcoinCash) {
|
2022-10-12 17:09:57 +00:00
|
|
|
final priority = _settingsStore.priority[wallet.type]!;
|
2021-01-05 18:31:03 +00:00
|
|
|
|
2024-03-29 18:51:34 +00:00
|
|
|
final amount = await bitcoin!.estimateFakeSendAllTxAmount(wallet, priority);
|
2021-01-05 18:31:03 +00:00
|
|
|
|
2023-09-01 15:06:18 +00:00
|
|
|
changeDepositAmount(amount: bitcoin!.formatterBitcoinAmountToString(amount: amount));
|
2021-01-05 18:31:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-07 05:58:22 +00:00
|
|
|
void updateTemplate() => _exchangeTemplateStore.update();
|
|
|
|
|
2020-11-10 14:58:40 +00:00
|
|
|
void addTemplate(
|
2022-10-12 17:09:57 +00:00
|
|
|
{required String amount,
|
|
|
|
required String depositCurrency,
|
|
|
|
required String receiveCurrency,
|
|
|
|
required String provider,
|
|
|
|
required String depositAddress,
|
2023-05-03 07:01:51 +00:00
|
|
|
required String receiveAddress,
|
|
|
|
required String depositCurrencyTitle,
|
|
|
|
required String receiveCurrencyTitle}) =>
|
2020-11-10 14:58:40 +00:00
|
|
|
_exchangeTemplateStore.addTemplate(
|
|
|
|
amount: amount,
|
|
|
|
depositCurrency: depositCurrency,
|
|
|
|
receiveCurrency: receiveCurrency,
|
|
|
|
provider: provider,
|
|
|
|
depositAddress: depositAddress,
|
2023-05-03 07:01:51 +00:00
|
|
|
receiveAddress: receiveAddress,
|
|
|
|
depositCurrencyTitle: depositCurrencyTitle,
|
|
|
|
receiveCurrencyTitle: receiveCurrencyTitle);
|
2020-10-07 05:58:22 +00:00
|
|
|
|
2022-10-12 17:09:57 +00:00
|
|
|
void removeTemplate({required ExchangeTemplate template}) =>
|
2020-11-10 14:58:40 +00:00
|
|
|
_exchangeTemplateStore.remove(template: template);
|
2020-10-07 05:58:22 +00:00
|
|
|
|
2023-10-25 20:58:25 +00:00
|
|
|
List<ExchangeProvider> providersForCurrentPair() =>
|
|
|
|
_providersForPair(from: depositCurrency, to: receiveCurrency);
|
2020-07-31 15:29:21 +00:00
|
|
|
|
|
|
|
List<ExchangeProvider> _providersForPair(
|
2023-10-25 20:58:25 +00:00
|
|
|
{required CryptoCurrency from, required CryptoCurrency to}) =>
|
|
|
|
providerList
|
|
|
|
.where((provider) =>
|
|
|
|
provider.pairList.where((pair) => pair.from == from && pair.to == to).isNotEmpty)
|
|
|
|
.toList();
|
2020-07-31 15:29:21 +00:00
|
|
|
|
|
|
|
void _onPairChange() {
|
2022-09-01 14:12:38 +00:00
|
|
|
depositAmount = '';
|
|
|
|
receiveAmount = '';
|
2022-10-20 17:47:36 +00:00
|
|
|
loadLimits();
|
|
|
|
_setAvailableProviders();
|
|
|
|
_bestRate = 0;
|
|
|
|
_calculateBestRate();
|
2020-07-31 15:29:21 +00:00
|
|
|
}
|
|
|
|
|
2020-09-02 08:47:41 +00:00
|
|
|
void _initialPairBasedOnWallet() {
|
|
|
|
switch (wallet.type) {
|
|
|
|
case WalletType.monero:
|
|
|
|
depositCurrency = CryptoCurrency.xmr;
|
|
|
|
receiveCurrency = CryptoCurrency.btc;
|
|
|
|
break;
|
|
|
|
case WalletType.bitcoin:
|
|
|
|
depositCurrency = CryptoCurrency.btc;
|
|
|
|
receiveCurrency = CryptoCurrency.xmr;
|
|
|
|
break;
|
2021-05-07 07:36:38 +00:00
|
|
|
case WalletType.litecoin:
|
|
|
|
depositCurrency = CryptoCurrency.ltc;
|
|
|
|
receiveCurrency = CryptoCurrency.xmr;
|
|
|
|
break;
|
2023-10-12 22:50:16 +00:00
|
|
|
case WalletType.bitcoinCash:
|
|
|
|
depositCurrency = CryptoCurrency.bch;
|
|
|
|
receiveCurrency = CryptoCurrency.xmr;
|
|
|
|
break;
|
2022-09-01 18:46:14 +00:00
|
|
|
case WalletType.haven:
|
|
|
|
depositCurrency = CryptoCurrency.xhv;
|
|
|
|
receiveCurrency = CryptoCurrency.btc;
|
|
|
|
break;
|
2023-08-04 17:01:49 +00:00
|
|
|
case WalletType.ethereum:
|
|
|
|
depositCurrency = CryptoCurrency.eth;
|
|
|
|
receiveCurrency = CryptoCurrency.xmr;
|
|
|
|
break;
|
2023-10-05 01:09:07 +00:00
|
|
|
case WalletType.nano:
|
|
|
|
depositCurrency = CryptoCurrency.nano;
|
|
|
|
receiveCurrency = CryptoCurrency.xmr;
|
|
|
|
break;
|
Wownero (#1485)
* fix: scanning issues
* fix: sync, storing silent unspents
* chore: deps
* fix: label issues, clear spent utxo
* chore: deps
* fix: build
* fix: missing types
* feat: new electrs API & changes, fixes for last block scanning
* feat: Scan Silent Payments homepage toggle
* chore: build configure
* feat: generic fixes, testnet UI improvements, useSSL on bitcoin nodes
* fix: invalid Object in sendData
* feat: improve addresses page & address book displays
* feat: silent payments labeled addresses disclaimer
* fix: missing i18n
* chore: print
* feat: single block scan, rescan by date working for btc mainnet
* feat: new cake features page replace market page, move sp scan toggle, auto switch node pop up alert
* feat: delete silent addresses
* fix: red dot in non ssl nodes
* fix: inconsistent connection states, fix tx history
* fix: tx & balance displays, cpfp sending
* feat: new rust lib
* chore: node path
* fix: check node based on network
* fix: missing txcount from addresses
* style: padding in feature page cards
* fix: restore not getting all wallet addresses by type
* fix: auto switch node broken
* fix: silent payment txs not being restored
* feat: change scanning to subscription model, sync improvements
* fix: scan re-subscription
* fix: default nodes
* fix: improve scanning by date, fix single block scan
* refactor: common function for input tx selection
* various fixes for build issues
* initial monero.dart implementation
* ...
* multiple wallets
new lib
minor fixes
* other fixes from monero.dart and monero_c
* fix: nodes & build
* update build scripts
fix polyseed
* remove unnecessary code
* Add windows app, build scripts and build guide for it.
* Minor fix in generated monero configs
* fix: send all with multiple outs
* add missing monero_c command
* add android build script
* Merge and fix main
* undo android ndk removal
* Fix modified exception_handler.dart
* Temporarily remove haven
* fix build issues
* fix pr script
* Fixes for build monero.dart (monero_c) for windows.
* monero build script
* wip: ios build script
* refactor: unchanged file
* Added build guides for iOS and macOS. Replaced nproc call on macOS. Added macOS configuration for configure_cake_wallet.sh script.
* Update monero.dart and monero_c versions.
* Add missed windows build scripts
* Update the application configuration for windows build script.
* Update cw_monero pubspec lock file for monero.dart
* Update pr_test_build.yml
* chore: upgrade
* chore: merge changes
* refactor: unchanged files [skip ci]
* Fix conflicts with main
* fix for multiple wallets
* Add tron to windows application configuration.
* Add macOS option for description message in configure_cake_wallet.sh
* Include missed monero dll for windows.
* fix conflicts with main
* Disable haven configuration for iOS as default. Add ability to configure cakewallet for iOS with for configuration script. Remove cw_shared configuration for cw_monero.
* fix: scan fixes, add date, allow sending while scanning
* add missing nano secrets file [skip ci]
* ios library
* don't pull prebuilds android
* Add auto generation of manifest file for android project even for iOS, macOS, Windows.
* feat: sync fixes, sp settings
* feat: fix resyncing
* store crash fix
* make init async so it won't lag
disable print starts
* fix monero_c build issues
* libstdc++
* Fix MacOS saving wallet file issue
Fix Secure Storage issue (somehow)
* update pubspec.lock
* fix build script
* Use dylib as iOS framework. Use custom path for loading of iOS framework for monero.dart. Add script for generate iOS framework for monero wallet.
* fix: date from height logic, status disconnected & chain tip get
* fix: params
* feat: electrum migration if using cake electrum
* fix nodes
update versions
* re-enable tron
* update sp_scanner to work on iOS [skip ci]
* bump monero_c hash
* bump monero_c commit
* bump moneroc version
* bump monero_c commit
* Add ability to build monero wallet lib as universal lib. Update macOS build guide. Change default arch for macOS project to .
* fix: wrong socket for old electrum nodes
* Fix unchecked wallet type call
* get App Dir correctly in default_settings_migration.dart
* handle previous issue with fetching linux documents directory [skip ci]
* backup fix
* fix NTFS issues
* Close the wallet when the wallet gets changed
* fix: double balance
* feat: node domain
* fix: menu name
* bump monero_c commit
* fix: update tip on set scanning
* fix: connection switching back and forth
* feat: check if node is electrs, and supports sp
* chore: fix build
* minor enhancements
* fixes and enhancements
* solve conflicts with main
* Only stop wallet on rename and delete
* fix: status toggle
* minor enhancement
* Monero.com fixes
* bump monero_c commit
* update sp_scanner to include windows and linux
* Update macOS build guide. Change brew dependencies for build unbound locally.
* fix conflicts and update macos build guide
* remove build cache when on gh actions
* update secure storage
* free up even more storage
* free up more storage
* Add initial wownero
* fix conflicts
* fix workflow issue
* build wownero
* ios and windows changes
* macos
* complete wownero flow (app side)
* add keychain group entitlement and update script for RunnerBase on macos
* update secure_storage version to 8.1.0 in configure.dart
* add wownero framework
* update ios builds
* proper path for wownero and monero
* finalizing wownero
* finalizing wownero
* free up even more storage
* revert commenting of build gradle configs
* revert commenting of secrets [skip ci]
* free more storage
* minor fixes
* link android wownero libraries
* bump monero_c commit
* wownero fixes
* rename target
* build_single.sh using clean env
* bump monero_c commit
* minor fix
* Add wownero polyseed
* fix conflicts with main
* fix: wallet seed display
fix: wownero not refreshing
* fix: wallet seed display
fix: wownero not refreshing
* bump monero_c commit
* minor fixes
* fix: incorrectly displaying XMR instead of WOW
* fix: incorrect restore height in wownero
* bump monero_c commit
* Add Inno Setup Script for windows exe installer
* drop libc++_shared.so
* fixes from comments
* Fix CMake for windows
* Merge latest monero dart changes [skip ci]
* bump monero_c commit
* add wownero to build scripts for macos [skip ci]
* add 14 word seed support to wownero
* UI fixes for wownero seed restore
* minor fixes
* reformat code to pass lints
* wownero: fixes
haven: removal popup
* minor iOS fix [skip ci]
* fix: wownero confirmation count (it is spendable after 3 confirms)
fix: transaction history not displaying in WOW and XMR
when tx has 0 confirms,
This is more of a workaround, because I have no idea
why would the cpp code not return pending transaction.
* Update preferences_key.dart [skip ci]
* minor fixes
---------
Co-authored-by: Rafael Saes <git@rafael.saes.dev>
Co-authored-by: Czarek Nakamoto <cyjan@mrcyjanek.net>
Co-authored-by: M <m@cakewallet.com>
Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com>
Co-authored-by: Matthew Fosse <matt@fosse.co>
2024-07-04 19:43:17 +00:00
|
|
|
case WalletType.banano:
|
|
|
|
depositCurrency = CryptoCurrency.banano;
|
|
|
|
receiveCurrency = CryptoCurrency.xmr;
|
|
|
|
break;
|
2023-12-02 02:26:43 +00:00
|
|
|
case WalletType.polygon:
|
|
|
|
depositCurrency = CryptoCurrency.maticpoly;
|
|
|
|
receiveCurrency = CryptoCurrency.xmr;
|
|
|
|
break;
|
CW-555-Add-Solana-Wallet (#1272)
* chore: Create cw_solana package and clean up files
* feat: Add Solana Wallet - Create, Restore form seed, restore from Key, Restore from QR, Send, Receive, transaction history, spl tokens
* fix: Make transactions file specific to solana only for solana transactions
* chore: Revert inject app details script
* fix: Fix issue with node and switch current node to main beta instead of testnet
* fix: Fix merge conflicts and adjust migration version
* fix: Fetch spl token error
Signed-off-by: Blazebrain <davidadegoke16@gmail.com>
* fix: Diplay and activate spl tokens bug
* fix: Review and fixes
* fix: reverted formatting for cryptocurrency class
* fix: Review comments, split sending flow into signing and sending separately, fix issues
* fix: Revert throwing unimplenented error
* chore: Fix comment
* chore: Fix comment
* fix: Errors in flow
* Update provider_types.dart [skip ci]
* fix: Issues with solana wallet
* Update solana_wallet.dart [skip ci]
* fix: Review comments
* fix: Date time config
* fix: Revert bash script for app details
* fix: Error with balance, displaying fees, fixing sent or received identifier bug, displaying token symbol with token transaction item in transactions list
* fix: Issues with address validation when sending spl tokens and walletconnect initial setup
* fix: Issues with sending, fetching transactions history, almost wrapping up walletconnect
* fix: Adjust imports that would affect monerocom building successfully
* fix: Refine transaction direction and continue work on walletconnect
* feat: Display SPL token transfers in the transaction history and finally settle the transaction direction
* fix: Delay in transactions history dispaly, show native token transactions first, then process spl token transactions
* feat: Switch node and revert solana chain id to previous id
* fix: Remove print statement
* fix: Remove await for transactions, fetch all transaction histories instantly and adjust solana send success message
* chore: Code refactoring and streamlined wallet type check for solana send success message
* fix: Make timeout error for node silent and add spl token images
---------
Signed-off-by: Blazebrain <davidadegoke16@gmail.com>
Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
2024-02-23 13:39:19 +00:00
|
|
|
case WalletType.solana:
|
|
|
|
depositCurrency = CryptoCurrency.sol;
|
|
|
|
receiveCurrency = CryptoCurrency.xmr;
|
|
|
|
break;
|
CW-525-Add-Tron-Wallet (#1327)
* chore: Initial setup for Tron Wallet
* feat: Create Tron Wallet base flow implemented, keys, address, receive, restore and proxy classes all setup
* feat: Display seed and key within the app
* feat: Activate restore from key and seed for Tron wallet
* feat: Add icon for tron wallet in wallet listing page
* feat: Activate display of receive address for tron
* feat: Fetch and display tron balance, sending transaction flow setup, fee limit calculation setup
* feat: Implement sending of native tron, setup sending of trc20 tokens
* chore: Rename function
* Delete lib/tron/tron.dart
* feat: Activate exchange for tron and its tokens, implement balance display for trc20 tokens and setup secrets configuration for tron
* feat: Implement tron token management, add, remove, delete, and get tokens in home settings view, also minor cleanup
* feat: Activate buy and sell for tron
* feat: Implement restore from QR, transactions history listing for both native transactions and trc20 transactions
* feat: Activate send all and do some minor cleanups
* chore: Fix some lint infos and warnings
* chore: Adjust configurations
* ci: Modify CI to create and add secrets for node
* fix: Fixes made while self reviewing the PR for this feature
* feat: Add guide for adding new wallet types, and add fixes to requested changes
* fix: Handle exceptions gracefully
* fix: Alternative for trc20 estimated fee
* fix: Fixes to display of amount and fee, removing clashes
* fix: Fee calculation WIP
* fix: Fix issue with handling of send all flow and display of amount and fee values before broadcasting transaction
* fix: PR review fixes and fix merge conflicts
* fix: Modify fetching assetOfTransaction [skip ci]
* fix: Move tron settings migration to 33
2024-05-03 18:00:05 +00:00
|
|
|
case WalletType.tron:
|
|
|
|
depositCurrency = CryptoCurrency.trx;
|
|
|
|
receiveCurrency = CryptoCurrency.xmr;
|
|
|
|
break;
|
Wownero (#1485)
* fix: scanning issues
* fix: sync, storing silent unspents
* chore: deps
* fix: label issues, clear spent utxo
* chore: deps
* fix: build
* fix: missing types
* feat: new electrs API & changes, fixes for last block scanning
* feat: Scan Silent Payments homepage toggle
* chore: build configure
* feat: generic fixes, testnet UI improvements, useSSL on bitcoin nodes
* fix: invalid Object in sendData
* feat: improve addresses page & address book displays
* feat: silent payments labeled addresses disclaimer
* fix: missing i18n
* chore: print
* feat: single block scan, rescan by date working for btc mainnet
* feat: new cake features page replace market page, move sp scan toggle, auto switch node pop up alert
* feat: delete silent addresses
* fix: red dot in non ssl nodes
* fix: inconsistent connection states, fix tx history
* fix: tx & balance displays, cpfp sending
* feat: new rust lib
* chore: node path
* fix: check node based on network
* fix: missing txcount from addresses
* style: padding in feature page cards
* fix: restore not getting all wallet addresses by type
* fix: auto switch node broken
* fix: silent payment txs not being restored
* feat: change scanning to subscription model, sync improvements
* fix: scan re-subscription
* fix: default nodes
* fix: improve scanning by date, fix single block scan
* refactor: common function for input tx selection
* various fixes for build issues
* initial monero.dart implementation
* ...
* multiple wallets
new lib
minor fixes
* other fixes from monero.dart and monero_c
* fix: nodes & build
* update build scripts
fix polyseed
* remove unnecessary code
* Add windows app, build scripts and build guide for it.
* Minor fix in generated monero configs
* fix: send all with multiple outs
* add missing monero_c command
* add android build script
* Merge and fix main
* undo android ndk removal
* Fix modified exception_handler.dart
* Temporarily remove haven
* fix build issues
* fix pr script
* Fixes for build monero.dart (monero_c) for windows.
* monero build script
* wip: ios build script
* refactor: unchanged file
* Added build guides for iOS and macOS. Replaced nproc call on macOS. Added macOS configuration for configure_cake_wallet.sh script.
* Update monero.dart and monero_c versions.
* Add missed windows build scripts
* Update the application configuration for windows build script.
* Update cw_monero pubspec lock file for monero.dart
* Update pr_test_build.yml
* chore: upgrade
* chore: merge changes
* refactor: unchanged files [skip ci]
* Fix conflicts with main
* fix for multiple wallets
* Add tron to windows application configuration.
* Add macOS option for description message in configure_cake_wallet.sh
* Include missed monero dll for windows.
* fix conflicts with main
* Disable haven configuration for iOS as default. Add ability to configure cakewallet for iOS with for configuration script. Remove cw_shared configuration for cw_monero.
* fix: scan fixes, add date, allow sending while scanning
* add missing nano secrets file [skip ci]
* ios library
* don't pull prebuilds android
* Add auto generation of manifest file for android project even for iOS, macOS, Windows.
* feat: sync fixes, sp settings
* feat: fix resyncing
* store crash fix
* make init async so it won't lag
disable print starts
* fix monero_c build issues
* libstdc++
* Fix MacOS saving wallet file issue
Fix Secure Storage issue (somehow)
* update pubspec.lock
* fix build script
* Use dylib as iOS framework. Use custom path for loading of iOS framework for monero.dart. Add script for generate iOS framework for monero wallet.
* fix: date from height logic, status disconnected & chain tip get
* fix: params
* feat: electrum migration if using cake electrum
* fix nodes
update versions
* re-enable tron
* update sp_scanner to work on iOS [skip ci]
* bump monero_c hash
* bump monero_c commit
* bump moneroc version
* bump monero_c commit
* Add ability to build monero wallet lib as universal lib. Update macOS build guide. Change default arch for macOS project to .
* fix: wrong socket for old electrum nodes
* Fix unchecked wallet type call
* get App Dir correctly in default_settings_migration.dart
* handle previous issue with fetching linux documents directory [skip ci]
* backup fix
* fix NTFS issues
* Close the wallet when the wallet gets changed
* fix: double balance
* feat: node domain
* fix: menu name
* bump monero_c commit
* fix: update tip on set scanning
* fix: connection switching back and forth
* feat: check if node is electrs, and supports sp
* chore: fix build
* minor enhancements
* fixes and enhancements
* solve conflicts with main
* Only stop wallet on rename and delete
* fix: status toggle
* minor enhancement
* Monero.com fixes
* bump monero_c commit
* update sp_scanner to include windows and linux
* Update macOS build guide. Change brew dependencies for build unbound locally.
* fix conflicts and update macos build guide
* remove build cache when on gh actions
* update secure storage
* free up even more storage
* free up more storage
* Add initial wownero
* fix conflicts
* fix workflow issue
* build wownero
* ios and windows changes
* macos
* complete wownero flow (app side)
* add keychain group entitlement and update script for RunnerBase on macos
* update secure_storage version to 8.1.0 in configure.dart
* add wownero framework
* update ios builds
* proper path for wownero and monero
* finalizing wownero
* finalizing wownero
* free up even more storage
* revert commenting of build gradle configs
* revert commenting of secrets [skip ci]
* free more storage
* minor fixes
* link android wownero libraries
* bump monero_c commit
* wownero fixes
* rename target
* build_single.sh using clean env
* bump monero_c commit
* minor fix
* Add wownero polyseed
* fix conflicts with main
* fix: wallet seed display
fix: wownero not refreshing
* fix: wallet seed display
fix: wownero not refreshing
* bump monero_c commit
* minor fixes
* fix: incorrectly displaying XMR instead of WOW
* fix: incorrect restore height in wownero
* bump monero_c commit
* Add Inno Setup Script for windows exe installer
* drop libc++_shared.so
* fixes from comments
* Fix CMake for windows
* Merge latest monero dart changes [skip ci]
* bump monero_c commit
* add wownero to build scripts for macos [skip ci]
* add 14 word seed support to wownero
* UI fixes for wownero seed restore
* minor fixes
* reformat code to pass lints
* wownero: fixes
haven: removal popup
* minor iOS fix [skip ci]
* fix: wownero confirmation count (it is spendable after 3 confirms)
fix: transaction history not displaying in WOW and XMR
when tx has 0 confirms,
This is more of a workaround, because I have no idea
why would the cpp code not return pending transaction.
* Update preferences_key.dart [skip ci]
* minor fixes
---------
Co-authored-by: Rafael Saes <git@rafael.saes.dev>
Co-authored-by: Czarek Nakamoto <cyjan@mrcyjanek.net>
Co-authored-by: M <m@cakewallet.com>
Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com>
Co-authored-by: Matthew Fosse <matt@fosse.co>
2024-07-04 19:43:17 +00:00
|
|
|
case WalletType.wownero:
|
|
|
|
depositCurrency = CryptoCurrency.wow;
|
|
|
|
receiveCurrency = CryptoCurrency.xmr;
|
|
|
|
break;
|
2023-10-15 13:36:05 +00:00
|
|
|
case WalletType.zano:
|
2023-12-16 15:00:22 +00:00
|
|
|
depositCurrency = CryptoCurrency.zano;
|
|
|
|
receiveCurrency = CryptoCurrency.btc;
|
|
|
|
break;
|
Wownero (#1485)
* fix: scanning issues
* fix: sync, storing silent unspents
* chore: deps
* fix: label issues, clear spent utxo
* chore: deps
* fix: build
* fix: missing types
* feat: new electrs API & changes, fixes for last block scanning
* feat: Scan Silent Payments homepage toggle
* chore: build configure
* feat: generic fixes, testnet UI improvements, useSSL on bitcoin nodes
* fix: invalid Object in sendData
* feat: improve addresses page & address book displays
* feat: silent payments labeled addresses disclaimer
* fix: missing i18n
* chore: print
* feat: single block scan, rescan by date working for btc mainnet
* feat: new cake features page replace market page, move sp scan toggle, auto switch node pop up alert
* feat: delete silent addresses
* fix: red dot in non ssl nodes
* fix: inconsistent connection states, fix tx history
* fix: tx & balance displays, cpfp sending
* feat: new rust lib
* chore: node path
* fix: check node based on network
* fix: missing txcount from addresses
* style: padding in feature page cards
* fix: restore not getting all wallet addresses by type
* fix: auto switch node broken
* fix: silent payment txs not being restored
* feat: change scanning to subscription model, sync improvements
* fix: scan re-subscription
* fix: default nodes
* fix: improve scanning by date, fix single block scan
* refactor: common function for input tx selection
* various fixes for build issues
* initial monero.dart implementation
* ...
* multiple wallets
new lib
minor fixes
* other fixes from monero.dart and monero_c
* fix: nodes & build
* update build scripts
fix polyseed
* remove unnecessary code
* Add windows app, build scripts and build guide for it.
* Minor fix in generated monero configs
* fix: send all with multiple outs
* add missing monero_c command
* add android build script
* Merge and fix main
* undo android ndk removal
* Fix modified exception_handler.dart
* Temporarily remove haven
* fix build issues
* fix pr script
* Fixes for build monero.dart (monero_c) for windows.
* monero build script
* wip: ios build script
* refactor: unchanged file
* Added build guides for iOS and macOS. Replaced nproc call on macOS. Added macOS configuration for configure_cake_wallet.sh script.
* Update monero.dart and monero_c versions.
* Add missed windows build scripts
* Update the application configuration for windows build script.
* Update cw_monero pubspec lock file for monero.dart
* Update pr_test_build.yml
* chore: upgrade
* chore: merge changes
* refactor: unchanged files [skip ci]
* Fix conflicts with main
* fix for multiple wallets
* Add tron to windows application configuration.
* Add macOS option for description message in configure_cake_wallet.sh
* Include missed monero dll for windows.
* fix conflicts with main
* Disable haven configuration for iOS as default. Add ability to configure cakewallet for iOS with for configuration script. Remove cw_shared configuration for cw_monero.
* fix: scan fixes, add date, allow sending while scanning
* add missing nano secrets file [skip ci]
* ios library
* don't pull prebuilds android
* Add auto generation of manifest file for android project even for iOS, macOS, Windows.
* feat: sync fixes, sp settings
* feat: fix resyncing
* store crash fix
* make init async so it won't lag
disable print starts
* fix monero_c build issues
* libstdc++
* Fix MacOS saving wallet file issue
Fix Secure Storage issue (somehow)
* update pubspec.lock
* fix build script
* Use dylib as iOS framework. Use custom path for loading of iOS framework for monero.dart. Add script for generate iOS framework for monero wallet.
* fix: date from height logic, status disconnected & chain tip get
* fix: params
* feat: electrum migration if using cake electrum
* fix nodes
update versions
* re-enable tron
* update sp_scanner to work on iOS [skip ci]
* bump monero_c hash
* bump monero_c commit
* bump moneroc version
* bump monero_c commit
* Add ability to build monero wallet lib as universal lib. Update macOS build guide. Change default arch for macOS project to .
* fix: wrong socket for old electrum nodes
* Fix unchecked wallet type call
* get App Dir correctly in default_settings_migration.dart
* handle previous issue with fetching linux documents directory [skip ci]
* backup fix
* fix NTFS issues
* Close the wallet when the wallet gets changed
* fix: double balance
* feat: node domain
* fix: menu name
* bump monero_c commit
* fix: update tip on set scanning
* fix: connection switching back and forth
* feat: check if node is electrs, and supports sp
* chore: fix build
* minor enhancements
* fixes and enhancements
* solve conflicts with main
* Only stop wallet on rename and delete
* fix: status toggle
* minor enhancement
* Monero.com fixes
* bump monero_c commit
* update sp_scanner to include windows and linux
* Update macOS build guide. Change brew dependencies for build unbound locally.
* fix conflicts and update macos build guide
* remove build cache when on gh actions
* update secure storage
* free up even more storage
* free up more storage
* Add initial wownero
* fix conflicts
* fix workflow issue
* build wownero
* ios and windows changes
* macos
* complete wownero flow (app side)
* add keychain group entitlement and update script for RunnerBase on macos
* update secure_storage version to 8.1.0 in configure.dart
* add wownero framework
* update ios builds
* proper path for wownero and monero
* finalizing wownero
* finalizing wownero
* free up even more storage
* revert commenting of build gradle configs
* revert commenting of secrets [skip ci]
* free more storage
* minor fixes
* link android wownero libraries
* bump monero_c commit
* wownero fixes
* rename target
* build_single.sh using clean env
* bump monero_c commit
* minor fix
* Add wownero polyseed
* fix conflicts with main
* fix: wallet seed display
fix: wownero not refreshing
* fix: wallet seed display
fix: wownero not refreshing
* bump monero_c commit
* minor fixes
* fix: incorrectly displaying XMR instead of WOW
* fix: incorrect restore height in wownero
* bump monero_c commit
* Add Inno Setup Script for windows exe installer
* drop libc++_shared.so
* fixes from comments
* Fix CMake for windows
* Merge latest monero dart changes [skip ci]
* bump monero_c commit
* add wownero to build scripts for macos [skip ci]
* add 14 word seed support to wownero
* UI fixes for wownero seed restore
* minor fixes
* reformat code to pass lints
* wownero: fixes
haven: removal popup
* minor iOS fix [skip ci]
* fix: wownero confirmation count (it is spendable after 3 confirms)
fix: transaction history not displaying in WOW and XMR
when tx has 0 confirms,
This is more of a workaround, because I have no idea
why would the cpp code not return pending transaction.
* Update preferences_key.dart [skip ci]
* minor fixes
---------
Co-authored-by: Rafael Saes <git@rafael.saes.dev>
Co-authored-by: Czarek Nakamoto <cyjan@mrcyjanek.net>
Co-authored-by: M <m@cakewallet.com>
Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com>
Co-authored-by: Matthew Fosse <matt@fosse.co>
2024-07-04 19:43:17 +00:00
|
|
|
case WalletType.none:
|
2020-09-02 08:47:41 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-02-23 17:36:03 +00:00
|
|
|
|
|
|
|
void _defineIsReceiveAmountEditable() {
|
2021-03-15 17:54:04 +00:00
|
|
|
/*if ((provider is ChangeNowExchangeProvider)
|
2021-02-23 17:36:03 +00:00
|
|
|
&&(depositCurrency == CryptoCurrency.xmr)
|
|
|
|
&&(receiveCurrency == CryptoCurrency.btc)) {
|
|
|
|
isReceiveAmountEditable = true;
|
|
|
|
} else {
|
|
|
|
isReceiveAmountEditable = false;
|
2021-03-15 17:54:04 +00:00
|
|
|
}*/
|
2022-01-26 15:44:15 +00:00
|
|
|
//isReceiveAmountEditable = false;
|
2022-09-01 14:12:38 +00:00
|
|
|
// isReceiveAmountEditable = selectedProviders.any((provider) => provider is ChangeNowExchangeProvider);
|
|
|
|
// isReceiveAmountEditable = provider is ChangeNowExchangeProvider || provider is SimpleSwapExchangeProvider;
|
|
|
|
isReceiveAmountEditable = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
|
|
|
void addExchangeProvider(ExchangeProvider provider) {
|
|
|
|
selectedProviders.add(provider);
|
2023-10-25 20:58:25 +00:00
|
|
|
if (providersForCurrentPair().contains(provider)) _tradeAvailableProviders.add(provider);
|
2022-09-01 14:12:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
|
|
|
void removeExchangeProvider(ExchangeProvider provider) {
|
|
|
|
selectedProviders.remove(provider);
|
2022-10-20 17:47:36 +00:00
|
|
|
_tradeAvailableProviders.remove(provider);
|
2022-09-01 14:12:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
|
|
|
void saveSelectedProviders() {
|
|
|
|
depositAmount = '';
|
|
|
|
receiveAmount = '';
|
|
|
|
isFixedRateMode = false;
|
|
|
|
_defineIsReceiveAmountEditable();
|
|
|
|
loadLimits();
|
2022-10-20 17:47:36 +00:00
|
|
|
_bestRate = 0;
|
|
|
|
_calculateBestRate();
|
2022-09-01 14:12:38 +00:00
|
|
|
|
2023-09-01 15:06:18 +00:00
|
|
|
final Map<String, dynamic> exchangeProvidersSelection =
|
|
|
|
json.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}")
|
|
|
|
as Map<String, dynamic>;
|
2022-09-01 14:12:38 +00:00
|
|
|
|
2022-10-20 17:47:36 +00:00
|
|
|
for (var provider in providerList) {
|
2023-09-01 15:06:18 +00:00
|
|
|
exchangeProvidersSelection[provider.title] = selectedProviders.contains(provider);
|
2022-09-01 14:12:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sharedPreferences.setString(
|
|
|
|
PreferencesKey.exchangeProvidersSelection,
|
|
|
|
json.encode(exchangeProvidersSelection),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool get isAvailableInSelected {
|
|
|
|
final providersForPair = providersForCurrentPair();
|
2023-09-01 15:06:18 +00:00
|
|
|
return selectedProviders
|
|
|
|
.any((element) => element.isAvailable && providersForPair.contains(element));
|
2021-02-23 17:36:03 +00:00
|
|
|
}
|
2022-10-20 17:47:36 +00:00
|
|
|
|
|
|
|
void _setAvailableProviders() {
|
|
|
|
_tradeAvailableProviders.clear();
|
|
|
|
|
2023-09-01 15:06:18 +00:00
|
|
|
_tradeAvailableProviders.addAll(
|
|
|
|
selectedProviders.where((provider) => providersForCurrentPair().contains(provider)));
|
2022-10-20 17:47:36 +00:00
|
|
|
}
|
2022-11-03 19:21:35 +00:00
|
|
|
|
|
|
|
@action
|
|
|
|
void setDefaultTransactionPriority() {
|
|
|
|
switch (wallet.type) {
|
|
|
|
case WalletType.monero:
|
|
|
|
case WalletType.haven:
|
Wownero (#1485)
* fix: scanning issues
* fix: sync, storing silent unspents
* chore: deps
* fix: label issues, clear spent utxo
* chore: deps
* fix: build
* fix: missing types
* feat: new electrs API & changes, fixes for last block scanning
* feat: Scan Silent Payments homepage toggle
* chore: build configure
* feat: generic fixes, testnet UI improvements, useSSL on bitcoin nodes
* fix: invalid Object in sendData
* feat: improve addresses page & address book displays
* feat: silent payments labeled addresses disclaimer
* fix: missing i18n
* chore: print
* feat: single block scan, rescan by date working for btc mainnet
* feat: new cake features page replace market page, move sp scan toggle, auto switch node pop up alert
* feat: delete silent addresses
* fix: red dot in non ssl nodes
* fix: inconsistent connection states, fix tx history
* fix: tx & balance displays, cpfp sending
* feat: new rust lib
* chore: node path
* fix: check node based on network
* fix: missing txcount from addresses
* style: padding in feature page cards
* fix: restore not getting all wallet addresses by type
* fix: auto switch node broken
* fix: silent payment txs not being restored
* feat: change scanning to subscription model, sync improvements
* fix: scan re-subscription
* fix: default nodes
* fix: improve scanning by date, fix single block scan
* refactor: common function for input tx selection
* various fixes for build issues
* initial monero.dart implementation
* ...
* multiple wallets
new lib
minor fixes
* other fixes from monero.dart and monero_c
* fix: nodes & build
* update build scripts
fix polyseed
* remove unnecessary code
* Add windows app, build scripts and build guide for it.
* Minor fix in generated monero configs
* fix: send all with multiple outs
* add missing monero_c command
* add android build script
* Merge and fix main
* undo android ndk removal
* Fix modified exception_handler.dart
* Temporarily remove haven
* fix build issues
* fix pr script
* Fixes for build monero.dart (monero_c) for windows.
* monero build script
* wip: ios build script
* refactor: unchanged file
* Added build guides for iOS and macOS. Replaced nproc call on macOS. Added macOS configuration for configure_cake_wallet.sh script.
* Update monero.dart and monero_c versions.
* Add missed windows build scripts
* Update the application configuration for windows build script.
* Update cw_monero pubspec lock file for monero.dart
* Update pr_test_build.yml
* chore: upgrade
* chore: merge changes
* refactor: unchanged files [skip ci]
* Fix conflicts with main
* fix for multiple wallets
* Add tron to windows application configuration.
* Add macOS option for description message in configure_cake_wallet.sh
* Include missed monero dll for windows.
* fix conflicts with main
* Disable haven configuration for iOS as default. Add ability to configure cakewallet for iOS with for configuration script. Remove cw_shared configuration for cw_monero.
* fix: scan fixes, add date, allow sending while scanning
* add missing nano secrets file [skip ci]
* ios library
* don't pull prebuilds android
* Add auto generation of manifest file for android project even for iOS, macOS, Windows.
* feat: sync fixes, sp settings
* feat: fix resyncing
* store crash fix
* make init async so it won't lag
disable print starts
* fix monero_c build issues
* libstdc++
* Fix MacOS saving wallet file issue
Fix Secure Storage issue (somehow)
* update pubspec.lock
* fix build script
* Use dylib as iOS framework. Use custom path for loading of iOS framework for monero.dart. Add script for generate iOS framework for monero wallet.
* fix: date from height logic, status disconnected & chain tip get
* fix: params
* feat: electrum migration if using cake electrum
* fix nodes
update versions
* re-enable tron
* update sp_scanner to work on iOS [skip ci]
* bump monero_c hash
* bump monero_c commit
* bump moneroc version
* bump monero_c commit
* Add ability to build monero wallet lib as universal lib. Update macOS build guide. Change default arch for macOS project to .
* fix: wrong socket for old electrum nodes
* Fix unchecked wallet type call
* get App Dir correctly in default_settings_migration.dart
* handle previous issue with fetching linux documents directory [skip ci]
* backup fix
* fix NTFS issues
* Close the wallet when the wallet gets changed
* fix: double balance
* feat: node domain
* fix: menu name
* bump monero_c commit
* fix: update tip on set scanning
* fix: connection switching back and forth
* feat: check if node is electrs, and supports sp
* chore: fix build
* minor enhancements
* fixes and enhancements
* solve conflicts with main
* Only stop wallet on rename and delete
* fix: status toggle
* minor enhancement
* Monero.com fixes
* bump monero_c commit
* update sp_scanner to include windows and linux
* Update macOS build guide. Change brew dependencies for build unbound locally.
* fix conflicts and update macos build guide
* remove build cache when on gh actions
* update secure storage
* free up even more storage
* free up more storage
* Add initial wownero
* fix conflicts
* fix workflow issue
* build wownero
* ios and windows changes
* macos
* complete wownero flow (app side)
* add keychain group entitlement and update script for RunnerBase on macos
* update secure_storage version to 8.1.0 in configure.dart
* add wownero framework
* update ios builds
* proper path for wownero and monero
* finalizing wownero
* finalizing wownero
* free up even more storage
* revert commenting of build gradle configs
* revert commenting of secrets [skip ci]
* free more storage
* minor fixes
* link android wownero libraries
* bump monero_c commit
* wownero fixes
* rename target
* build_single.sh using clean env
* bump monero_c commit
* minor fix
* Add wownero polyseed
* fix conflicts with main
* fix: wallet seed display
fix: wownero not refreshing
* fix: wallet seed display
fix: wownero not refreshing
* bump monero_c commit
* minor fixes
* fix: incorrectly displaying XMR instead of WOW
* fix: incorrect restore height in wownero
* bump monero_c commit
* Add Inno Setup Script for windows exe installer
* drop libc++_shared.so
* fixes from comments
* Fix CMake for windows
* Merge latest monero dart changes [skip ci]
* bump monero_c commit
* add wownero to build scripts for macos [skip ci]
* add 14 word seed support to wownero
* UI fixes for wownero seed restore
* minor fixes
* reformat code to pass lints
* wownero: fixes
haven: removal popup
* minor iOS fix [skip ci]
* fix: wownero confirmation count (it is spendable after 3 confirms)
fix: transaction history not displaying in WOW and XMR
when tx has 0 confirms,
This is more of a workaround, because I have no idea
why would the cpp code not return pending transaction.
* Update preferences_key.dart [skip ci]
* minor fixes
---------
Co-authored-by: Rafael Saes <git@rafael.saes.dev>
Co-authored-by: Czarek Nakamoto <cyjan@mrcyjanek.net>
Co-authored-by: M <m@cakewallet.com>
Co-authored-by: Konstantin Ullrich <konstantinullrich12@gmail.com>
Co-authored-by: Matthew Fosse <matt@fosse.co>
2024-07-04 19:43:17 +00:00
|
|
|
case WalletType.wownero:
|
2023-09-01 15:06:18 +00:00
|
|
|
_settingsStore.priority[wallet.type] = monero!.getMoneroTransactionPriorityAutomatic();
|
2022-11-03 19:21:35 +00:00
|
|
|
break;
|
|
|
|
case WalletType.bitcoin:
|
2023-09-01 15:06:18 +00:00
|
|
|
_settingsStore.priority[wallet.type] = bitcoin!.getBitcoinTransactionPriorityMedium();
|
2022-11-03 19:21:35 +00:00
|
|
|
break;
|
|
|
|
case WalletType.litecoin:
|
2023-09-01 15:06:18 +00:00
|
|
|
_settingsStore.priority[wallet.type] = bitcoin!.getLitecoinTransactionPriorityMedium();
|
2022-11-03 19:21:35 +00:00
|
|
|
break;
|
2023-10-12 22:50:16 +00:00
|
|
|
case WalletType.ethereum:
|
|
|
|
_settingsStore.priority[wallet.type] = ethereum!.getDefaultTransactionPriority();
|
|
|
|
break;
|
|
|
|
case WalletType.bitcoinCash:
|
|
|
|
_settingsStore.priority[wallet.type] = bitcoinCash!.getDefaultTransactionPriority();
|
|
|
|
break;
|
2023-12-02 02:26:43 +00:00
|
|
|
case WalletType.polygon:
|
|
|
|
_settingsStore.priority[wallet.type] = polygon!.getDefaultTransactionPriority();
|
|
|
|
break;
|
2023-10-15 13:36:05 +00:00
|
|
|
case WalletType.zano:
|
|
|
|
_settingsStore.priority[wallet.type] = monero!.getMoneroTransactionPriorityAutomatic();
|
|
|
|
break;
|
2022-11-03 19:21:35 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-03-01 13:50:31 +00:00
|
|
|
|
2023-08-04 13:49:26 +00:00
|
|
|
void _setProviders() {
|
2023-10-25 20:58:25 +00:00
|
|
|
if (_settingsStore.exchangeStatus == ExchangeApiMode.torOnly)
|
2023-09-01 15:06:18 +00:00
|
|
|
providerList = _allProviders.where((provider) => provider.supportsOnionAddress).toList();
|
2023-10-25 20:58:25 +00:00
|
|
|
else
|
2023-03-01 13:50:31 +00:00
|
|
|
providerList = _allProviders;
|
|
|
|
}
|
2023-03-31 09:45:54 +00:00
|
|
|
|
2023-10-25 20:58:25 +00:00
|
|
|
int get depositMaxDigits => depositCurrency.decimals;
|
2023-03-31 09:45:54 +00:00
|
|
|
|
2023-10-25 20:58:25 +00:00
|
|
|
int get receiveMaxDigits => receiveCurrency.decimals;
|
2024-03-28 12:41:11 +00:00
|
|
|
|
2024-04-25 01:14:11 +00:00
|
|
|
Future<CreateTradeResult> isCanCreateTrade(Trade trade) async {
|
2024-03-28 12:41:11 +00:00
|
|
|
if (trade.provider == ExchangeProviderDescription.thorChain) {
|
|
|
|
final payoutAddress = trade.payoutAddress ?? '';
|
|
|
|
final fromWalletAddress = trade.fromWalletAddress ?? '';
|
|
|
|
final tapRootPattern = RegExp(P2trAddress.regex.pattern);
|
|
|
|
|
|
|
|
if (tapRootPattern.hasMatch(payoutAddress) || tapRootPattern.hasMatch(fromWalletAddress)) {
|
2024-04-25 01:14:11 +00:00
|
|
|
return CreateTradeResult(
|
|
|
|
result: false,
|
|
|
|
errorMessage: S.current.thorchain_taproot_address_not_supported,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
final currenciesToCheckPattern = RegExp('0x[0-9a-zA-Z]');
|
|
|
|
|
|
|
|
// Perform checks for payOutAddress
|
|
|
|
final isPayOutAddressAccordingToPattern = currenciesToCheckPattern.hasMatch(payoutAddress);
|
|
|
|
|
|
|
|
if (isPayOutAddressAccordingToPattern) {
|
|
|
|
final isPayOutAddressEOA = await _isExternallyOwnedAccountAddress(payoutAddress);
|
|
|
|
|
|
|
|
return CreateTradeResult(
|
|
|
|
result: isPayOutAddressEOA,
|
|
|
|
errorMessage:
|
|
|
|
!isPayOutAddressEOA ? S.current.thorchain_contract_address_not_supported : null,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform checks for fromWalletAddress
|
|
|
|
final isFromWalletAddressAddressAccordingToPattern =
|
|
|
|
currenciesToCheckPattern.hasMatch(fromWalletAddress);
|
|
|
|
|
|
|
|
if (isFromWalletAddressAddressAccordingToPattern) {
|
|
|
|
final isFromWalletAddressEOA = await _isExternallyOwnedAccountAddress(fromWalletAddress);
|
|
|
|
|
|
|
|
return CreateTradeResult(
|
|
|
|
result: isFromWalletAddressEOA,
|
|
|
|
errorMessage:
|
|
|
|
!isFromWalletAddressEOA ? S.current.thorchain_contract_address_not_supported : null,
|
|
|
|
);
|
2024-03-28 12:41:11 +00:00
|
|
|
}
|
|
|
|
}
|
2024-04-25 01:14:11 +00:00
|
|
|
return CreateTradeResult(result: true);
|
|
|
|
}
|
|
|
|
|
|
|
|
String _normalizeReceiveCurrency(CryptoCurrency receiveCurrency) {
|
|
|
|
switch (receiveCurrency) {
|
|
|
|
case CryptoCurrency.eth:
|
|
|
|
return 'eth';
|
|
|
|
case CryptoCurrency.maticpoly:
|
|
|
|
return 'polygon';
|
|
|
|
default:
|
|
|
|
return receiveCurrency.tag ?? '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<bool> _isExternallyOwnedAccountAddress(String receivingAddress) async {
|
|
|
|
final normalizedReceiveCurrency = _normalizeReceiveCurrency(receiveCurrency);
|
|
|
|
|
|
|
|
final isEOAAddress = !(await _isContractAddress(normalizedReceiveCurrency, receivingAddress));
|
|
|
|
return isEOAAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<bool> _isContractAddress(String chainName, String contractAddress) async {
|
|
|
|
final httpClient = http.Client();
|
|
|
|
|
|
|
|
final uri = Uri.https(
|
|
|
|
'deep-index.moralis.io',
|
|
|
|
'/api/v2.2/erc20/metadata',
|
|
|
|
{
|
|
|
|
"chain": chainName,
|
|
|
|
"addresses": contractAddress,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
try {
|
|
|
|
final response = await httpClient.get(
|
|
|
|
uri,
|
|
|
|
headers: {
|
|
|
|
"Accept": "application/json",
|
|
|
|
"X-API-Key": secrets.moralisApiKey,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
final decodedResponse = jsonDecode(response.body)[0] as Map<String, dynamic>;
|
|
|
|
|
|
|
|
final name = decodedResponse['name'] as String?;
|
|
|
|
|
|
|
|
bool isContractAddress = name!.isNotEmpty;
|
|
|
|
|
|
|
|
return isContractAddress;
|
|
|
|
} catch (e) {
|
|
|
|
print(e);
|
|
|
|
return false;
|
|
|
|
}
|
2024-03-28 12:41:11 +00:00
|
|
|
}
|
2020-09-02 08:47:41 +00:00
|
|
|
}
|