mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-10 04:34:34 +00:00
Merge branch 'staging' into rylee-tmp
# Conflicts: # lib/main.dart
This commit is contained in:
commit
28421fff6a
32 changed files with 1505 additions and 722 deletions
|
@ -1 +1 @@
|
||||||
Subproject commit b9423d604eca52f3ea3c3f1ded52c0ad07248837
|
Subproject commit 516fa886ab5f94bbc32d29e50711bdccc9cbd154
|
|
@ -31,8 +31,9 @@ import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
|
||||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/restore_from_encrypted_string_view.dart';
|
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/restore_from_encrypted_string_view.dart';
|
||||||
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
|
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
|
||||||
|
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/changenow_initial_load_status.dart';
|
import 'package:stackwallet/providers/exchange/changenow_initial_load_status.dart';
|
||||||
import 'package:stackwallet/providers/exchange/exchange_form_provider.dart';
|
import 'package:stackwallet/providers/exchange/estimate_rate_exchange_form_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart';
|
import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
|
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
|
||||||
import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
|
import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
|
||||||
|
@ -41,7 +42,6 @@ import 'package:stackwallet/providers/global/base_currencies_provider.dart';
|
||||||
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
||||||
import 'package:stackwallet/providers/providers.dart';
|
import 'package:stackwallet/providers/providers.dart';
|
||||||
import 'package:stackwallet/route_generator.dart';
|
import 'package:stackwallet/route_generator.dart';
|
||||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
|
||||||
import 'package:stackwallet/services/debug_service.dart';
|
import 'package:stackwallet/services/debug_service.dart';
|
||||||
import 'package:stackwallet/services/locale_service.dart';
|
import 'package:stackwallet/services/locale_service.dart';
|
||||||
import 'package:stackwallet/services/node_service.dart';
|
import 'package:stackwallet/services/node_service.dart';
|
||||||
|
@ -70,16 +70,18 @@ void main() async {
|
||||||
}
|
}
|
||||||
// FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
// FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
||||||
await Hive.initFlutter(appDirectory.path);
|
await Hive.initFlutter(appDirectory.path);
|
||||||
final isar = await Isar.open(
|
if (!(Logging.isArmLinux || Logging.isTestEnv)) {
|
||||||
[LogSchema],
|
final isar = await Isar.open(
|
||||||
directory: appDirectory.path,
|
[LogSchema],
|
||||||
inspector: false,
|
directory: appDirectory.path,
|
||||||
);
|
inspector: false,
|
||||||
await Logging.instance.init(isar);
|
);
|
||||||
await DebugService.instance.init(isar);
|
await Logging.instance.init(isar);
|
||||||
|
await DebugService.instance.init(isar);
|
||||||
|
|
||||||
// clear out all info logs on startup. No need to await and block
|
// clear out all info logs on startup. No need to await and block
|
||||||
DebugService.instance.purgeInfoLogs();
|
unawaited(DebugService.instance.purgeInfoLogs());
|
||||||
|
}
|
||||||
|
|
||||||
// Registering Transaction Model Adapters
|
// Registering Transaction Model Adapters
|
||||||
Hive.registerAdapter(TransactionDataAdapter());
|
Hive.registerAdapter(TransactionDataAdapter());
|
||||||
|
@ -193,20 +195,21 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
||||||
NotificationApi.prefs = _prefs;
|
NotificationApi.prefs = _prefs;
|
||||||
NotificationApi.notificationsService = _notificationsService;
|
NotificationApi.notificationsService = _notificationsService;
|
||||||
|
|
||||||
ref.read(baseCurrenciesProvider).update();
|
unawaited(ref.read(baseCurrenciesProvider).update());
|
||||||
|
|
||||||
await _nodeService.updateDefaults();
|
await _nodeService.updateDefaults();
|
||||||
await _notificationsService.init(
|
await _notificationsService.init(
|
||||||
nodeService: _nodeService,
|
nodeService: _nodeService,
|
||||||
tradesService: _tradesService,
|
tradesService: _tradesService,
|
||||||
prefs: _prefs,
|
prefs: _prefs,
|
||||||
|
changeNow: ref.read(changeNowProvider),
|
||||||
);
|
);
|
||||||
await _prefs.init();
|
await _prefs.init();
|
||||||
ref.read(priceAnd24hChangeNotifierProvider).start(true);
|
ref.read(priceAnd24hChangeNotifierProvider).start(true);
|
||||||
await _wallets.load(_prefs);
|
await _wallets.load(_prefs);
|
||||||
loadingCompleter.complete();
|
loadingCompleter.complete();
|
||||||
// TODO: this currently hangs for a long time
|
// TODO: this should probably run unawaited. Keep commented out for now as proper community nodes ui hasn't been implemented yet
|
||||||
// await _nodeService.updateCommunityNodes();
|
// unawaited(_nodeService.updateCommunityNodes());
|
||||||
|
|
||||||
if (_prefs.isAutoBackupEnabled) {
|
if (_prefs.isAutoBackupEnabled) {
|
||||||
switch (_prefs.backupFrequencyType) {
|
switch (_prefs.backupFrequencyType) {
|
||||||
|
@ -216,7 +219,7 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
||||||
.startPeriodicBackupTimer(duration: const Duration(minutes: 10));
|
.startPeriodicBackupTimer(duration: const Duration(minutes: 10));
|
||||||
break;
|
break;
|
||||||
case BackupFrequencyType.everyAppStart:
|
case BackupFrequencyType.everyAppStart:
|
||||||
ref.read(autoSWBServiceProvider).doBackup();
|
unawaited(ref.read(autoSWBServiceProvider).doBackup());
|
||||||
break;
|
break;
|
||||||
case BackupFrequencyType.afterClosingAWallet:
|
case BackupFrequencyType.afterClosingAWallet:
|
||||||
// ignore this case here
|
// ignore this case here
|
||||||
|
@ -236,8 +239,9 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
||||||
.isNotEmpty) {
|
.isNotEmpty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final response = await ChangeNow.getAvailableCurrencies();
|
final response = await ref.read(changeNowProvider).getAvailableCurrencies();
|
||||||
final response2 = await ChangeNow.getAvailableFloatingRatePairs();
|
final response2 =
|
||||||
|
await ref.read(changeNowProvider).getAvailableFloatingRatePairs();
|
||||||
if (response.value != null) {
|
if (response.value != null) {
|
||||||
ref.read(availableChangeNowCurrenciesStateProvider.state).state =
|
ref.read(availableChangeNowCurrenciesStateProvider.state).state =
|
||||||
response.value!;
|
response.value!;
|
||||||
|
@ -248,13 +252,13 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
||||||
if (response.value!.length > 1) {
|
if (response.value!.length > 1) {
|
||||||
if (ref.read(estimatedRateExchangeFormProvider).from == null) {
|
if (ref.read(estimatedRateExchangeFormProvider).from == null) {
|
||||||
if (response.value!.where((e) => e.ticker == "btc").isNotEmpty) {
|
if (response.value!.where((e) => e.ticker == "btc").isNotEmpty) {
|
||||||
ref.read(estimatedRateExchangeFormProvider).updateFrom(
|
await ref.read(estimatedRateExchangeFormProvider).updateFrom(
|
||||||
response.value!.firstWhere((e) => e.ticker == "btc"), false);
|
response.value!.firstWhere((e) => e.ticker == "btc"), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ref.read(estimatedRateExchangeFormProvider).to == null) {
|
if (ref.read(estimatedRateExchangeFormProvider).to == null) {
|
||||||
if (response.value!.where((e) => e.ticker == "doge").isNotEmpty) {
|
if (response.value!.where((e) => e.ticker == "doge").isNotEmpty) {
|
||||||
ref.read(estimatedRateExchangeFormProvider).updateTo(
|
await ref.read(estimatedRateExchangeFormProvider).updateTo(
|
||||||
response.value!.firstWhere((e) => e.ticker == "doge"), false);
|
response.value!.firstWhere((e) => e.ticker == "doge"), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,7 +292,8 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final response3 = await ChangeNow.getAvailableFixedRateMarkets();
|
final response3 =
|
||||||
|
await ref.read(changeNowProvider).getAvailableFixedRateMarkets();
|
||||||
if (response3.value != null) {
|
if (response3.value != null) {
|
||||||
ref.read(fixedRateMarketPairsStateProvider.state).state =
|
ref.read(fixedRateMarketPairsStateProvider.state).state =
|
||||||
response3.value!;
|
response3.value!;
|
||||||
|
@ -297,7 +302,7 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
||||||
final matchingMarkets =
|
final matchingMarkets =
|
||||||
response3.value!.where((e) => e.to == "doge" && e.from == "btc");
|
response3.value!.where((e) => e.to == "doge" && e.from == "btc");
|
||||||
if (matchingMarkets.isNotEmpty) {
|
if (matchingMarkets.isNotEmpty) {
|
||||||
ref
|
await ref
|
||||||
.read(fixedRateExchangeFormProvider)
|
.read(fixedRateExchangeFormProvider)
|
||||||
.updateMarket(matchingMarkets.first, true);
|
.updateMarket(matchingMarkets.first, true);
|
||||||
}
|
}
|
||||||
|
@ -443,7 +448,7 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Navigator.push(
|
unawaited(Navigator.push(
|
||||||
navigatorKey.currentContext!,
|
navigatorKey.currentContext!,
|
||||||
RouteGenerator.getRoute(
|
RouteGenerator.getRoute(
|
||||||
shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute,
|
shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute,
|
||||||
|
@ -458,7 +463,7 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
||||||
),
|
),
|
||||||
settings: const RouteSettings(name: "/swbrestorelockscreen"),
|
settings: const RouteSettings(name: "/swbrestorelockscreen"),
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,9 @@ import 'package:decimal/decimal.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:stackwallet/models/exchange/change_now/currency.dart';
|
import 'package:stackwallet/models/exchange/change_now/currency.dart';
|
||||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
import 'package:stackwallet/services/change_now/change_now.dart';
|
||||||
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
|
||||||
class ExchangeFormState extends ChangeNotifier {
|
class EstimatedRateExchangeFormState extends ChangeNotifier {
|
||||||
Decimal? _fromAmount;
|
Decimal? _fromAmount;
|
||||||
Decimal? _toAmount;
|
Decimal? _toAmount;
|
||||||
|
|
||||||
|
@ -23,6 +24,18 @@ class ExchangeFormState extends ChangeNotifier {
|
||||||
_to = to;
|
_to = to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearAmounts(bool shouldNotifyListeners) {
|
||||||
|
_fromAmount = null;
|
||||||
|
_toAmount = null;
|
||||||
|
_minFromAmount = null;
|
||||||
|
_minToAmount = null;
|
||||||
|
rate = null;
|
||||||
|
|
||||||
|
if (shouldNotifyListeners) {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> swap() async {
|
Future<void> swap() async {
|
||||||
final Decimal? newToAmount = _fromAmount;
|
final Decimal? newToAmount = _fromAmount;
|
||||||
final Decimal? newFromAmount = _toAmount;
|
final Decimal? newFromAmount = _toAmount;
|
||||||
|
@ -30,9 +43,9 @@ class ExchangeFormState extends ChangeNotifier {
|
||||||
final Decimal? newMinFromAmount = _minToAmount;
|
final Decimal? newMinFromAmount = _minToAmount;
|
||||||
final Decimal? newMinToAmount = _minFromAmount;
|
final Decimal? newMinToAmount = _minFromAmount;
|
||||||
|
|
||||||
final Decimal? newRate = rate == null
|
// final Decimal? newRate = rate == null
|
||||||
? rate
|
// ? rate
|
||||||
: (Decimal.one / rate!).toDecimal(scaleOnInfinitePrecision: 12);
|
// : (Decimal.one / rate!).toDecimal(scaleOnInfinitePrecision: 12);
|
||||||
|
|
||||||
final Currency? newTo = from;
|
final Currency? newTo = from;
|
||||||
final Currency? newFrom = to;
|
final Currency? newFrom = to;
|
||||||
|
@ -43,125 +56,171 @@ class ExchangeFormState extends ChangeNotifier {
|
||||||
_minToAmount = newMinToAmount;
|
_minToAmount = newMinToAmount;
|
||||||
_minFromAmount = newMinFromAmount;
|
_minFromAmount = newMinFromAmount;
|
||||||
|
|
||||||
rate = newRate;
|
// rate = newRate;
|
||||||
|
|
||||||
_to = newTo;
|
_to = newTo;
|
||||||
_from = newFrom;
|
_from = newFrom;
|
||||||
|
|
||||||
|
await _updateMinFromAmount(shouldNotifyListeners: false);
|
||||||
|
|
||||||
|
rate = null;
|
||||||
|
|
||||||
|
if (_fromAmount != null) {
|
||||||
|
Decimal? amt;
|
||||||
|
if (_minFromAmount != null) {
|
||||||
|
if (_minFromAmount! > _fromAmount!) {
|
||||||
|
amt = await getStandardEstimatedToAmount(
|
||||||
|
fromAmount: _minFromAmount!, from: _from!, to: _to!);
|
||||||
|
if (amt != null) {
|
||||||
|
rate =
|
||||||
|
(amt / _minFromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
amt = await getStandardEstimatedToAmount(
|
||||||
|
fromAmount: _fromAmount!, from: _from!, to: _to!);
|
||||||
|
if (amt != null) {
|
||||||
|
rate = (amt / _fromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rate != null) {
|
||||||
|
_toAmount = (_fromAmount! * rate!);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_minFromAmount != null) {
|
||||||
|
Decimal? amt = await getStandardEstimatedToAmount(
|
||||||
|
fromAmount: _minFromAmount!, from: _from!, to: _to!);
|
||||||
|
if (amt != null) {
|
||||||
|
rate =
|
||||||
|
(amt / _minFromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
String get fromAmountString =>
|
String get fromAmountString =>
|
||||||
_fromAmount == null ? "-" : _fromAmount!.toStringAsFixed(8);
|
_fromAmount == null ? "" : _fromAmount!.toStringAsFixed(8);
|
||||||
String get toAmountString =>
|
String get toAmountString =>
|
||||||
_toAmount == null ? "-" : _toAmount!.toStringAsFixed(8);
|
_toAmount == null ? "" : _toAmount!.toStringAsFixed(8);
|
||||||
|
|
||||||
Future<void> updateTo(Currency to, bool shouldNotifyListeners) async {
|
Future<void> updateTo(Currency to, bool shouldNotifyListeners) async {
|
||||||
_to = to;
|
try {
|
||||||
if (_from == null) {
|
_to = to;
|
||||||
|
if (_from == null) {
|
||||||
|
rate = null;
|
||||||
|
notifyListeners();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _updateMinFromAmount(shouldNotifyListeners: shouldNotifyListeners);
|
||||||
|
// await _updateMinToAmount(shouldNotifyListeners: shouldNotifyListeners);
|
||||||
|
|
||||||
rate = null;
|
rate = null;
|
||||||
notifyListeners();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _updateMinFromAmount(shouldNotifyListeners: shouldNotifyListeners);
|
if (_fromAmount != null) {
|
||||||
// await _updateMinToAmount(shouldNotifyListeners: shouldNotifyListeners);
|
Decimal? amt;
|
||||||
|
if (_minFromAmount != null) {
|
||||||
rate = null;
|
if (_minFromAmount! > _fromAmount!) {
|
||||||
|
amt = await getStandardEstimatedToAmount(
|
||||||
if (_fromAmount != null) {
|
fromAmount: _minFromAmount!, from: _from!, to: _to!);
|
||||||
Decimal? amt;
|
if (amt != null) {
|
||||||
if (_minFromAmount != null) {
|
rate = (amt / _minFromAmount!)
|
||||||
if (_minFromAmount! > _fromAmount!) {
|
.toDecimal(scaleOnInfinitePrecision: 12);
|
||||||
amt = await getStandardEstimatedToAmount(
|
}
|
||||||
|
debugPrint("A");
|
||||||
|
} else {
|
||||||
|
amt = await getStandardEstimatedToAmount(
|
||||||
|
fromAmount: _fromAmount!, from: _from!, to: _to!);
|
||||||
|
if (amt != null) {
|
||||||
|
rate =
|
||||||
|
(amt / _fromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
||||||
|
}
|
||||||
|
debugPrint("B");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rate != null) {
|
||||||
|
_toAmount = (_fromAmount! * rate!);
|
||||||
|
}
|
||||||
|
debugPrint("C");
|
||||||
|
} else {
|
||||||
|
if (_minFromAmount != null) {
|
||||||
|
Decimal? amt = await getStandardEstimatedToAmount(
|
||||||
fromAmount: _minFromAmount!, from: _from!, to: _to!);
|
fromAmount: _minFromAmount!, from: _from!, to: _to!);
|
||||||
if (amt != null) {
|
if (amt != null) {
|
||||||
rate =
|
rate =
|
||||||
(amt / _minFromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
(amt / _minFromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
||||||
}
|
}
|
||||||
debugPrint("A");
|
debugPrint("D");
|
||||||
} else {
|
|
||||||
amt = await getStandardEstimatedToAmount(
|
|
||||||
fromAmount: _fromAmount!, from: _from!, to: _to!);
|
|
||||||
if (amt != null) {
|
|
||||||
rate = (amt / _fromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
|
||||||
}
|
|
||||||
debugPrint("B");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rate != null) {
|
|
||||||
_toAmount = (_fromAmount! * rate!);
|
|
||||||
}
|
|
||||||
debugPrint("C");
|
|
||||||
} else {
|
|
||||||
if (_minFromAmount != null) {
|
|
||||||
Decimal? amt = await getStandardEstimatedToAmount(
|
|
||||||
fromAmount: _minFromAmount!, from: _from!, to: _to!);
|
|
||||||
if (amt != null) {
|
|
||||||
rate =
|
|
||||||
(amt / _minFromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
|
||||||
}
|
|
||||||
debugPrint("D");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debugPrint(
|
debugPrint(
|
||||||
"_updated TO: _from=${_from!.ticker} _to=${_to!.ticker} _fromAmount=$_fromAmount _toAmount=$_toAmount rate:$rate");
|
"_updated TO: _from=${_from!.ticker} _to=${_to!.ticker} _fromAmount=$_fromAmount _toAmount=$_toAmount rate:$rate");
|
||||||
|
|
||||||
if (shouldNotifyListeners) {
|
if (shouldNotifyListeners) {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateFrom(Currency from, bool shouldNotifyListeners) async {
|
Future<void> updateFrom(Currency from, bool shouldNotifyListeners) async {
|
||||||
_from = from;
|
try {
|
||||||
|
_from = from;
|
||||||
|
|
||||||
|
if (_to == null) {
|
||||||
|
rate = null;
|
||||||
|
notifyListeners();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _updateMinFromAmount(shouldNotifyListeners: shouldNotifyListeners);
|
||||||
|
|
||||||
if (_to == null) {
|
|
||||||
rate = null;
|
rate = null;
|
||||||
notifyListeners();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _updateMinFromAmount(shouldNotifyListeners: shouldNotifyListeners);
|
if (_fromAmount != null) {
|
||||||
|
Decimal? amt;
|
||||||
rate = null;
|
if (_minFromAmount != null) {
|
||||||
|
if (_minFromAmount! > _fromAmount!) {
|
||||||
if (_fromAmount != null) {
|
amt = await getStandardEstimatedToAmount(
|
||||||
Decimal? amt;
|
fromAmount: _minFromAmount!, from: _from!, to: _to!);
|
||||||
if (_minFromAmount != null) {
|
if (amt != null) {
|
||||||
if (_minFromAmount! > _fromAmount!) {
|
rate = (amt / _minFromAmount!)
|
||||||
amt = await getStandardEstimatedToAmount(
|
.toDecimal(scaleOnInfinitePrecision: 12);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
amt = await getStandardEstimatedToAmount(
|
||||||
|
fromAmount: _fromAmount!, from: _from!, to: _to!);
|
||||||
|
if (amt != null) {
|
||||||
|
rate =
|
||||||
|
(amt / _fromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rate != null) {
|
||||||
|
_toAmount = (_fromAmount! * rate!);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_minFromAmount != null) {
|
||||||
|
Decimal? amt = await getStandardEstimatedToAmount(
|
||||||
fromAmount: _minFromAmount!, from: _from!, to: _to!);
|
fromAmount: _minFromAmount!, from: _from!, to: _to!);
|
||||||
if (amt != null) {
|
if (amt != null) {
|
||||||
rate =
|
rate =
|
||||||
(amt / _minFromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
(amt / _minFromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
amt = await getStandardEstimatedToAmount(
|
|
||||||
fromAmount: _fromAmount!, from: _from!, to: _to!);
|
|
||||||
if (amt != null) {
|
|
||||||
rate = (amt / _fromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rate != null) {
|
|
||||||
_toAmount = (_fromAmount! * rate!);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (_minFromAmount != null) {
|
|
||||||
Decimal? amt = await getStandardEstimatedToAmount(
|
|
||||||
fromAmount: _minFromAmount!, from: _from!, to: _to!);
|
|
||||||
if (amt != null) {
|
|
||||||
rate =
|
|
||||||
(amt / _minFromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debugPrint(
|
debugPrint(
|
||||||
"_updated FROM: _from=${_from!.ticker} _to=${_to!.ticker} _fromAmount=$_fromAmount _toAmount=$_toAmount rate:$rate");
|
"_updated FROM: _from=${_from!.ticker} _to=${_to!.ticker} _fromAmount=$_fromAmount _toAmount=$_toAmount rate:$rate");
|
||||||
if (shouldNotifyListeners) {
|
if (shouldNotifyListeners) {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +329,7 @@ class ExchangeFormState extends ChangeNotifier {
|
||||||
required Currency from,
|
required Currency from,
|
||||||
required Currency to,
|
required Currency to,
|
||||||
}) async {
|
}) async {
|
||||||
final response = await ChangeNow.getEstimatedExchangeAmount(
|
final response = await ChangeNow.instance.getEstimatedExchangeAmount(
|
||||||
fromTicker: from.ticker, toTicker: to.ticker, fromAmount: fromAmount);
|
fromTicker: from.ticker, toTicker: to.ticker, fromAmount: fromAmount);
|
||||||
|
|
||||||
if (response.value != null) {
|
if (response.value != null) {
|
||||||
|
@ -286,8 +345,8 @@ class ExchangeFormState extends ChangeNotifier {
|
||||||
required Currency from,
|
required Currency from,
|
||||||
required Currency to,
|
required Currency to,
|
||||||
}) async {
|
}) async {
|
||||||
final response = await ChangeNow.getMinimalExchangeAmount(
|
final response = await ChangeNow.instance
|
||||||
fromTicker: from.ticker, toTicker: to.ticker);
|
.getMinimalExchangeAmount(fromTicker: from.ticker, toTicker: to.ticker);
|
||||||
|
|
||||||
if (response.value != null) {
|
if (response.value != null) {
|
||||||
return response.value!;
|
return response.value!;
|
|
@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
|
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
|
||||||
|
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/changenow_initial_load_status.dart';
|
import 'package:stackwallet/providers/exchange/changenow_initial_load_status.dart';
|
||||||
import 'package:stackwallet/providers/exchange/exchange_form_provider.dart';
|
import 'package:stackwallet/providers/exchange/estimate_rate_exchange_form_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart';
|
import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
|
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
|
||||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
|
||||||
import 'package:stackwallet/utilities/cfcolors.dart';
|
import 'package:stackwallet/utilities/cfcolors.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
@ -38,7 +38,8 @@ class _ExchangeLoadingOverlayViewState
|
||||||
ref.read(changeNowFixedInitialLoadStatusStateProvider.state).state =
|
ref.read(changeNowFixedInitialLoadStatusStateProvider.state).state =
|
||||||
ChangeNowLoadStatus.loading;
|
ChangeNowLoadStatus.loading;
|
||||||
|
|
||||||
final response3 = await ChangeNow.getAvailableFixedRateMarkets();
|
final response3 =
|
||||||
|
await ref.read(changeNowProvider).getAvailableFixedRateMarkets();
|
||||||
if (response3.value != null) {
|
if (response3.value != null) {
|
||||||
ref.read(fixedRateMarketPairsStateProvider.state).state =
|
ref.read(fixedRateMarketPairsStateProvider.state).state =
|
||||||
response3.value!;
|
response3.value!;
|
||||||
|
@ -47,7 +48,7 @@ class _ExchangeLoadingOverlayViewState
|
||||||
final matchingMarkets =
|
final matchingMarkets =
|
||||||
response3.value!.where((e) => e.to == "doge" && e.from == "btc");
|
response3.value!.where((e) => e.to == "doge" && e.from == "btc");
|
||||||
if (matchingMarkets.isNotEmpty) {
|
if (matchingMarkets.isNotEmpty) {
|
||||||
ref
|
await ref
|
||||||
.read(fixedRateExchangeFormProvider)
|
.read(fixedRateExchangeFormProvider)
|
||||||
.updateMarket(matchingMarkets.first, true);
|
.updateMarket(matchingMarkets.first, true);
|
||||||
}
|
}
|
||||||
|
@ -78,8 +79,9 @@ class _ExchangeLoadingOverlayViewState
|
||||||
ref.read(changeNowEstimatedInitialLoadStatusStateProvider.state).state =
|
ref.read(changeNowEstimatedInitialLoadStatusStateProvider.state).state =
|
||||||
ChangeNowLoadStatus.loading;
|
ChangeNowLoadStatus.loading;
|
||||||
|
|
||||||
final response = await ChangeNow.getAvailableCurrencies();
|
final response = await ref.read(changeNowProvider).getAvailableCurrencies();
|
||||||
final response2 = await ChangeNow.getAvailableFloatingRatePairs();
|
final response2 =
|
||||||
|
await ref.read(changeNowProvider).getAvailableFloatingRatePairs();
|
||||||
if (response.value != null) {
|
if (response.value != null) {
|
||||||
ref.read(availableChangeNowCurrenciesStateProvider.state).state =
|
ref.read(availableChangeNowCurrenciesStateProvider.state).state =
|
||||||
response.value!;
|
response.value!;
|
||||||
|
@ -90,13 +92,13 @@ class _ExchangeLoadingOverlayViewState
|
||||||
if (response.value!.length > 1) {
|
if (response.value!.length > 1) {
|
||||||
if (ref.read(estimatedRateExchangeFormProvider).from == null) {
|
if (ref.read(estimatedRateExchangeFormProvider).from == null) {
|
||||||
if (response.value!.where((e) => e.ticker == "btc").isNotEmpty) {
|
if (response.value!.where((e) => e.ticker == "btc").isNotEmpty) {
|
||||||
ref.read(estimatedRateExchangeFormProvider).updateFrom(
|
await ref.read(estimatedRateExchangeFormProvider).updateFrom(
|
||||||
response.value!.firstWhere((e) => e.ticker == "btc"), false);
|
response.value!.firstWhere((e) => e.ticker == "btc"), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ref.read(estimatedRateExchangeFormProvider).to == null) {
|
if (ref.read(estimatedRateExchangeFormProvider).to == null) {
|
||||||
if (response.value!.where((e) => e.ticker == "doge").isNotEmpty) {
|
if (response.value!.where((e) => e.ticker == "doge").isNotEmpty) {
|
||||||
ref.read(estimatedRateExchangeFormProvider).updateTo(
|
await ref.read(estimatedRateExchangeFormProvider).updateTo(
|
||||||
response.value!.firstWhere((e) => e.ticker == "doge"), false);
|
response.value!.firstWhere((e) => e.ticker == "doge"), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/models/exchange/change_now/change_now_response.dart';
|
import 'package:stackwallet/models/exchange/change_now/change_now_response.dart';
|
||||||
|
@ -6,8 +8,8 @@ import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_4_view.dart';
|
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_4_view.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
|
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart';
|
import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart';
|
||||||
|
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||||
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
||||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
|
||||||
import 'package:stackwallet/services/notifications_api.dart';
|
import 'package:stackwallet/services/notifications_api.dart';
|
||||||
import 'package:stackwallet/utilities/assets.dart';
|
import 'package:stackwallet/utilities/assets.dart';
|
||||||
import 'package:stackwallet/utilities/cfcolors.dart';
|
import 'package:stackwallet/utilities/cfcolors.dart';
|
||||||
|
@ -219,35 +221,39 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
||||||
response;
|
response;
|
||||||
if (model.rateType ==
|
if (model.rateType ==
|
||||||
ExchangeRateType.estimated) {
|
ExchangeRateType.estimated) {
|
||||||
response = await ChangeNow
|
response = await ref
|
||||||
|
.read(changeNowProvider)
|
||||||
.createStandardExchangeTransaction(
|
.createStandardExchangeTransaction(
|
||||||
fromTicker: model.sendTicker,
|
fromTicker: model.sendTicker,
|
||||||
toTicker: model.receiveTicker,
|
toTicker: model.receiveTicker,
|
||||||
receivingAddress: model.recipientAddress!,
|
receivingAddress:
|
||||||
amount: model.sendAmount,
|
model.recipientAddress!,
|
||||||
refundAddress: model.refundAddress!,
|
amount: model.sendAmount,
|
||||||
);
|
refundAddress: model.refundAddress!,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
response = await ChangeNow
|
response = await ref
|
||||||
|
.read(changeNowProvider)
|
||||||
.createFixedRateExchangeTransaction(
|
.createFixedRateExchangeTransaction(
|
||||||
fromTicker: model.sendTicker,
|
fromTicker: model.sendTicker,
|
||||||
toTicker: model.receiveTicker,
|
toTicker: model.receiveTicker,
|
||||||
receivingAddress: model.recipientAddress!,
|
receivingAddress:
|
||||||
amount: model.sendAmount,
|
model.recipientAddress!,
|
||||||
refundAddress: model.refundAddress!,
|
amount: model.sendAmount,
|
||||||
rateId: model.rateId!,
|
refundAddress: model.refundAddress!,
|
||||||
);
|
rateId: model.rateId!,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.value == null) {
|
if (response.value == null) {
|
||||||
showDialog<void>(
|
unawaited(showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
builder: (_) => StackDialog(
|
builder: (_) => StackDialog(
|
||||||
title: "Failed to create trade",
|
title: "Failed to create trade",
|
||||||
message: response.exception?.toString(),
|
message: response.exception?.toString(),
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,8 +263,9 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
||||||
shouldNotifyListeners: true,
|
shouldNotifyListeners: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
final statusResponse =
|
final statusResponse = await ref
|
||||||
await ChangeNow.getTransactionStatus(
|
.read(changeNowProvider)
|
||||||
|
.getTransactionStatus(
|
||||||
id: response.value!.id);
|
id: response.value!.id);
|
||||||
|
|
||||||
debugPrint("WTF: $statusResponse");
|
debugPrint("WTF: $statusResponse");
|
||||||
|
@ -278,7 +285,7 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
||||||
status += " for deposit";
|
status += " for deposit";
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationApi.showNotification(
|
unawaited(NotificationApi.showNotification(
|
||||||
changeNowId: model.trade!.id,
|
changeNowId: model.trade!.id,
|
||||||
title: status,
|
title: status,
|
||||||
body: "Trade ID ${model.trade!.id}",
|
body: "Trade ID ${model.trade!.id}",
|
||||||
|
@ -287,13 +294,13 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
||||||
date: model.trade!.date,
|
date: model.trade!.date,
|
||||||
shouldWatchForUpdates: true,
|
shouldWatchForUpdates: true,
|
||||||
coinName: "coinName",
|
coinName: "coinName",
|
||||||
);
|
));
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
Navigator.of(context).pushNamed(
|
unawaited(Navigator.of(context).pushNamed(
|
||||||
Step4View.routeName,
|
Step4View.routeName,
|
||||||
arguments: model,
|
arguments: model,
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
|
|
|
@ -13,10 +13,10 @@ import 'package:stackwallet/pages/exchange_view/send_from_view.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart';
|
import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart';
|
||||||
import 'package:stackwallet/pages/home_view/home_view.dart';
|
import 'package:stackwallet/pages/home_view/home_view.dart';
|
||||||
import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dialog.dart';
|
import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dialog.dart';
|
||||||
|
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/exchange_send_from_wallet_id_provider.dart';
|
import 'package:stackwallet/providers/exchange/exchange_send_from_wallet_id_provider.dart';
|
||||||
import 'package:stackwallet/providers/providers.dart';
|
import 'package:stackwallet/providers/providers.dart';
|
||||||
import 'package:stackwallet/route_generator.dart';
|
import 'package:stackwallet/route_generator.dart';
|
||||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
|
||||||
import 'package:stackwallet/utilities/assets.dart';
|
import 'package:stackwallet/utilities/assets.dart';
|
||||||
import 'package:stackwallet/utilities/cfcolors.dart';
|
import 'package:stackwallet/utilities/cfcolors.dart';
|
||||||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||||
|
@ -69,8 +69,9 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _updateStatus() async {
|
Future<void> _updateStatus() async {
|
||||||
final statusResponse =
|
final statusResponse = await ref
|
||||||
await ChangeNow.getTransactionStatus(id: model.trade!.id);
|
.read(changeNowProvider)
|
||||||
|
.getTransactionStatus(id: model.trade!.id);
|
||||||
String status = "Waiting";
|
String status = "Waiting";
|
||||||
if (statusResponse.value != null) {
|
if (statusResponse.value != null) {
|
||||||
_status = statusResponse.value!.status;
|
_status = statusResponse.value!.status;
|
||||||
|
@ -214,11 +215,11 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
||||||
final data = ClipboardData(
|
final data = ClipboardData(
|
||||||
text: model.sendAmount.toString());
|
text: model.sendAmount.toString());
|
||||||
await clipboard.setData(data);
|
await clipboard.setData(data);
|
||||||
showFloatingFlushBar(
|
unawaited(showFloatingFlushBar(
|
||||||
type: FlushBarType.info,
|
type: FlushBarType.info,
|
||||||
message: "Copied to clipboard",
|
message: "Copied to clipboard",
|
||||||
context: context,
|
context: context,
|
||||||
);
|
));
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
|
@ -271,11 +272,11 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
||||||
final data = ClipboardData(
|
final data = ClipboardData(
|
||||||
text: model.trade!.payinAddress);
|
text: model.trade!.payinAddress);
|
||||||
await clipboard.setData(data);
|
await clipboard.setData(data);
|
||||||
showFloatingFlushBar(
|
unawaited(showFloatingFlushBar(
|
||||||
type: FlushBarType.info,
|
type: FlushBarType.info,
|
||||||
message: "Copied to clipboard",
|
message: "Copied to clipboard",
|
||||||
context: context,
|
context: context,
|
||||||
);
|
));
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
|
@ -331,11 +332,11 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
||||||
final data =
|
final data =
|
||||||
ClipboardData(text: model.trade!.id);
|
ClipboardData(text: model.trade!.id);
|
||||||
await clipboard.setData(data);
|
await clipboard.setData(data);
|
||||||
showFloatingFlushBar(
|
unawaited(showFloatingFlushBar(
|
||||||
type: FlushBarType.info,
|
type: FlushBarType.info,
|
||||||
message: "Copied to clipboard",
|
message: "Copied to clipboard",
|
||||||
context: context,
|
context: context,
|
||||||
);
|
));
|
||||||
},
|
},
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
Assets.svg.copy,
|
Assets.svg.copy,
|
||||||
|
@ -487,7 +488,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
||||||
try {
|
try {
|
||||||
bool wasCancelled = false;
|
bool wasCancelled = false;
|
||||||
|
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
useSafeArea: false,
|
useSafeArea: false,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
|
@ -500,7 +501,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
));
|
||||||
|
|
||||||
final txData =
|
final txData =
|
||||||
await manager.prepareSend(
|
await manager.prepareSend(
|
||||||
|
@ -524,7 +525,8 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
||||||
txData["address"] = address;
|
txData["address"] = address;
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
Navigator.of(context).push(
|
unawaited(
|
||||||
|
Navigator.of(context).push(
|
||||||
RouteGenerator.getRoute(
|
RouteGenerator.getRoute(
|
||||||
shouldUseMaterialRoute:
|
shouldUseMaterialRoute:
|
||||||
RouteGenerator
|
RouteGenerator
|
||||||
|
@ -543,7 +545,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
||||||
.routeName,
|
.routeName,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -551,7 +553,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
||||||
// pop building dialog
|
// pop building dialog
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
useSafeArea: false,
|
useSafeArea: false,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
|
@ -584,7 +586,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
));
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:decimal/decimal.dart';
|
import 'package:decimal/decimal.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
@ -16,20 +18,21 @@ import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.
|
||||||
import 'package:stackwallet/pages/exchange_view/trade_details_view.dart';
|
import 'package:stackwallet/pages/exchange_view/trade_details_view.dart';
|
||||||
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
|
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
|
||||||
|
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/changenow_initial_load_status.dart';
|
import 'package:stackwallet/providers/exchange/changenow_initial_load_status.dart';
|
||||||
import 'package:stackwallet/providers/exchange/exchange_form_provider.dart';
|
import 'package:stackwallet/providers/exchange/estimate_rate_exchange_form_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/exchange_send_from_wallet_id_provider.dart';
|
import 'package:stackwallet/providers/exchange/exchange_send_from_wallet_id_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart';
|
import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
|
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/trade_sent_from_stack_lookup_provider.dart';
|
import 'package:stackwallet/providers/exchange/trade_sent_from_stack_lookup_provider.dart';
|
||||||
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
||||||
import 'package:stackwallet/providers/providers.dart';
|
import 'package:stackwallet/providers/providers.dart';
|
||||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
|
||||||
import 'package:stackwallet/utilities/assets.dart';
|
import 'package:stackwallet/utilities/assets.dart';
|
||||||
import 'package:stackwallet/utilities/cfcolors.dart';
|
import 'package:stackwallet/utilities/cfcolors.dart';
|
||||||
import 'package:stackwallet/utilities/constants.dart';
|
import 'package:stackwallet/utilities/constants.dart';
|
||||||
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
||||||
import 'package:stackwallet/widgets/loading_indicator.dart';
|
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||||
import 'package:stackwallet/widgets/trade_card.dart';
|
import 'package:stackwallet/widgets/trade_card.dart';
|
||||||
|
@ -55,6 +58,23 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
_sendFocusNode.unfocus();
|
_sendFocusNode.unfocus();
|
||||||
_receiveFocusNode.unfocus();
|
_receiveFocusNode.unfocus();
|
||||||
|
|
||||||
|
unawaited(
|
||||||
|
showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (_) => WillPopScope(
|
||||||
|
onWillPop: () async => false,
|
||||||
|
child: Container(
|
||||||
|
color: CFColors.stackAccent.withOpacity(0.8),
|
||||||
|
child: const CustomLoadingOverlay(
|
||||||
|
message: "Updating exchange rate",
|
||||||
|
eventBus: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
if (ref.watch(prefsChangeNotifierProvider
|
if (ref.watch(prefsChangeNotifierProvider
|
||||||
.select((pref) => pref.exchangeRateType)) ==
|
.select((pref) => pref.exchangeRateType)) ==
|
||||||
ExchangeRateType.estimated) {
|
ExchangeRateType.estimated) {
|
||||||
|
@ -74,6 +94,9 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
_swapLock = false;
|
_swapLock = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +220,17 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
void initState() {
|
void initState() {
|
||||||
_sendController = TextEditingController();
|
_sendController = TextEditingController();
|
||||||
_receiveController = TextEditingController();
|
_receiveController = TextEditingController();
|
||||||
|
|
||||||
|
final isEstimated =
|
||||||
|
ref.read(prefsChangeNotifierProvider).exchangeRateType ==
|
||||||
|
ExchangeRateType.estimated;
|
||||||
|
_sendController.text = isEstimated
|
||||||
|
? ref.read(estimatedRateExchangeFormProvider).fromAmountString
|
||||||
|
: ref.read(fixedRateExchangeFormProvider).fromAmountString;
|
||||||
|
_receiveController.text = isEstimated
|
||||||
|
? ref.read(estimatedRateExchangeFormProvider).toAmountString
|
||||||
|
: ref.read(fixedRateExchangeFormProvider).toAmountString;
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,14 +441,14 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
.read(fixedRateExchangeFormProvider)
|
.read(fixedRateExchangeFormProvider)
|
||||||
.updateMarket(market, true);
|
.updateMarket(market, true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => const StackDialog(
|
builder: (_) => const StackDialog(
|
||||||
title: "Fixed rate market error",
|
title: "Fixed rate market error",
|
||||||
message:
|
message:
|
||||||
"Could not find the specified fixed rate trade pair",
|
"Could not find the specified fixed rate trade pair",
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -716,14 +750,14 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
.read(fixedRateExchangeFormProvider)
|
.read(fixedRateExchangeFormProvider)
|
||||||
.updateMarket(market, true);
|
.updateMarket(market, true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => const StackDialog(
|
builder: (_) => const StackDialog(
|
||||||
title: "Fixed rate market error",
|
title: "Fixed rate market error",
|
||||||
message:
|
message:
|
||||||
"Could not find the specified fixed rate trade pair",
|
"Could not find the specified fixed rate trade pair",
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -924,12 +958,12 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
showFloatingFlushBar(
|
unawaited(showFloatingFlushBar(
|
||||||
type: FlushBarType.warning,
|
type: FlushBarType.warning,
|
||||||
message:
|
message:
|
||||||
"Estimated rate trade pair \"$fromTicker-$toTicker\" unavailable. Reverting to last estimated rate pair.",
|
"Estimated rate trade pair \"$fromTicker-$toTicker\" unavailable. Reverting to last estimated rate pair.",
|
||||||
context: context,
|
context: context,
|
||||||
);
|
));
|
||||||
break;
|
break;
|
||||||
case ExchangeRateType.fixed:
|
case ExchangeRateType.fixed:
|
||||||
final fromTicker = ref
|
final fromTicker = ref
|
||||||
|
@ -970,12 +1004,12 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
showFloatingFlushBar(
|
unawaited(showFloatingFlushBar(
|
||||||
type: FlushBarType.warning,
|
type: FlushBarType.warning,
|
||||||
message:
|
message:
|
||||||
"Fixed rate trade pair \"$fromTicker-$toTicker\" unavailable. Reverting to last fixed rate pair.",
|
"Fixed rate trade pair \"$fromTicker-$toTicker\" unavailable. Reverting to last fixed rate pair.",
|
||||||
context: context,
|
context: context,
|
||||||
);
|
));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1047,7 +1081,7 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAvailable) {
|
if (!isAvailable) {
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
builder: (_) => StackDialog(
|
builder: (_) => StackDialog(
|
||||||
|
@ -1056,7 +1090,7 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
message:
|
message:
|
||||||
"The $fromTicker - $toTicker market is currently disabled for estimated/floating rate trades",
|
"The $fromTicker - $toTicker market is currently disabled for estimated/floating rate trades",
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1068,15 +1102,16 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
.read(prefsChangeNotifierProvider)
|
.read(prefsChangeNotifierProvider)
|
||||||
.exchangeRateType;
|
.exchangeRateType;
|
||||||
|
|
||||||
final response = await ChangeNow
|
final response = await ref
|
||||||
|
.read(changeNowProvider)
|
||||||
.getEstimatedExchangeAmount(
|
.getEstimatedExchangeAmount(
|
||||||
fromTicker: fromTicker,
|
fromTicker: fromTicker,
|
||||||
toTicker: toTicker,
|
toTicker: toTicker,
|
||||||
fromAmount: sendAmount,
|
fromAmount: sendAmount,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.value == null) {
|
if (response.value == null) {
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
builder: (_) => StackDialog(
|
builder: (_) => StackDialog(
|
||||||
|
@ -1084,7 +1119,7 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
"Failed to update trade estimate",
|
"Failed to update trade estimate",
|
||||||
message: response.exception?.toString(),
|
message: response.exception?.toString(),
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1108,10 +1143,10 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
exchangeSendFromWalletIdStateProvider
|
exchangeSendFromWalletIdStateProvider
|
||||||
.state)
|
.state)
|
||||||
.state = null;
|
.state = null;
|
||||||
Navigator.of(context).pushNamed(
|
unawaited(Navigator.of(context).pushNamed(
|
||||||
Step1View.routeName,
|
Step1View.routeName,
|
||||||
arguments: model,
|
arguments: model,
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final fromTicker = ref
|
final fromTicker = ref
|
||||||
|
@ -1133,18 +1168,19 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
.read(prefsChangeNotifierProvider)
|
.read(prefsChangeNotifierProvider)
|
||||||
.exchangeRateType;
|
.exchangeRateType;
|
||||||
|
|
||||||
final response = await ChangeNow
|
final response = await ref
|
||||||
|
.read(changeNowProvider)
|
||||||
.getEstimatedFixedRateExchangeAmount(
|
.getEstimatedFixedRateExchangeAmount(
|
||||||
fromTicker: fromTicker,
|
fromTicker: fromTicker,
|
||||||
toTicker: toTicker,
|
toTicker: toTicker,
|
||||||
fromAmount: sendAmount,
|
fromAmount: sendAmount,
|
||||||
useRateId: true,
|
useRateId: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
bool? shouldCancel;
|
bool? shouldCancel;
|
||||||
|
|
||||||
if (response.value == null) {
|
if (response.value == null) {
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
builder: (_) => StackDialog(
|
builder: (_) => StackDialog(
|
||||||
|
@ -1152,7 +1188,7 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
"Failed to update trade estimate",
|
"Failed to update trade estimate",
|
||||||
message: response.exception?.toString(),
|
message: response.exception?.toString(),
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
} else if (response.value!.warningMessage !=
|
} else if (response.value!.warningMessage !=
|
||||||
null &&
|
null &&
|
||||||
|
@ -1234,10 +1270,10 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
exchangeSendFromWalletIdStateProvider
|
exchangeSendFromWalletIdStateProvider
|
||||||
.state)
|
.state)
|
||||||
.state = null;
|
.state = null;
|
||||||
Navigator.of(context).pushNamed(
|
unawaited(Navigator.of(context).pushNamed(
|
||||||
Step1View.routeName,
|
Step1View.routeName,
|
||||||
arguments: model,
|
arguments: model,
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1341,18 +1377,18 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
||||||
final tx = txData.getAllTransactions()[txid];
|
final tx = txData.getAllTransactions()[txid];
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
Navigator.of(context).pushNamed(
|
unawaited(Navigator.of(context).pushNamed(
|
||||||
TradeDetailsView.routeName,
|
TradeDetailsView.routeName,
|
||||||
arguments: Tuple4(tradeId, tx,
|
arguments: Tuple4(tradeId, tx,
|
||||||
walletIds.first, manager.walletName),
|
walletIds.first, manager.walletName),
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Navigator.of(context).pushNamed(
|
unawaited(Navigator.of(context).pushNamed(
|
||||||
TradeDetailsView.routeName,
|
TradeDetailsView.routeName,
|
||||||
arguments: Tuple4(
|
arguments: Tuple4(
|
||||||
tradeId, null, walletIds?.first, null),
|
tradeId, null, walletIds?.first, null),
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -1454,7 +1490,7 @@ class RateInfo extends ConsumerWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showModalBottomSheet<dynamic>(
|
unawaited(showModalBottomSheet<dynamic>(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
context: context,
|
context: context,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
|
@ -1467,7 +1503,7 @@ class RateInfo extends ConsumerWidget {
|
||||||
if (value is ExchangeRateType && value != type) {
|
if (value is ExchangeRateType && value != type) {
|
||||||
onChanged(value);
|
onChanged(value);
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
style: Theme.of(context).textButtonTheme.style?.copyWith(
|
style: Theme.of(context).textButtonTheme.style?.copyWith(
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:decimal/decimal.dart';
|
import 'package:decimal/decimal.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
@ -16,13 +18,12 @@ import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.
|
||||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart';
|
import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart';
|
||||||
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
|
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/changenow_initial_load_status.dart';
|
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/exchange_form_provider.dart';
|
import 'package:stackwallet/providers/exchange/estimate_rate_exchange_form_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/exchange_send_from_wallet_id_provider.dart';
|
import 'package:stackwallet/providers/exchange/exchange_send_from_wallet_id_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart';
|
import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
|
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
|
||||||
import 'package:stackwallet/providers/providers.dart';
|
import 'package:stackwallet/providers/providers.dart';
|
||||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
|
||||||
import 'package:stackwallet/utilities/assets.dart';
|
import 'package:stackwallet/utilities/assets.dart';
|
||||||
import 'package:stackwallet/utilities/cfcolors.dart';
|
import 'package:stackwallet/utilities/cfcolors.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
|
@ -30,6 +31,7 @@ import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||||
import 'package:stackwallet/utilities/format.dart';
|
import 'package:stackwallet/utilities/format.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
||||||
import 'package:stackwallet/widgets/loading_indicator.dart';
|
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
@ -72,6 +74,23 @@ class _WalletInitiatedExchangeViewState
|
||||||
_sendFocusNode.unfocus();
|
_sendFocusNode.unfocus();
|
||||||
_receiveFocusNode.unfocus();
|
_receiveFocusNode.unfocus();
|
||||||
|
|
||||||
|
unawaited(
|
||||||
|
showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
barrierDismissible: false,
|
||||||
|
builder: (_) => WillPopScope(
|
||||||
|
onWillPop: () async => false,
|
||||||
|
child: Container(
|
||||||
|
color: CFColors.stackAccent.withOpacity(0.8),
|
||||||
|
child: const CustomLoadingOverlay(
|
||||||
|
message: "Updating exchange rate",
|
||||||
|
eventBus: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
if (ref.watch(prefsChangeNotifierProvider
|
if (ref.watch(prefsChangeNotifierProvider
|
||||||
.select((pref) => pref.exchangeRateType)) ==
|
.select((pref) => pref.exchangeRateType)) ==
|
||||||
ExchangeRateType.estimated) {
|
ExchangeRateType.estimated) {
|
||||||
|
@ -91,6 +110,9 @@ class _WalletInitiatedExchangeViewState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
_swapLock = false;
|
_swapLock = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +238,11 @@ class _WalletInitiatedExchangeViewState
|
||||||
coin = widget.coin;
|
coin = widget.coin;
|
||||||
_sendController = TextEditingController();
|
_sendController = TextEditingController();
|
||||||
_receiveController = TextEditingController();
|
_receiveController = TextEditingController();
|
||||||
|
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||||
|
ref.read(estimatedRateExchangeFormProvider).clearAmounts(true);
|
||||||
|
// ref.read(fixedRateExchangeFormProvider);
|
||||||
|
});
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,41 +257,6 @@ class _WalletInitiatedExchangeViewState
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
debugPrint("BUILD: $runtimeType");
|
debugPrint("BUILD: $runtimeType");
|
||||||
|
|
||||||
if (ref
|
|
||||||
.watch(changeNowEstimatedInitialLoadStatusStateProvider.state)
|
|
||||||
.state ==
|
|
||||||
false) {
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Center(
|
|
||||||
child: Text(
|
|
||||||
"Loading ChangeNOW data",
|
|
||||||
style: STextStyles.pageTitleH2,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
Center(
|
|
||||||
child: Text(
|
|
||||||
"This shouldn't take long",
|
|
||||||
style: STextStyles.smallMed14,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 16,
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 100,
|
|
||||||
width: 100,
|
|
||||||
child: LoadingIndicator(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final isEstimated = ref.watch(prefsChangeNotifierProvider
|
final isEstimated = ref.watch(prefsChangeNotifierProvider
|
||||||
.select((pref) => pref.exchangeRateType)) ==
|
.select((pref) => pref.exchangeRateType)) ==
|
||||||
ExchangeRateType.estimated;
|
ExchangeRateType.estimated;
|
||||||
|
@ -512,14 +504,14 @@ class _WalletInitiatedExchangeViewState
|
||||||
fixedRateExchangeFormProvider)
|
fixedRateExchangeFormProvider)
|
||||||
.updateMarket(market, true);
|
.updateMarket(market, true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => const StackDialog(
|
builder: (_) => const StackDialog(
|
||||||
title: "Fixed rate market error",
|
title: "Fixed rate market error",
|
||||||
message:
|
message:
|
||||||
"Could not find the specified fixed rate trade pair",
|
"Could not find the specified fixed rate trade pair",
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -867,14 +859,14 @@ class _WalletInitiatedExchangeViewState
|
||||||
fixedRateExchangeFormProvider)
|
fixedRateExchangeFormProvider)
|
||||||
.updateMarket(market, true);
|
.updateMarket(market, true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => const StackDialog(
|
builder: (_) => const StackDialog(
|
||||||
title: "Fixed rate market error",
|
title: "Fixed rate market error",
|
||||||
message:
|
message:
|
||||||
"Could not find the specified fixed rate trade pair",
|
"Could not find the specified fixed rate trade pair",
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1099,12 +1091,12 @@ class _WalletInitiatedExchangeViewState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
showFloatingFlushBar(
|
unawaited(showFloatingFlushBar(
|
||||||
type: FlushBarType.warning,
|
type: FlushBarType.warning,
|
||||||
message:
|
message:
|
||||||
"Estimated rate trade pair \"$fromTicker-$toTicker\" unavailable. Reverting to last estimated rate pair.",
|
"Estimated rate trade pair \"$fromTicker-$toTicker\" unavailable. Reverting to last estimated rate pair.",
|
||||||
context: context,
|
context: context,
|
||||||
);
|
));
|
||||||
break;
|
break;
|
||||||
case ExchangeRateType.fixed:
|
case ExchangeRateType.fixed:
|
||||||
final fromTicker = ref
|
final fromTicker = ref
|
||||||
|
@ -1146,12 +1138,12 @@ class _WalletInitiatedExchangeViewState
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
showFloatingFlushBar(
|
unawaited(showFloatingFlushBar(
|
||||||
type: FlushBarType.warning,
|
type: FlushBarType.warning,
|
||||||
message:
|
message:
|
||||||
"Fixed rate trade pair \"$fromTicker-$toTicker\" unavailable. Reverting to last fixed rate pair.",
|
"Fixed rate trade pair \"$fromTicker-$toTicker\" unavailable. Reverting to last fixed rate pair.",
|
||||||
context: context,
|
context: context,
|
||||||
);
|
));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1219,6 +1211,24 @@ class _WalletInitiatedExchangeViewState
|
||||||
|
|
||||||
if (ft.toLowerCase() ==
|
if (ft.toLowerCase() ==
|
||||||
coin.ticker.toLowerCase()) {
|
coin.ticker.toLowerCase()) {
|
||||||
|
bool shouldPop = false;
|
||||||
|
bool wasPopped = false;
|
||||||
|
unawaited(showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => WillPopScope(
|
||||||
|
onWillPop: () async {
|
||||||
|
if (shouldPop) {
|
||||||
|
wasPopped = true;
|
||||||
|
}
|
||||||
|
return shouldPop;
|
||||||
|
},
|
||||||
|
child: const CustomLoadingOverlay(
|
||||||
|
message: "Checking available balance",
|
||||||
|
eventBus: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
final availableBalance =
|
final availableBalance =
|
||||||
await manager.availableBalance;
|
await manager.availableBalance;
|
||||||
|
|
||||||
|
@ -1228,17 +1238,23 @@ class _WalletInitiatedExchangeViewState
|
||||||
Format.decimalAmountToSatoshis(
|
Format.decimalAmountToSatoshis(
|
||||||
sendAmount),
|
sendAmount),
|
||||||
feeObject.medium);
|
feeObject.medium);
|
||||||
|
|
||||||
|
shouldPop = true;
|
||||||
|
if (!wasPopped && mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
if (availableBalance <
|
if (availableBalance <
|
||||||
sendAmount +
|
sendAmount +
|
||||||
Format.satoshisToAmount(fee)) {
|
Format.satoshisToAmount(fee)) {
|
||||||
showDialog<void>(
|
unawaited(showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => StackOkDialog(
|
builder: (_) => StackOkDialog(
|
||||||
title: "Insufficient balance",
|
title: "Insufficient balance",
|
||||||
message:
|
message:
|
||||||
"Current ${coin.prettyName} wallet does not have enough ${coin.ticker} for this trade",
|
"Current ${coin.prettyName} wallet does not have enough ${coin.ticker} for this trade",
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1272,7 +1288,7 @@ class _WalletInitiatedExchangeViewState
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAvailable) {
|
if (!isAvailable) {
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
builder: (_) => StackDialog(
|
builder: (_) => StackDialog(
|
||||||
|
@ -1281,7 +1297,7 @@ class _WalletInitiatedExchangeViewState
|
||||||
message:
|
message:
|
||||||
"The $fromTicker - $toTicker market is currently disabled for estimated/floating rate trades",
|
"The $fromTicker - $toTicker market is currently disabled for estimated/floating rate trades",
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1289,15 +1305,16 @@ class _WalletInitiatedExchangeViewState
|
||||||
.read(prefsChangeNotifierProvider)
|
.read(prefsChangeNotifierProvider)
|
||||||
.exchangeRateType;
|
.exchangeRateType;
|
||||||
|
|
||||||
final response = await ChangeNow
|
final response = await ref
|
||||||
|
.read(changeNowProvider)
|
||||||
.getEstimatedExchangeAmount(
|
.getEstimatedExchangeAmount(
|
||||||
fromTicker: fromTicker,
|
fromTicker: fromTicker,
|
||||||
toTicker: toTicker,
|
toTicker: toTicker,
|
||||||
fromAmount: sendAmount,
|
fromAmount: sendAmount,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.value == null) {
|
if (response.value == null) {
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
builder: (_) => StackDialog(
|
builder: (_) => StackDialog(
|
||||||
|
@ -1306,7 +1323,7 @@ class _WalletInitiatedExchangeViewState
|
||||||
message:
|
message:
|
||||||
response.exception?.toString(),
|
response.exception?.toString(),
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1330,10 +1347,10 @@ class _WalletInitiatedExchangeViewState
|
||||||
exchangeSendFromWalletIdStateProvider
|
exchangeSendFromWalletIdStateProvider
|
||||||
.state)
|
.state)
|
||||||
.state = Tuple2(walletId, coin);
|
.state = Tuple2(walletId, coin);
|
||||||
Navigator.of(context).pushNamed(
|
unawaited(Navigator.of(context).pushNamed(
|
||||||
Step2View.routeName,
|
Step2View.routeName,
|
||||||
arguments: model,
|
arguments: model,
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final fromTicker = ref
|
final fromTicker = ref
|
||||||
|
@ -1355,18 +1372,19 @@ class _WalletInitiatedExchangeViewState
|
||||||
.read(prefsChangeNotifierProvider)
|
.read(prefsChangeNotifierProvider)
|
||||||
.exchangeRateType;
|
.exchangeRateType;
|
||||||
|
|
||||||
final response = await ChangeNow
|
final response = await ref
|
||||||
|
.read(changeNowProvider)
|
||||||
.getEstimatedFixedRateExchangeAmount(
|
.getEstimatedFixedRateExchangeAmount(
|
||||||
fromTicker: fromTicker,
|
fromTicker: fromTicker,
|
||||||
toTicker: toTicker,
|
toTicker: toTicker,
|
||||||
fromAmount: sendAmount,
|
fromAmount: sendAmount,
|
||||||
useRateId: true,
|
useRateId: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
bool? shouldCancel;
|
bool? shouldCancel;
|
||||||
|
|
||||||
if (response.value == null) {
|
if (response.value == null) {
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
builder: (_) => StackDialog(
|
builder: (_) => StackDialog(
|
||||||
|
@ -1375,7 +1393,7 @@ class _WalletInitiatedExchangeViewState
|
||||||
message:
|
message:
|
||||||
response.exception?.toString(),
|
response.exception?.toString(),
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
return;
|
return;
|
||||||
} else if (response.value!.warningMessage !=
|
} else if (response.value!.warningMessage !=
|
||||||
null &&
|
null &&
|
||||||
|
@ -1457,10 +1475,10 @@ class _WalletInitiatedExchangeViewState
|
||||||
exchangeSendFromWalletIdStateProvider
|
exchangeSendFromWalletIdStateProvider
|
||||||
.state)
|
.state)
|
||||||
.state = Tuple2(walletId, coin);
|
.state = Tuple2(walletId, coin);
|
||||||
Navigator.of(context).pushNamed(
|
unawaited(Navigator.of(context).pushNamed(
|
||||||
Step2View.routeName,
|
Step2View.routeName,
|
||||||
arguments: model,
|
arguments: model,
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/exchange_view.dart';
|
import 'package:stackwallet/pages/exchange_view/exchange_view.dart';
|
||||||
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
|
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/exchange_form_provider.dart';
|
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||||
|
import 'package:stackwallet/providers/exchange/estimate_rate_exchange_form_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart';
|
import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
|
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
|
||||||
import 'package:stackwallet/providers/providers.dart';
|
import 'package:stackwallet/providers/providers.dart';
|
||||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
|
||||||
import 'package:stackwallet/utilities/cfcolors.dart';
|
import 'package:stackwallet/utilities/cfcolors.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
@ -41,8 +43,9 @@ class _HomeViewButtonBarState extends ConsumerState<HomeViewButtonBar> {
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
WidgetRef ref,
|
WidgetRef ref,
|
||||||
) async {
|
) async {
|
||||||
final response = await ChangeNow.getAvailableCurrencies();
|
final response = await ref.read(changeNowProvider).getAvailableCurrencies();
|
||||||
final response2 = await ChangeNow.getAvailableFloatingRatePairs();
|
final response2 =
|
||||||
|
await ref.read(changeNowProvider).getAvailableFloatingRatePairs();
|
||||||
if (response.value != null && response2.value != null) {
|
if (response.value != null && response2.value != null) {
|
||||||
ref.read(availableChangeNowCurrenciesStateProvider.state).state =
|
ref.read(availableChangeNowCurrenciesStateProvider.state).state =
|
||||||
response.value!;
|
response.value!;
|
||||||
|
@ -52,13 +55,13 @@ class _HomeViewButtonBarState extends ConsumerState<HomeViewButtonBar> {
|
||||||
if (response.value!.length > 1) {
|
if (response.value!.length > 1) {
|
||||||
if (ref.read(estimatedRateExchangeFormProvider).from == null) {
|
if (ref.read(estimatedRateExchangeFormProvider).from == null) {
|
||||||
if (response.value!.where((e) => e.ticker == "btc").isNotEmpty) {
|
if (response.value!.where((e) => e.ticker == "btc").isNotEmpty) {
|
||||||
ref.read(estimatedRateExchangeFormProvider).updateFrom(
|
await ref.read(estimatedRateExchangeFormProvider).updateFrom(
|
||||||
response.value!.firstWhere((e) => e.ticker == "btc"), true);
|
response.value!.firstWhere((e) => e.ticker == "btc"), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ref.read(estimatedRateExchangeFormProvider).to == null) {
|
if (ref.read(estimatedRateExchangeFormProvider).to == null) {
|
||||||
if (response.value!.where((e) => e.ticker == "doge").isNotEmpty) {
|
if (response.value!.where((e) => e.ticker == "doge").isNotEmpty) {
|
||||||
ref.read(estimatedRateExchangeFormProvider).updateTo(
|
await ref.read(estimatedRateExchangeFormProvider).updateTo(
|
||||||
response.value!.firstWhere((e) => e.ticker == "doge"), true);
|
response.value!.firstWhere((e) => e.ticker == "doge"), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +73,7 @@ class _HomeViewButtonBarState extends ConsumerState<HomeViewButtonBar> {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Failed to load changeNOW floating rate market data: \n${response.exception?.errorMessage}\n${response2.exception?.toString()}",
|
"Failed to load changeNOW floating rate market data: \n${response.exception?.errorMessage}\n${response2.exception?.toString()}",
|
||||||
level: LogLevel.Error);
|
level: LogLevel.Error);
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
builder: (_) => StackDialog(
|
builder: (_) => StackDialog(
|
||||||
|
@ -78,7 +81,7 @@ class _HomeViewButtonBarState extends ConsumerState<HomeViewButtonBar> {
|
||||||
message:
|
message:
|
||||||
"${response.exception?.toString()}\n\n${response2.exception?.toString()}",
|
"${response.exception?.toString()}\n\n${response2.exception?.toString()}",
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +89,8 @@ class _HomeViewButtonBarState extends ConsumerState<HomeViewButtonBar> {
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
WidgetRef ref,
|
WidgetRef ref,
|
||||||
) async {
|
) async {
|
||||||
final response3 = await ChangeNow.getAvailableFixedRateMarkets();
|
final response3 =
|
||||||
|
await ref.read(changeNowProvider).getAvailableFixedRateMarkets();
|
||||||
|
|
||||||
if (response3.value != null) {
|
if (response3.value != null) {
|
||||||
ref.read(fixedRateMarketPairsStateProvider.state).state =
|
ref.read(fixedRateMarketPairsStateProvider.state).state =
|
||||||
|
@ -97,7 +101,7 @@ class _HomeViewButtonBarState extends ConsumerState<HomeViewButtonBar> {
|
||||||
response3.value!.where((e) => e.to == "doge" && e.from == "btc");
|
response3.value!.where((e) => e.to == "doge" && e.from == "btc");
|
||||||
|
|
||||||
if (matchingMarkets.isNotEmpty) {
|
if (matchingMarkets.isNotEmpty) {
|
||||||
ref
|
await ref
|
||||||
.read(fixedRateExchangeFormProvider)
|
.read(fixedRateExchangeFormProvider)
|
||||||
.updateMarket(matchingMarkets.first, true);
|
.updateMarket(matchingMarkets.first, true);
|
||||||
}
|
}
|
||||||
|
@ -108,14 +112,14 @@ class _HomeViewButtonBarState extends ConsumerState<HomeViewButtonBar> {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Failed to load changeNOW fixed rate markets: ${response3.exception?.errorMessage}",
|
"Failed to load changeNOW fixed rate markets: ${response3.exception?.errorMessage}",
|
||||||
level: LogLevel.Error);
|
level: LogLevel.Error);
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
builder: (_) => StackDialog(
|
builder: (_) => StackDialog(
|
||||||
title: "ChangeNOW API call failed",
|
title: "ChangeNOW API call failed",
|
||||||
message: "${response3.exception?.toString()}",
|
message: "${response3.exception?.toString()}",
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||||
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
|
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
|
||||||
import 'package:stackwallet/pages/send_view/sub_widgets/sending_transaction_dialog.dart';
|
import 'package:stackwallet/pages/send_view/sub_widgets/sending_transaction_dialog.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
||||||
import 'package:stackwallet/providers/providers.dart';
|
import 'package:stackwallet/providers/providers.dart';
|
||||||
import 'package:stackwallet/route_generator.dart';
|
import 'package:stackwallet/route_generator.dart';
|
||||||
|
import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart';
|
||||||
import 'package:stackwallet/utilities/cfcolors.dart';
|
import 'package:stackwallet/utilities/cfcolors.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
|
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||||
import 'package:stackwallet/utilities/format.dart';
|
import 'package:stackwallet/utilities/format.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
|
@ -40,25 +45,25 @@ class _ConfirmTransactionViewState
|
||||||
late final String routeOnSuccessName;
|
late final String routeOnSuccessName;
|
||||||
|
|
||||||
Future<void> _attemptSend(BuildContext context) async {
|
Future<void> _attemptSend(BuildContext context) async {
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
useSafeArea: false,
|
useSafeArea: false,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return const SendingTransactionDialog();
|
return const SendingTransactionDialog();
|
||||||
},
|
},
|
||||||
);
|
));
|
||||||
|
|
||||||
final note = transactionInfo["note"] as String? ?? "";
|
final note = transactionInfo["note"] as String? ?? "";
|
||||||
final manager =
|
final manager =
|
||||||
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final txid = await manager.confirmSend(txData: transactionInfo);
|
final txid = await manager.confirmSend(txData: transactionInfo);
|
||||||
manager.refresh();
|
unawaited(manager.refresh());
|
||||||
|
|
||||||
// save note
|
// save note
|
||||||
ref
|
await ref
|
||||||
.read(notesServiceChangeNotifierProvider(walletId))
|
.read(notesServiceChangeNotifierProvider(walletId))
|
||||||
.editOrAddNote(txid: txid, note: note);
|
.editOrAddNote(txid: txid, note: note);
|
||||||
|
|
||||||
|
@ -66,12 +71,26 @@ class _ConfirmTransactionViewState
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
Navigator.of(context).popUntil(ModalRoute.withName(routeOnSuccessName));
|
Navigator.of(context).popUntil(ModalRoute.withName(routeOnSuccessName));
|
||||||
}
|
}
|
||||||
|
} on BadEpicHttpAddressException catch (_) {
|
||||||
|
if (mounted) {
|
||||||
|
// pop building dialog
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
unawaited(
|
||||||
|
showFloatingFlushBar(
|
||||||
|
type: FlushBarType.warning,
|
||||||
|
message:
|
||||||
|
"Connection failed. Please check the address and try again.",
|
||||||
|
context: context,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
debugPrint("$e\n$s");
|
debugPrint("$e\n$s");
|
||||||
// pop sending dialog
|
// pop sending dialog
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
showDialog<void>(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
useSafeArea: false,
|
useSafeArea: false,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
|
@ -81,10 +100,10 @@ class _ConfirmTransactionViewState
|
||||||
message: e.toString(),
|
message: e.toString(),
|
||||||
rightButton: TextButton(
|
rightButton: TextButton(
|
||||||
style: Theme.of(context).textButtonTheme.style?.copyWith(
|
style: Theme.of(context).textButtonTheme.style?.copyWith(
|
||||||
backgroundColor: MaterialStateProperty.all<Color>(
|
backgroundColor: MaterialStateProperty.all<Color>(
|
||||||
CFColors.buttonGray,
|
CFColors.buttonGray,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
"Ok",
|
"Ok",
|
||||||
style: STextStyles.button.copyWith(
|
style: STextStyles.button.copyWith(
|
||||||
|
@ -193,9 +212,9 @@ class _ConfirmTransactionViewState
|
||||||
.select((value) => value.locale),
|
.select((value) => value.locale),
|
||||||
),
|
),
|
||||||
)} ${ref.watch(
|
)} ${ref.watch(
|
||||||
managerProvider
|
managerProvider
|
||||||
.select((value) => value.coin),
|
.select((value) => value.coin),
|
||||||
).ticker}",
|
).ticker}",
|
||||||
style: STextStyles.itemSubtitle12,
|
style: STextStyles.itemSubtitle12,
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
),
|
),
|
||||||
|
@ -221,9 +240,9 @@ class _ConfirmTransactionViewState
|
||||||
.select((value) => value.locale),
|
.select((value) => value.locale),
|
||||||
),
|
),
|
||||||
)} ${ref.watch(
|
)} ${ref.watch(
|
||||||
managerProvider
|
managerProvider
|
||||||
.select((value) => value.coin),
|
.select((value) => value.coin),
|
||||||
).ticker}",
|
).ticker}",
|
||||||
style: STextStyles.itemSubtitle12,
|
style: STextStyles.itemSubtitle12,
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
),
|
),
|
||||||
|
@ -273,9 +292,9 @@ class _ConfirmTransactionViewState
|
||||||
.select((value) => value.locale),
|
.select((value) => value.locale),
|
||||||
),
|
),
|
||||||
)} ${ref.watch(
|
)} ${ref.watch(
|
||||||
managerProvider
|
managerProvider
|
||||||
.select((value) => value.coin),
|
.select((value) => value.coin),
|
||||||
).ticker}",
|
).ticker}",
|
||||||
style: STextStyles.itemSubtitle12,
|
style: STextStyles.itemSubtitle12,
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
),
|
),
|
||||||
|
@ -287,18 +306,18 @@ class _ConfirmTransactionViewState
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
style:
|
style:
|
||||||
Theme.of(context).textButtonTheme.style?.copyWith(
|
Theme.of(context).textButtonTheme.style?.copyWith(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
MaterialStateProperty.all<Color>(
|
MaterialStateProperty.all<Color>(
|
||||||
CFColors.stackAccent,
|
CFColors.stackAccent,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final unlocked = await Navigator.push(
|
final unlocked = await Navigator.push(
|
||||||
context,
|
context,
|
||||||
RouteGenerator.getRoute(
|
RouteGenerator.getRoute(
|
||||||
shouldUseMaterialRoute:
|
shouldUseMaterialRoute:
|
||||||
RouteGenerator.useMaterialPageRoute,
|
RouteGenerator.useMaterialPageRoute,
|
||||||
builder: (_) => const LockscreenView(
|
builder: (_) => const LockscreenView(
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
popOnSuccess: true,
|
popOnSuccess: true,
|
||||||
|
@ -306,9 +325,9 @@ class _ConfirmTransactionViewState
|
||||||
routeOnSuccess: "",
|
routeOnSuccess: "",
|
||||||
biometricsCancelButtonString: "CANCEL",
|
biometricsCancelButtonString: "CANCEL",
|
||||||
biometricsLocalizedReason:
|
biometricsLocalizedReason:
|
||||||
"Authenticate to send transaction",
|
"Authenticate to send transaction",
|
||||||
biometricsAuthenticationTitle:
|
biometricsAuthenticationTitle:
|
||||||
"Confirm Transaction",
|
"Confirm Transaction",
|
||||||
),
|
),
|
||||||
settings: const RouteSettings(
|
settings: const RouteSettings(
|
||||||
name: "/confirmsendlockscreen"),
|
name: "/confirmsendlockscreen"),
|
||||||
|
@ -316,7 +335,7 @@ class _ConfirmTransactionViewState
|
||||||
);
|
);
|
||||||
|
|
||||||
if (unlocked is bool && unlocked && mounted) {
|
if (unlocked is bool && unlocked && mounted) {
|
||||||
_attemptSend(context);
|
unawaited(_attemptSend(context));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:decimal/decimal.dart';
|
import 'package:decimal/decimal.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
@ -1175,7 +1177,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
try {
|
try {
|
||||||
bool wasCancelled = false;
|
bool wasCancelled = false;
|
||||||
|
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
useSafeArea: false,
|
useSafeArea: false,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
|
@ -1188,7 +1190,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
));
|
||||||
|
|
||||||
final txData = await manager.prepareSend(
|
final txData = await manager.prepareSend(
|
||||||
address: _address!,
|
address: _address!,
|
||||||
|
@ -1205,7 +1207,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
txData["note"] = noteController.text;
|
txData["note"] = noteController.text;
|
||||||
txData["address"] = _address;
|
txData["address"] = _address;
|
||||||
|
|
||||||
Navigator.of(context).push(
|
unawaited(Navigator.of(context).push(
|
||||||
RouteGenerator.getRoute(
|
RouteGenerator.getRoute(
|
||||||
shouldUseMaterialRoute: RouteGenerator
|
shouldUseMaterialRoute: RouteGenerator
|
||||||
.useMaterialPageRoute,
|
.useMaterialPageRoute,
|
||||||
|
@ -1219,14 +1221,14 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
.routeName,
|
.routeName,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
// pop building dialog
|
// pop building dialog
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
showDialog<dynamic>(
|
unawaited(showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
useSafeArea: false,
|
useSafeArea: false,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
|
@ -1258,7 +1260,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_navigation_bar.
|
||||||
import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_summary.dart';
|
import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_summary.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/all_transactions_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/all_transactions_view.dart';
|
||||||
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
||||||
import 'package:stackwallet/providers/exchange/exchange_form_provider.dart';
|
import 'package:stackwallet/providers/exchange/estimate_rate_exchange_form_provider.dart';
|
||||||
import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
|
import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
|
||||||
import 'package:stackwallet/providers/providers.dart';
|
import 'package:stackwallet/providers/providers.dart';
|
||||||
import 'package:stackwallet/providers/ui/transaction_filter_provider.dart';
|
import 'package:stackwallet/providers/ui/transaction_filter_provider.dart';
|
||||||
|
|
4
lib/providers/exchange/change_now_provider.dart
Normal file
4
lib/providers/exchange/change_now_provider.dart
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:stackwallet/services/change_now/change_now.dart';
|
||||||
|
|
||||||
|
final changeNowProvider = Provider<ChangeNow>((ref) => ChangeNow.instance);
|
|
@ -0,0 +1,5 @@
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:stackwallet/models/exchange/estimated_rate_exchange_form_state.dart';
|
||||||
|
|
||||||
|
final estimatedRateExchangeFormProvider =
|
||||||
|
ChangeNotifierProvider((ref) => EstimatedRateExchangeFormState());
|
|
@ -1,5 +0,0 @@
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
import 'package:stackwallet/models/exchange/exchange_form_state.dart';
|
|
||||||
|
|
||||||
final estimatedRateExchangeFormProvider =
|
|
||||||
ChangeNotifierProvider((ref) => ExchangeFormState());
|
|
|
@ -21,6 +21,7 @@ import 'package:stackwallet/pages/address_book_views/subviews/contact_details_vi
|
||||||
import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_address_view.dart';
|
import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_address_view.dart';
|
||||||
import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart';
|
import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart';
|
import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart';
|
||||||
|
import 'package:stackwallet/pages/exchange_view/exchange_loading_overlay.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_1_view.dart';
|
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_1_view.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart';
|
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view.dart';
|
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view.dart';
|
||||||
|
@ -721,9 +722,14 @@ class RouteGenerator {
|
||||||
if (args is Tuple2<String, Coin>) {
|
if (args is Tuple2<String, Coin>) {
|
||||||
return getRoute(
|
return getRoute(
|
||||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||||
builder: (_) => WalletInitiatedExchangeView(
|
builder: (_) => Stack(
|
||||||
walletId: args.item1,
|
children: [
|
||||||
coin: args.item2,
|
WalletInitiatedExchangeView(
|
||||||
|
walletId: args.item1,
|
||||||
|
coin: args.item2,
|
||||||
|
),
|
||||||
|
const ExchangeLoadingOverlayView(),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
settings: RouteSettings(
|
settings: RouteSettings(
|
||||||
name: settings.name,
|
name: settings.name,
|
||||||
|
|
|
@ -13,20 +13,24 @@ import 'package:stackwallet/models/exchange/change_now/exchange_transaction_stat
|
||||||
import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart';
|
import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
|
||||||
abstract class ChangeNow {
|
class ChangeNow {
|
||||||
static const String scheme = "https";
|
static const String scheme = "https";
|
||||||
static const String authority = "api.changenow.io";
|
static const String authority = "api.changenow.io";
|
||||||
static const String apiVersion = "/v1";
|
static const String apiVersion = "/v1";
|
||||||
|
|
||||||
/// set this to override using standard http client. Useful for testing
|
ChangeNow._();
|
||||||
static http.Client? client;
|
static final ChangeNow _instance = ChangeNow._();
|
||||||
|
static ChangeNow get instance => _instance;
|
||||||
|
|
||||||
static Uri _buildUri(String path, Map<String, dynamic>? params) {
|
/// set this to override using standard http client. Useful for testing
|
||||||
|
http.Client? client;
|
||||||
|
|
||||||
|
Uri _buildUri(String path, Map<String, dynamic>? params) {
|
||||||
return Uri.https(authority, apiVersion + path, params);
|
return Uri.https(authority, apiVersion + path, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<dynamic> _makeGetRequest(Uri uri) async {
|
Future<dynamic> _makeGetRequest(Uri uri) async {
|
||||||
final client = ChangeNow.client ?? http.Client();
|
final client = this.client ?? http.Client();
|
||||||
try {
|
try {
|
||||||
final response = await client.get(
|
final response = await client.get(
|
||||||
uri,
|
uri,
|
||||||
|
@ -43,11 +47,11 @@ abstract class ChangeNow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<dynamic> _makePostRequest(
|
Future<dynamic> _makePostRequest(
|
||||||
Uri uri,
|
Uri uri,
|
||||||
Map<String, String> body,
|
Map<String, String> body,
|
||||||
) async {
|
) async {
|
||||||
final client = ChangeNow.client ?? http.Client();
|
final client = this.client ?? http.Client();
|
||||||
try {
|
try {
|
||||||
final response = await client.post(
|
final response = await client.post(
|
||||||
uri,
|
uri,
|
||||||
|
@ -69,7 +73,7 @@ abstract class ChangeNow {
|
||||||
///
|
///
|
||||||
/// Set [active] to true to return only active currencies.
|
/// Set [active] to true to return only active currencies.
|
||||||
/// Set [fixedRate] to true to return only currencies available on a fixed-rate flow.
|
/// Set [fixedRate] to true to return only currencies available on a fixed-rate flow.
|
||||||
static Future<ChangeNowResponse<List<Currency>>> getAvailableCurrencies({
|
Future<ChangeNowResponse<List<Currency>>> getAvailableCurrencies({
|
||||||
bool? fixedRate,
|
bool? fixedRate,
|
||||||
bool? active,
|
bool? active,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -117,7 +121,7 @@ abstract class ChangeNow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ChangeNowResponse<List<Currency>> _parseAvailableCurrenciesJson(
|
ChangeNowResponse<List<Currency>> _parseAvailableCurrenciesJson(
|
||||||
List<dynamic> jsonArray) {
|
List<dynamic> jsonArray) {
|
||||||
try {
|
try {
|
||||||
List<Currency> currencies = [];
|
List<Currency> currencies = [];
|
||||||
|
@ -144,7 +148,7 @@ abstract class ChangeNow {
|
||||||
///
|
///
|
||||||
/// Required [ticker] to fetch paired currencies for.
|
/// Required [ticker] to fetch paired currencies for.
|
||||||
/// Set [fixedRate] to true to return only currencies available on a fixed-rate flow.
|
/// Set [fixedRate] to true to return only currencies available on a fixed-rate flow.
|
||||||
static Future<ChangeNowResponse<List<Currency>>> getPairedCurrencies({
|
Future<ChangeNowResponse<List<Currency>>> getPairedCurrencies({
|
||||||
required String ticker,
|
required String ticker,
|
||||||
bool? fixedRate,
|
bool? fixedRate,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -199,7 +203,7 @@ abstract class ChangeNow {
|
||||||
/// The API endpoint returns minimal payment amount required to make
|
/// The API endpoint returns minimal payment amount required to make
|
||||||
/// an exchange of [fromTicker] to [toTicker].
|
/// an exchange of [fromTicker] to [toTicker].
|
||||||
/// If you try to exchange less, the transaction will most likely fail.
|
/// If you try to exchange less, the transaction will most likely fail.
|
||||||
static Future<ChangeNowResponse<Decimal>> getMinimalExchangeAmount({
|
Future<ChangeNowResponse<Decimal>> getMinimalExchangeAmount({
|
||||||
required String fromTicker,
|
required String fromTicker,
|
||||||
required String toTicker,
|
required String toTicker,
|
||||||
String? apiKey,
|
String? apiKey,
|
||||||
|
@ -237,7 +241,7 @@ abstract class ChangeNow {
|
||||||
|
|
||||||
/// Get estimated amount of [toTicker] cryptocurrency to receive
|
/// Get estimated amount of [toTicker] cryptocurrency to receive
|
||||||
/// for [fromAmount] of [fromTicker]
|
/// for [fromAmount] of [fromTicker]
|
||||||
static Future<ChangeNowResponse<EstimatedExchangeAmount>>
|
Future<ChangeNowResponse<EstimatedExchangeAmount>>
|
||||||
getEstimatedExchangeAmount({
|
getEstimatedExchangeAmount({
|
||||||
required String fromTicker,
|
required String fromTicker,
|
||||||
required String toTicker,
|
required String toTicker,
|
||||||
|
@ -281,7 +285,7 @@ abstract class ChangeNow {
|
||||||
|
|
||||||
/// This API endpoint returns fixed-rate estimated exchange amount of
|
/// This API endpoint returns fixed-rate estimated exchange amount of
|
||||||
/// [toTicker] cryptocurrency to receive for [fromAmount] of [fromTicker]
|
/// [toTicker] cryptocurrency to receive for [fromAmount] of [fromTicker]
|
||||||
static Future<ChangeNowResponse<EstimatedExchangeAmount>>
|
Future<ChangeNowResponse<EstimatedExchangeAmount>>
|
||||||
getEstimatedFixedRateExchangeAmount({
|
getEstimatedFixedRateExchangeAmount({
|
||||||
required String fromTicker,
|
required String fromTicker,
|
||||||
required String toTicker,
|
required String toTicker,
|
||||||
|
@ -336,7 +340,7 @@ abstract class ChangeNow {
|
||||||
/// fixed-rate flow. Some currencies get enabled or disabled from time to
|
/// fixed-rate flow. Some currencies get enabled or disabled from time to
|
||||||
/// time and the market info gets updates, so make sure to refresh the list
|
/// time and the market info gets updates, so make sure to refresh the list
|
||||||
/// occasionally. One time per minute is sufficient.
|
/// occasionally. One time per minute is sufficient.
|
||||||
static Future<ChangeNowResponse<List<FixedRateMarket>>>
|
Future<ChangeNowResponse<List<FixedRateMarket>>>
|
||||||
getAvailableFixedRateMarkets({
|
getAvailableFixedRateMarkets({
|
||||||
String? apiKey,
|
String? apiKey,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -373,7 +377,7 @@ abstract class ChangeNow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ChangeNowResponse<List<FixedRateMarket>> _parseFixedRateMarketsJson(
|
ChangeNowResponse<List<FixedRateMarket>> _parseFixedRateMarketsJson(
|
||||||
List<dynamic> jsonArray) {
|
List<dynamic> jsonArray) {
|
||||||
try {
|
try {
|
||||||
List<FixedRateMarket> markets = [];
|
List<FixedRateMarket> markets = [];
|
||||||
|
@ -395,7 +399,7 @@ abstract class ChangeNow {
|
||||||
|
|
||||||
/// The API endpoint creates a transaction, generates an address for
|
/// The API endpoint creates a transaction, generates an address for
|
||||||
/// sending funds and returns transaction attributes.
|
/// sending funds and returns transaction attributes.
|
||||||
static Future<ChangeNowResponse<ExchangeTransaction>>
|
Future<ChangeNowResponse<ExchangeTransaction>>
|
||||||
createStandardExchangeTransaction({
|
createStandardExchangeTransaction({
|
||||||
required String fromTicker,
|
required String fromTicker,
|
||||||
required String toTicker,
|
required String toTicker,
|
||||||
|
@ -457,7 +461,7 @@ abstract class ChangeNow {
|
||||||
|
|
||||||
/// The API endpoint creates a transaction, generates an address for
|
/// The API endpoint creates a transaction, generates an address for
|
||||||
/// sending funds and returns transaction attributes.
|
/// sending funds and returns transaction attributes.
|
||||||
static Future<ChangeNowResponse<ExchangeTransaction>>
|
Future<ChangeNowResponse<ExchangeTransaction>>
|
||||||
createFixedRateExchangeTransaction({
|
createFixedRateExchangeTransaction({
|
||||||
required String fromTicker,
|
required String fromTicker,
|
||||||
required String toTicker,
|
required String toTicker,
|
||||||
|
@ -520,8 +524,7 @@ abstract class ChangeNow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<ChangeNowResponse<ExchangeTransactionStatus>>
|
Future<ChangeNowResponse<ExchangeTransactionStatus>> getTransactionStatus({
|
||||||
getTransactionStatus({
|
|
||||||
required String id,
|
required String id,
|
||||||
String? apiKey,
|
String? apiKey,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -556,7 +559,7 @@ abstract class ChangeNow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<ChangeNowResponse<List<AvailableFloatingRatePair>>>
|
Future<ChangeNowResponse<List<AvailableFloatingRatePair>>>
|
||||||
getAvailableFloatingRatePairs({
|
getAvailableFloatingRatePairs({
|
||||||
bool includePartners = false,
|
bool includePartners = false,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -593,7 +596,7 @@ abstract class ChangeNow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ChangeNowResponse<List<AvailableFloatingRatePair>>
|
ChangeNowResponse<List<AvailableFloatingRatePair>>
|
||||||
_parseAvailableFloatingRatePairsJson(List<dynamic> jsonArray) {
|
_parseAvailableFloatingRatePairsJson(List<dynamic> jsonArray) {
|
||||||
try {
|
try {
|
||||||
List<AvailableFloatingRatePair> pairs = [];
|
List<AvailableFloatingRatePair> pairs = [];
|
||||||
|
|
|
@ -1063,8 +1063,8 @@ class BitcoinWallet extends CoinServiceAPI {
|
||||||
@override
|
@override
|
||||||
Future<void> refresh() async {
|
Future<void> refresh() async {
|
||||||
if (refreshMutex) {
|
if (refreshMutex) {
|
||||||
Logging.instance
|
Logging.instance.log("$walletId $walletName refreshMutex denied",
|
||||||
.log("$walletName refreshMutex denied", level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
refreshMutex = true;
|
refreshMutex = true;
|
||||||
|
@ -1139,14 +1139,15 @@ class BitcoinWallet extends CoinServiceAPI {
|
||||||
if (shouldAutoSync) {
|
if (shouldAutoSync) {
|
||||||
timer ??= Timer.periodic(const Duration(seconds: 150), (timer) async {
|
timer ??= Timer.periodic(const Duration(seconds: 150), (timer) async {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Periodic refresh check for $walletName in object instance: $hashCode",
|
"Periodic refresh check for $walletId $walletName in object instance: $hashCode",
|
||||||
level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
// chain height check currently broken
|
// chain height check currently broken
|
||||||
// if ((await chainHeight) != (await storedChainHeight)) {
|
// if ((await chainHeight) != (await storedChainHeight)) {
|
||||||
if (await refreshIfThereIsNewData()) {
|
if (await refreshIfThereIsNewData()) {
|
||||||
await refresh();
|
await refresh();
|
||||||
GlobalEventBus.instance.fire(UpdatedInBackgroundEvent(
|
GlobalEventBus.instance.fire(UpdatedInBackgroundEvent(
|
||||||
"New data found in $walletName in background!", walletId));
|
"New data found in $walletId $walletName in background!",
|
||||||
|
walletId));
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
});
|
});
|
||||||
|
@ -3375,7 +3376,7 @@ class BitcoinWallet extends CoinServiceAPI {
|
||||||
);
|
);
|
||||||
|
|
||||||
// clear cache
|
// clear cache
|
||||||
_cachedElectrumXClient.clearSharedTransactionCache(coin: coin);
|
await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin);
|
||||||
|
|
||||||
// back up data
|
// back up data
|
||||||
await _rescanBackup();
|
await _rescanBackup();
|
||||||
|
|
|
@ -741,7 +741,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
@override
|
@override
|
||||||
Future<void> refresh() async {
|
Future<void> refresh() async {
|
||||||
if (refreshMutex) {
|
if (refreshMutex) {
|
||||||
Logging.instance.log("refreshMutex denied", level: LogLevel.Info);
|
Logging.instance.log("$walletId $walletName refreshMutex denied",
|
||||||
|
level: LogLevel.Info);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
refreshMutex = true;
|
refreshMutex = true;
|
||||||
|
@ -820,7 +821,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
if (await refreshIfThereIsNewData()) {
|
if (await refreshIfThereIsNewData()) {
|
||||||
await refresh();
|
await refresh();
|
||||||
GlobalEventBus.instance.fire(UpdatedInBackgroundEvent(
|
GlobalEventBus.instance.fire(UpdatedInBackgroundEvent(
|
||||||
"New data found in $walletName in background!", walletId));
|
"New data found in $walletId $walletName in background!",
|
||||||
|
walletId));
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
});
|
});
|
||||||
|
@ -1761,7 +1763,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
await _getCurrentAddressForChain(1, derivePathType);
|
await _getCurrentAddressForChain(1, derivePathType);
|
||||||
final int txCount = await getTxCount(address: currentExternalAddr);
|
final int txCount = await getTxCount(address: currentExternalAddr);
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
'Number of txs for current change address $currentExternalAddr: $txCount', level: LogLevel.Info);
|
'Number of txs for current change address $currentExternalAddr: $txCount',
|
||||||
|
level: LogLevel.Info);
|
||||||
|
|
||||||
if (txCount >= 1) {
|
if (txCount >= 1) {
|
||||||
// First increment the change index
|
// First increment the change index
|
||||||
|
@ -1786,7 +1789,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Exception rethrown from _checkChangeAddressForTransactions($derivePathType): $e\n$s", level: LogLevel.Error);
|
"Exception rethrown from _checkChangeAddressForTransactions($derivePathType): $e\n$s",
|
||||||
|
level: LogLevel.Error);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1798,7 +1802,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Exception rethrown from _checkCurrentReceivingAddressesForTransactions(): $e\n$s", level: LogLevel.Info);
|
"Exception rethrown from _checkCurrentReceivingAddressesForTransactions(): $e\n$s",
|
||||||
|
level: LogLevel.Info);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1821,7 +1826,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Exception rethrown from _checkCurrentChangeAddressesForTransactions(): $e\n$s", level: LogLevel.Error);
|
"Exception rethrown from _checkCurrentChangeAddressesForTransactions(): $e\n$s",
|
||||||
|
level: LogLevel.Error);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1969,7 +1975,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
Logging.instance.log("addAddresses: $allAddresses", level: LogLevel.Info);
|
Logging.instance.log("addAddresses: $allAddresses", level: LogLevel.Info);
|
||||||
Logging.instance.log("allTxHashes: $allTxHashes", level: LogLevel.Info);
|
Logging.instance.log("allTxHashes: $allTxHashes", level: LogLevel.Info);
|
||||||
|
|
||||||
Logging.instance.log("allTransactions length: ${allTransactions.length}", level: LogLevel.Info);
|
Logging.instance.log("allTransactions length: ${allTransactions.length}",
|
||||||
|
level: LogLevel.Info);
|
||||||
|
|
||||||
final priceData =
|
final priceData =
|
||||||
await _priceAPI.getPricesAnd24hChange(baseCurrency: _prefs.currency);
|
await _priceAPI.getPricesAnd24hChange(baseCurrency: _prefs.currency);
|
||||||
|
@ -2015,11 +2022,13 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.instance.log("recipientsArray: $recipientsArray", level: LogLevel.Info);
|
Logging.instance
|
||||||
|
.log("recipientsArray: $recipientsArray", level: LogLevel.Info);
|
||||||
|
|
||||||
final foundInSenders =
|
final foundInSenders =
|
||||||
allAddresses.any((element) => sendersArray.contains(element));
|
allAddresses.any((element) => sendersArray.contains(element));
|
||||||
Logging.instance.log("foundInSenders: $foundInSenders", level: LogLevel.Info);
|
Logging.instance
|
||||||
|
.log("foundInSenders: $foundInSenders", level: LogLevel.Info);
|
||||||
|
|
||||||
// If txType = Sent, then calculate inputAmtSentFromWallet
|
// If txType = Sent, then calculate inputAmtSentFromWallet
|
||||||
if (foundInSenders) {
|
if (foundInSenders) {
|
||||||
|
@ -2228,7 +2237,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
dynamic coinSelection(int satoshiAmountToSend, int selectedTxFeeRate,
|
dynamic coinSelection(int satoshiAmountToSend, int selectedTxFeeRate,
|
||||||
String _recipientAddress, bool isSendAll,
|
String _recipientAddress, bool isSendAll,
|
||||||
{int additionalOutputs = 0, List<UtxoObject>? utxos}) async {
|
{int additionalOutputs = 0, List<UtxoObject>? utxos}) async {
|
||||||
Logging.instance.log("Starting coinSelection ----------", level: LogLevel.Info);
|
Logging.instance
|
||||||
|
.log("Starting coinSelection ----------", level: LogLevel.Info);
|
||||||
final List<UtxoObject> availableOutputs = utxos ?? outputsList;
|
final List<UtxoObject> availableOutputs = utxos ?? outputsList;
|
||||||
final List<UtxoObject> spendableOutputs = [];
|
final List<UtxoObject> spendableOutputs = [];
|
||||||
int spendableSatoshiValue = 0;
|
int spendableSatoshiValue = 0;
|
||||||
|
@ -2246,10 +2256,14 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
spendableOutputs.sort(
|
spendableOutputs.sort(
|
||||||
(a, b) => b.status.confirmations.compareTo(a.status.confirmations));
|
(a, b) => b.status.confirmations.compareTo(a.status.confirmations));
|
||||||
|
|
||||||
Logging.instance.log("spendableOutputs.length: ${spendableOutputs.length}", level: LogLevel.Info);
|
Logging.instance.log("spendableOutputs.length: ${spendableOutputs.length}",
|
||||||
Logging.instance.log("spendableOutputs: $spendableOutputs", level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
Logging.instance.log("spendableSatoshiValue: $spendableSatoshiValue", level: LogLevel.Info);
|
Logging.instance
|
||||||
Logging.instance.log("satoshiAmountToSend: $satoshiAmountToSend", level: LogLevel.Info);
|
.log("spendableOutputs: $spendableOutputs", level: LogLevel.Info);
|
||||||
|
Logging.instance.log("spendableSatoshiValue: $spendableSatoshiValue",
|
||||||
|
level: LogLevel.Info);
|
||||||
|
Logging.instance
|
||||||
|
.log("satoshiAmountToSend: $satoshiAmountToSend", level: LogLevel.Info);
|
||||||
// If the amount the user is trying to send is smaller than the amount that they have spendable,
|
// If the amount the user is trying to send is smaller than the amount that they have spendable,
|
||||||
// then return 1, which indicates that they have an insufficient balance.
|
// then return 1, which indicates that they have an insufficient balance.
|
||||||
if (spendableSatoshiValue < satoshiAmountToSend) {
|
if (spendableSatoshiValue < satoshiAmountToSend) {
|
||||||
|
@ -2284,10 +2298,14 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
inputsBeingConsumed += 1;
|
inputsBeingConsumed += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.instance.log("satoshisBeingUsed: $satoshisBeingUsed", level: LogLevel.Info);
|
Logging.instance
|
||||||
Logging.instance.log("inputsBeingConsumed: $inputsBeingConsumed", level: LogLevel.Info);
|
.log("satoshisBeingUsed: $satoshisBeingUsed", level: LogLevel.Info);
|
||||||
Logging.instance.log('utxoObjectsToUse: $utxoObjectsToUse', level: LogLevel.Info);
|
Logging.instance
|
||||||
Logging.instance.log('satoshiAmountToSend $satoshiAmountToSend', level: LogLevel.Info);
|
.log("inputsBeingConsumed: $inputsBeingConsumed", level: LogLevel.Info);
|
||||||
|
Logging.instance
|
||||||
|
.log('utxoObjectsToUse: $utxoObjectsToUse', level: LogLevel.Info);
|
||||||
|
Logging.instance
|
||||||
|
.log('satoshiAmountToSend $satoshiAmountToSend', level: LogLevel.Info);
|
||||||
|
|
||||||
// numberOfOutputs' length must always be equal to that of recipientsArray and recipientsAmtArray
|
// numberOfOutputs' length must always be equal to that of recipientsArray and recipientsAmtArray
|
||||||
List<String> recipientsArray = [_recipientAddress];
|
List<String> recipientsArray = [_recipientAddress];
|
||||||
|
@ -2297,7 +2315,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
final utxoSigningData = await fetchBuildTxData(utxoObjectsToUse);
|
final utxoSigningData = await fetchBuildTxData(utxoObjectsToUse);
|
||||||
|
|
||||||
if (isSendAll) {
|
if (isSendAll) {
|
||||||
Logging.instance.log("Attempting to send all $coin", level: LogLevel.Info);
|
Logging.instance
|
||||||
|
.log("Attempting to send all $coin", level: LogLevel.Info);
|
||||||
|
|
||||||
final int vSizeForOneOutput = (await buildTransaction(
|
final int vSizeForOneOutput = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
utxosToUse: utxoObjectsToUse,
|
||||||
|
@ -2362,8 +2381,10 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
feeRatePerKB: selectedTxFeeRate,
|
feeRatePerKB: selectedTxFeeRate,
|
||||||
);
|
);
|
||||||
|
|
||||||
Logging.instance.log("feeForTwoOutputs: $feeForTwoOutputs", level: LogLevel.Info);
|
Logging.instance
|
||||||
Logging.instance.log("feeForOneOutput: $feeForOneOutput", level: LogLevel.Info);
|
.log("feeForTwoOutputs: $feeForTwoOutputs", level: LogLevel.Info);
|
||||||
|
Logging.instance
|
||||||
|
.log("feeForOneOutput: $feeForOneOutput", level: LogLevel.Info);
|
||||||
if (feeForOneOutput < (vSizeForOneOutput + 1) * 1000) {
|
if (feeForOneOutput < (vSizeForOneOutput + 1) * 1000) {
|
||||||
feeForOneOutput = (vSizeForOneOutput + 1) * 1000;
|
feeForOneOutput = (vSizeForOneOutput + 1) * 1000;
|
||||||
}
|
}
|
||||||
|
@ -2371,8 +2392,10 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
feeForTwoOutputs = ((vSizeForTwoOutPuts + 1) * 1000);
|
feeForTwoOutputs = ((vSizeForTwoOutPuts + 1) * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.instance.log("feeForTwoOutputs: $feeForTwoOutputs", level: LogLevel.Info);
|
Logging.instance
|
||||||
Logging.instance.log("feeForOneOutput: $feeForOneOutput", level: LogLevel.Info);
|
.log("feeForTwoOutputs: $feeForTwoOutputs", level: LogLevel.Info);
|
||||||
|
Logging.instance
|
||||||
|
.log("feeForOneOutput: $feeForOneOutput", level: LogLevel.Info);
|
||||||
|
|
||||||
if (satoshisBeingUsed - satoshiAmountToSend > feeForOneOutput) {
|
if (satoshisBeingUsed - satoshiAmountToSend > feeForOneOutput) {
|
||||||
if (satoshisBeingUsed - satoshiAmountToSend >
|
if (satoshisBeingUsed - satoshiAmountToSend >
|
||||||
|
@ -2400,12 +2423,17 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
// At this point, we have the outputs we're going to use, the amounts to send along with which addresses
|
// At this point, we have the outputs we're going to use, the amounts to send along with which addresses
|
||||||
// we intend to send these amounts to. We have enough to send instructions to build the transaction.
|
// we intend to send these amounts to. We have enough to send instructions to build the transaction.
|
||||||
Logging.instance.log('2 outputs in tx', level: LogLevel.Info);
|
Logging.instance.log('2 outputs in tx', level: LogLevel.Info);
|
||||||
Logging.instance.log('Input size: $satoshisBeingUsed', level: LogLevel.Info);
|
|
||||||
Logging.instance.log('Recipient output size: $satoshiAmountToSend', level: LogLevel.Info);
|
|
||||||
Logging.instance.log('Change Output Size: $changeOutputSize', level: LogLevel.Info);
|
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Difference (fee being paid): $feeBeingPaid sats', level: LogLevel.Info);
|
.log('Input size: $satoshisBeingUsed', level: LogLevel.Info);
|
||||||
Logging.instance.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
Logging.instance.log('Recipient output size: $satoshiAmountToSend',
|
||||||
|
level: LogLevel.Info);
|
||||||
|
Logging.instance.log('Change Output Size: $changeOutputSize',
|
||||||
|
level: LogLevel.Info);
|
||||||
|
Logging.instance.log(
|
||||||
|
'Difference (fee being paid): $feeBeingPaid sats',
|
||||||
|
level: LogLevel.Info);
|
||||||
|
Logging.instance
|
||||||
|
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
utxosToUse: utxoObjectsToUse,
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
|
@ -2421,14 +2449,19 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
satoshisBeingUsed - satoshiAmountToSend - changeOutputSize;
|
satoshisBeingUsed - satoshiAmountToSend - changeOutputSize;
|
||||||
recipientsAmtArray.removeLast();
|
recipientsAmtArray.removeLast();
|
||||||
recipientsAmtArray.add(changeOutputSize);
|
recipientsAmtArray.add(changeOutputSize);
|
||||||
Logging.instance.log('Adjusted Input size: $satoshisBeingUsed', level: LogLevel.Info);
|
Logging.instance.log('Adjusted Input size: $satoshisBeingUsed',
|
||||||
Logging.instance
|
level: LogLevel.Info);
|
||||||
.log('Adjusted Recipient output size: $satoshiAmountToSend', level: LogLevel.Info);
|
|
||||||
Logging.instance
|
|
||||||
.log('Adjusted Change Output Size: $changeOutputSize', level: LogLevel.Info);
|
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
'Adjusted Difference (fee being paid): $feeBeingPaid sats', level: LogLevel.Info);
|
'Adjusted Recipient output size: $satoshiAmountToSend',
|
||||||
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
|
Logging.instance.log(
|
||||||
|
'Adjusted Change Output Size: $changeOutputSize',
|
||||||
|
level: LogLevel.Info);
|
||||||
|
Logging.instance.log(
|
||||||
|
'Adjusted Difference (fee being paid): $feeBeingPaid sats',
|
||||||
|
level: LogLevel.Info);
|
||||||
|
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
||||||
|
level: LogLevel.Info);
|
||||||
txn = await buildTransaction(
|
txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
utxosToUse: utxoObjectsToUse,
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
|
@ -2449,11 +2482,15 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
// Something went wrong here. It either overshot or undershot the estimated fee amount or the changeOutputSize
|
// Something went wrong here. It either overshot or undershot the estimated fee amount or the changeOutputSize
|
||||||
// is smaller than or equal to [DUST_LIMIT]. Revert to single output transaction.
|
// is smaller than or equal to [DUST_LIMIT]. Revert to single output transaction.
|
||||||
Logging.instance.log('1 output in tx', level: LogLevel.Info);
|
Logging.instance.log('1 output in tx', level: LogLevel.Info);
|
||||||
Logging.instance.log('Input size: $satoshisBeingUsed', level: LogLevel.Info);
|
Logging.instance
|
||||||
Logging.instance.log('Recipient output size: $satoshiAmountToSend', level: LogLevel.Info);
|
.log('Input size: $satoshisBeingUsed', level: LogLevel.Info);
|
||||||
|
Logging.instance.log('Recipient output size: $satoshiAmountToSend',
|
||||||
|
level: LogLevel.Info);
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats', level: LogLevel.Info);
|
'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats',
|
||||||
Logging.instance.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
|
Logging.instance
|
||||||
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
utxosToUse: utxoObjectsToUse,
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
|
@ -2474,11 +2511,15 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
// which makes it uneconomical to add to the transaction. Here, we pass data directly to instruct
|
// which makes it uneconomical to add to the transaction. Here, we pass data directly to instruct
|
||||||
// the wallet to begin crafting the transaction that the user requested.
|
// the wallet to begin crafting the transaction that the user requested.
|
||||||
Logging.instance.log('1 output in tx', level: LogLevel.Info);
|
Logging.instance.log('1 output in tx', level: LogLevel.Info);
|
||||||
Logging.instance.log('Input size: $satoshisBeingUsed', level: LogLevel.Info);
|
Logging.instance
|
||||||
Logging.instance.log('Recipient output size: $satoshiAmountToSend', level: LogLevel.Info);
|
.log('Input size: $satoshisBeingUsed', level: LogLevel.Info);
|
||||||
|
Logging.instance.log('Recipient output size: $satoshiAmountToSend',
|
||||||
|
level: LogLevel.Info);
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats', level: LogLevel.Info);
|
'Difference (fee being paid): ${satoshisBeingUsed - satoshiAmountToSend} sats',
|
||||||
Logging.instance.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
|
Logging.instance
|
||||||
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
utxosToUse: utxoObjectsToUse,
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
|
@ -2499,11 +2540,15 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
// what we need to pay for fees. Here, we pass data directly to instruct the wallet to begin
|
// what we need to pay for fees. Here, we pass data directly to instruct the wallet to begin
|
||||||
// crafting the transaction that the user requested.
|
// crafting the transaction that the user requested.
|
||||||
Logging.instance.log('1 output in tx', level: LogLevel.Info);
|
Logging.instance.log('1 output in tx', level: LogLevel.Info);
|
||||||
Logging.instance.log('Input size: $satoshisBeingUsed', level: LogLevel.Info);
|
Logging.instance
|
||||||
Logging.instance.log('Recipient output size: $satoshiAmountToSend', level: LogLevel.Info);
|
.log('Input size: $satoshisBeingUsed', level: LogLevel.Info);
|
||||||
|
Logging.instance.log('Recipient output size: $satoshiAmountToSend',
|
||||||
|
level: LogLevel.Info);
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
'Fee being paid: ${satoshisBeingUsed - satoshiAmountToSend} sats', level: LogLevel.Info);
|
'Fee being paid: ${satoshisBeingUsed - satoshiAmountToSend} sats',
|
||||||
Logging.instance.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
|
Logging.instance
|
||||||
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
utxosToUse: utxoObjectsToUse,
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
|
@ -2523,7 +2568,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
// pay for the transaction fee. Ideally, at this stage, we should check if the user has any
|
// pay for the transaction fee. Ideally, at this stage, we should check if the user has any
|
||||||
// additional outputs they're able to spend and then recalculate fees.
|
// additional outputs they're able to spend and then recalculate fees.
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
'Cannot pay tx fee - checking for more outputs and trying again', level: LogLevel.Warning);
|
'Cannot pay tx fee - checking for more outputs and trying again',
|
||||||
|
level: LogLevel.Warning);
|
||||||
// try adding more outputs
|
// try adding more outputs
|
||||||
if (spendableOutputs.length > inputsBeingConsumed) {
|
if (spendableOutputs.length > inputsBeingConsumed) {
|
||||||
return coinSelection(satoshiAmountToSend, selectedTxFeeRate,
|
return coinSelection(satoshiAmountToSend, selectedTxFeeRate,
|
||||||
|
@ -2630,7 +2676,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
Logging.instance
|
||||||
|
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2642,7 +2689,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
required List<String> recipients,
|
required List<String> recipients,
|
||||||
required List<int> satoshiAmounts,
|
required List<int> satoshiAmounts,
|
||||||
}) async {
|
}) async {
|
||||||
Logging.instance.log("Starting buildTransaction ----------", level: LogLevel.Info);
|
Logging.instance
|
||||||
|
.log("Starting buildTransaction ----------", level: LogLevel.Info);
|
||||||
|
|
||||||
final txb = TransactionBuilder(network: _network);
|
final txb = TransactionBuilder(network: _network);
|
||||||
txb.setVersion(1);
|
txb.setVersion(1);
|
||||||
|
@ -2671,8 +2719,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance
|
Logging.instance.log("Caught exception while signing transaction: $e\n$s",
|
||||||
.log("Caught exception while signing transaction: $e\n$s", level: LogLevel.Error);
|
level: LogLevel.Error);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2733,7 +2781,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
await _rescanRestore();
|
await _rescanRestore();
|
||||||
|
|
||||||
longMutex = false;
|
longMutex = false;
|
||||||
Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s", level: LogLevel.Error);
|
Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s",
|
||||||
|
level: LogLevel.Error);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2884,7 +2933,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
||||||
return DB.instance.get<dynamic>(boxName: walletId, key: "isFavorite")
|
return DB.instance.get<dynamic>(boxName: walletId, key: "isFavorite")
|
||||||
as bool;
|
as bool;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("isFavorite fetch failed: $e\n$s", level: LogLevel.Error);
|
Logging.instance
|
||||||
|
.log("isFavorite fetch failed: $e\n$s", level: LogLevel.Error);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:decimal/decimal.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_libepiccash/epic_cash.dart';
|
import 'package:flutter_libepiccash/epic_cash.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:mutex/mutex.dart';
|
import 'package:mutex/mutex.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
@ -39,6 +40,17 @@ const int MINIMUM_CONFIRMATIONS = 10;
|
||||||
const String GENESIS_HASH_MAINNET = "";
|
const String GENESIS_HASH_MAINNET = "";
|
||||||
const String GENESIS_HASH_TESTNET = "";
|
const String GENESIS_HASH_TESTNET = "";
|
||||||
|
|
||||||
|
class BadEpicHttpAddressException implements Exception {
|
||||||
|
final String? message;
|
||||||
|
|
||||||
|
BadEpicHttpAddressException({this.message});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return "BadEpicHttpAddressException: $message";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// isolate
|
// isolate
|
||||||
|
|
||||||
Map<ReceivePort, Isolate> isolates = {};
|
Map<ReceivePort, Isolate> isolates = {};
|
||||||
|
@ -61,123 +73,110 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
|
||||||
final function = arguments['function'] as String;
|
final function = arguments['function'] as String;
|
||||||
try {
|
try {
|
||||||
if (function == "scanOutPuts") {
|
if (function == "scanOutPuts") {
|
||||||
final config = arguments['config'] as String?;
|
final wallet = arguments['wallet'] as String?;
|
||||||
final password = arguments['password'] as String?;
|
|
||||||
final startHeight = arguments['startHeight'] as int?;
|
final startHeight = arguments['startHeight'] as int?;
|
||||||
final numberOfBlocks = arguments['numberOfBlocks'] as int?;
|
final numberOfBlocks = arguments['numberOfBlocks'] as int?;
|
||||||
Map<String, dynamic> result = {};
|
Map<String, dynamic> result = {};
|
||||||
if (!(config == null ||
|
if (!(wallet == null ||
|
||||||
password == null ||
|
|
||||||
startHeight == null ||
|
startHeight == null ||
|
||||||
numberOfBlocks == null)) {
|
numberOfBlocks == null)) {
|
||||||
var outputs =
|
var outputs =
|
||||||
await scanOutPuts(config, password, startHeight, numberOfBlocks);
|
await scanOutPuts(wallet, startHeight, numberOfBlocks);
|
||||||
result['outputs'] = outputs;
|
result['outputs'] = outputs;
|
||||||
sendPort.send(result);
|
sendPort.send(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (function == "getPendingSlates") {
|
} else if (function == "getPendingSlates") {
|
||||||
final config = arguments['config'] as String?;
|
final wallet = arguments['wallet'] as String?;
|
||||||
final password = arguments['password'] as String?;
|
|
||||||
final secretKeyIndex = arguments['secretKeyIndex'] as int?;
|
final secretKeyIndex = arguments['secretKeyIndex'] as int?;
|
||||||
final slates = arguments['slates'] as String;
|
final slates = arguments['slates'] as String;
|
||||||
Map<String, dynamic> result = {};
|
Map<String, dynamic> result = {};
|
||||||
|
|
||||||
if (!(config == null || password == null || secretKeyIndex == null)) {
|
if (!(wallet == null || secretKeyIndex == null)) {
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log("SECRET_KEY_INDEX_IS $secretKeyIndex", level: LogLevel.Info);
|
.log("SECRET_KEY_INDEX_IS $secretKeyIndex", level: LogLevel.Info);
|
||||||
result['result'] =
|
result['result'] =
|
||||||
await getPendingSlates(config, password, secretKeyIndex, slates);
|
await getPendingSlates(wallet, secretKeyIndex, slates);
|
||||||
sendPort.send(result);
|
sendPort.send(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (function == "subscribeRequest") {
|
} else if (function == "subscribeRequest") {
|
||||||
final config = arguments['config'] as String?;
|
final wallet = arguments['wallet'] as String?;
|
||||||
final password = arguments['password'] as String?;
|
|
||||||
final secretKeyIndex = arguments['secretKeyIndex'] as int?;
|
final secretKeyIndex = arguments['secretKeyIndex'] as int?;
|
||||||
final epicboxConfig = arguments['epicboxConfig'] as String?;
|
final epicboxConfig = arguments['epicboxConfig'] as String?;
|
||||||
Map<String, dynamic> result = {};
|
Map<String, dynamic> result = {};
|
||||||
|
|
||||||
if (!(config == null ||
|
if (!(wallet == null ||
|
||||||
password == null ||
|
|
||||||
secretKeyIndex == null ||
|
secretKeyIndex == null ||
|
||||||
epicboxConfig == null)) {
|
epicboxConfig == null)) {
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log("SECRET_KEY_INDEX_IS $secretKeyIndex", level: LogLevel.Info);
|
.log("SECRET_KEY_INDEX_IS $secretKeyIndex", level: LogLevel.Info);
|
||||||
result['result'] = await getSubscribeRequest(
|
result['result'] = await getSubscribeRequest(
|
||||||
config, password, secretKeyIndex, epicboxConfig);
|
wallet, secretKeyIndex, epicboxConfig);
|
||||||
sendPort.send(result);
|
sendPort.send(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (function == "processSlates") {
|
} else if (function == "processSlates") {
|
||||||
final config = arguments['config'] as String?;
|
final wallet = arguments['wallet'] as String?;
|
||||||
final password = arguments['password'] as String?;
|
|
||||||
final slates = arguments['slates'];
|
final slates = arguments['slates'];
|
||||||
Map<String, dynamic> result = {};
|
Map<String, dynamic> result = {};
|
||||||
|
|
||||||
if (!(config == null || password == null || slates == null)) {
|
if (!(wallet == null || slates == null)) {
|
||||||
result['result'] =
|
result['result'] =
|
||||||
await processSlates(config, password, slates.toString());
|
await processSlates(wallet, slates.toString());
|
||||||
sendPort.send(result);
|
sendPort.send(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (function == "getWalletInfo") {
|
} else if (function == "getWalletInfo") {
|
||||||
final config = arguments['config'] as String?;
|
final wallet = arguments['wallet'] as String?;
|
||||||
final password = arguments['password'] as String?;
|
|
||||||
final refreshFromNode = arguments['refreshFromNode'] as int?;
|
final refreshFromNode = arguments['refreshFromNode'] as int?;
|
||||||
final minimumConfirmations = arguments['minimumConfirmations'] as int?;
|
final minimumConfirmations = arguments['minimumConfirmations'] as int?;
|
||||||
Map<String, dynamic> result = {};
|
Map<String, dynamic> result = {};
|
||||||
if (!(config == null ||
|
if (!(wallet == null ||
|
||||||
password == null ||
|
|
||||||
refreshFromNode == null ||
|
refreshFromNode == null ||
|
||||||
minimumConfirmations == null)) {
|
minimumConfirmations == null)) {
|
||||||
var res = await getWalletInfo(
|
var res = await getWalletInfo(
|
||||||
config, password, refreshFromNode, minimumConfirmations);
|
wallet, refreshFromNode, minimumConfirmations);
|
||||||
result['result'] = res;
|
result['result'] = res;
|
||||||
sendPort.send(result);
|
sendPort.send(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (function == "getTransactions") {
|
} else if (function == "getTransactions") {
|
||||||
final config = arguments['config'] as String?;
|
final wallet = arguments['wallet'] as String?;
|
||||||
final password = arguments['password'] as String?;
|
|
||||||
final refreshFromNode = arguments['refreshFromNode'] as int?;
|
final refreshFromNode = arguments['refreshFromNode'] as int?;
|
||||||
Map<String, dynamic> result = {};
|
Map<String, dynamic> result = {};
|
||||||
if (!(config == null || password == null || refreshFromNode == null)) {
|
if (!(wallet == null || refreshFromNode == null)) {
|
||||||
var res = await getTransactions(config, password, refreshFromNode);
|
var res = await getTransactions(wallet, refreshFromNode);
|
||||||
result['result'] = res;
|
result['result'] = res;
|
||||||
sendPort.send(result);
|
sendPort.send(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (function == "startSync") {
|
} else if (function == "startSync") {
|
||||||
final config = arguments['config'] as String?;
|
final wallet = arguments['wallet'] as String?;
|
||||||
final password = arguments['password'] as String?;
|
|
||||||
const int refreshFromNode = 1;
|
const int refreshFromNode = 1;
|
||||||
Map<String, dynamic> result = {};
|
Map<String, dynamic> result = {};
|
||||||
if (!(config == null || password == null)) {
|
if (!(wallet == null)) {
|
||||||
var res = await getWalletInfo(config, password, refreshFromNode, 10);
|
var res = await getWalletInfo(wallet, refreshFromNode, 10);
|
||||||
result['result'] = res;
|
result['result'] = res;
|
||||||
sendPort.send(result);
|
sendPort.send(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (function == "getTransactionFees") {
|
} else if (function == "getTransactionFees") {
|
||||||
final config = arguments['config'] as String?;
|
final wallet = arguments['wallet'] as String?;
|
||||||
final password = arguments['password'] as String?;
|
|
||||||
final amount = arguments['amount'] as int?;
|
final amount = arguments['amount'] as int?;
|
||||||
final minimumConfirmations = arguments['minimumConfirmations'] as int?;
|
final minimumConfirmations = arguments['minimumConfirmations'] as int?;
|
||||||
Map<String, dynamic> result = {};
|
Map<String, dynamic> result = {};
|
||||||
if (!(config == null ||
|
if (!(wallet == null ||
|
||||||
password == null ||
|
|
||||||
amount == null ||
|
amount == null ||
|
||||||
minimumConfirmations == null)) {
|
minimumConfirmations == null)) {
|
||||||
var res = await getTransactionFees(
|
var res = await getTransactionFees(
|
||||||
config, password, amount, minimumConfirmations);
|
wallet, amount, minimumConfirmations);
|
||||||
result['result'] = res;
|
result['result'] = res;
|
||||||
sendPort.send(result);
|
sendPort.send(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (function == "createTransaction") {
|
} else if (function == "createTransaction") {
|
||||||
final config = arguments['config'] as String?;
|
final wallet = arguments['wallet'] as String?;
|
||||||
final password = arguments['password'] as String?;
|
|
||||||
final amount = arguments['amount'] as int?;
|
final amount = arguments['amount'] as int?;
|
||||||
final address = arguments['address'] as String?;
|
final address = arguments['address'] as String?;
|
||||||
final secretKeyIndex = arguments['secretKeyIndex'] as int?;
|
final secretKeyIndex = arguments['secretKeyIndex'] as int?;
|
||||||
|
@ -185,19 +184,41 @@ Future<void> executeNative(Map<String, dynamic> arguments) async {
|
||||||
final minimumConfirmations = arguments['minimumConfirmations'] as int?;
|
final minimumConfirmations = arguments['minimumConfirmations'] as int?;
|
||||||
|
|
||||||
Map<String, dynamic> result = {};
|
Map<String, dynamic> result = {};
|
||||||
if (!(config == null ||
|
if (!(wallet == null ||
|
||||||
password == null ||
|
|
||||||
amount == null ||
|
amount == null ||
|
||||||
address == null ||
|
address == null ||
|
||||||
secretKeyIndex == null ||
|
secretKeyIndex == null ||
|
||||||
epicboxConfig == null ||
|
epicboxConfig == null ||
|
||||||
minimumConfirmations == null)) {
|
minimumConfirmations == null)) {
|
||||||
var res = await createTransaction(config, password, amount, address,
|
var res = await createTransaction(wallet, amount, address,
|
||||||
secretKeyIndex, epicboxConfig, minimumConfirmations);
|
secretKeyIndex, epicboxConfig, minimumConfirmations);
|
||||||
result['result'] = res;
|
result['result'] = res;
|
||||||
sendPort.send(result);
|
sendPort.send(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else if (function == "txHttpSend") {
|
||||||
|
final wallet = arguments['wallet'] as String?;
|
||||||
|
final selectionStrategyIsAll = arguments['selectionStrategyIsAll'] as int?;
|
||||||
|
final minimumConfirmations = arguments['minimumConfirmations'] as int?;
|
||||||
|
final message = arguments['message'] as String?;
|
||||||
|
final amount = arguments['amount'] as int?;
|
||||||
|
final address = arguments['address'] as String?;
|
||||||
|
|
||||||
|
Map<String, dynamic> result = {};
|
||||||
|
|
||||||
|
if (!(wallet == null ||
|
||||||
|
selectionStrategyIsAll == null ||
|
||||||
|
minimumConfirmations == null ||
|
||||||
|
message == null ||
|
||||||
|
amount == null ||
|
||||||
|
address == null)) {
|
||||||
|
var res = await txHttpSend(wallet, selectionStrategyIsAll,
|
||||||
|
minimumConfirmations, message, amount, address);
|
||||||
|
result['result'] = res;
|
||||||
|
sendPort.send(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Error Arguments for $function not formatted correctly",
|
"Error Arguments for $function not formatted correctly",
|
||||||
|
@ -225,14 +246,14 @@ void stop(ReceivePort port) {
|
||||||
// Keep Wrapper functions outside of the class to avoid memory leaks and errors about receive ports and illegal arguments.
|
// Keep Wrapper functions outside of the class to avoid memory leaks and errors about receive ports and illegal arguments.
|
||||||
// TODO: Can get rid of this wrapper and call it in a full isolate instead of compute() if we want more control over this
|
// TODO: Can get rid of this wrapper and call it in a full isolate instead of compute() if we want more control over this
|
||||||
Future<String> _cancelTransactionWrapper(
|
Future<String> _cancelTransactionWrapper(
|
||||||
Tuple3<String, String, String> data) async {
|
Tuple2<String, String> data) async {
|
||||||
// assuming this returns an empty string on success
|
// assuming this returns an empty string on success
|
||||||
// or an error message string on failure
|
// or an error message string on failure
|
||||||
return cancelTransaction(data.item1, data.item2, data.item3);
|
return cancelTransaction(data.item1, data.item2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> _deleteWalletWrapper(Tuple2<String, String> data) async {
|
Future<String> _deleteWalletWrapper(String wallet) async {
|
||||||
return deleteWallet(data.item1, data.item2);
|
return deleteWallet(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> deleteEpicWallet({
|
Future<String> deleteEpicWallet({
|
||||||
|
@ -255,9 +276,9 @@ Future<String> deleteEpicWallet({
|
||||||
config = jsonEncode(editConfig);
|
config = jsonEncode(editConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
final password = await secureStore.read(key: '${walletId}_password');
|
final wallet = await secureStore.read(key: '${walletId}_wallet');
|
||||||
|
|
||||||
return compute(_deleteWalletWrapper, Tuple2(config!, password!));
|
return compute(_deleteWalletWrapper, wallet!);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> _initWalletWrapper(
|
Future<String> _initWalletWrapper(
|
||||||
|
@ -268,9 +289,9 @@ Future<String> _initWalletWrapper(
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> _initGetAddressInfoWrapper(
|
Future<String> _initGetAddressInfoWrapper(
|
||||||
Tuple4<String, String, int, String> data) async {
|
Tuple3<String, int, String> data) async {
|
||||||
String walletAddress =
|
String walletAddress =
|
||||||
getAddressInfo(data.item1, data.item2, data.item3, data.item4);
|
getAddressInfo(data.item1, data.item2, data.item3);
|
||||||
return walletAddress;
|
return walletAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,16 +585,14 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
Future<String> startSync() async {
|
Future<String> startSync() async {
|
||||||
Logging.instance.log("request start sync", level: LogLevel.Info);
|
Logging.instance.log("request start sync", level: LogLevel.Info);
|
||||||
final config = await getRealConfig();
|
final wallet = await _secureStore.read(key: '${_walletId}_wallet');
|
||||||
final password = await _secureStore.read(key: '${_walletId}_password');
|
|
||||||
|
|
||||||
if (!syncMutex.isLocked) {
|
if (!syncMutex.isLocked) {
|
||||||
await syncMutex.protect(() async {
|
await syncMutex.protect(() async {
|
||||||
Logging.instance.log("sync started", level: LogLevel.Info);
|
Logging.instance.log("sync started", level: LogLevel.Info);
|
||||||
ReceivePort receivePort = await getIsolate({
|
ReceivePort receivePort = await getIsolate({
|
||||||
"function": "startSync",
|
"function": "startSync",
|
||||||
"config": config,
|
"wallet": wallet!,
|
||||||
"password": password!,
|
|
||||||
}, name: walletName);
|
}, name: walletName);
|
||||||
this.receivePort = receivePort;
|
this.receivePort = receivePort;
|
||||||
|
|
||||||
|
@ -596,17 +615,14 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> allWalletBalances() async {
|
Future<String> allWalletBalances() async {
|
||||||
final config = await getRealConfig();
|
final wallet = await _secureStore.read(key: '${_walletId}_wallet');
|
||||||
final password = await _secureStore.read(key: '${_walletId}_password');
|
|
||||||
|
|
||||||
const refreshFromNode = 0;
|
const refreshFromNode = 0;
|
||||||
|
|
||||||
dynamic message;
|
dynamic message;
|
||||||
await m.protect(() async {
|
await m.protect(() async {
|
||||||
ReceivePort receivePort = await getIsolate({
|
ReceivePort receivePort = await getIsolate({
|
||||||
"function": "getWalletInfo",
|
"function": "getWalletInfo",
|
||||||
"config": config,
|
"wallet": wallet!,
|
||||||
"password": password!,
|
|
||||||
"refreshFromNode": refreshFromNode,
|
"refreshFromNode": refreshFromNode,
|
||||||
"minimumConfirmations": MINIMUM_CONFIRMATIONS,
|
"minimumConfirmations": MINIMUM_CONFIRMATIONS,
|
||||||
}, name: walletName);
|
}, name: walletName);
|
||||||
|
@ -652,9 +668,7 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
late PriceAPI _priceAPI;
|
late PriceAPI _priceAPI;
|
||||||
|
|
||||||
Future<String> cancelPendingTransactionAndPost(String tx_slate_id) async {
|
Future<String> cancelPendingTransactionAndPost(String tx_slate_id) async {
|
||||||
final String config = await getRealConfig();
|
final wallet = await _secureStore.read(key: '${_walletId}_wallet');
|
||||||
final String password =
|
|
||||||
(await _secureStore.read(key: '${_walletId}_password'))!;
|
|
||||||
final int? receivingIndex = DB.instance
|
final int? receivingIndex = DB.instance
|
||||||
.get<dynamic>(boxName: walletId, key: "receivingIndex") as int?;
|
.get<dynamic>(boxName: walletId, key: "receivingIndex") as int?;
|
||||||
final epicboxConfig =
|
final epicboxConfig =
|
||||||
|
@ -677,8 +691,7 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
await m.protect(() async {
|
await m.protect(() async {
|
||||||
ReceivePort receivePort = await getIsolate({
|
ReceivePort receivePort = await getIsolate({
|
||||||
"function": "subscribeRequest",
|
"function": "subscribeRequest",
|
||||||
"config": config,
|
"wallet": wallet,
|
||||||
"password": password,
|
|
||||||
"secretKeyIndex": currentReceivingIndex!,
|
"secretKeyIndex": currentReceivingIndex!,
|
||||||
"epicboxConfig": epicboxConfig,
|
"epicboxConfig": epicboxConfig,
|
||||||
}, name: walletName);
|
}, name: walletName);
|
||||||
|
@ -713,17 +726,15 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
//
|
//
|
||||||
/// returns an empty String on success, error message on failure
|
/// returns an empty String on success, error message on failure
|
||||||
Future<String> cancelPendingTransaction(String tx_slate_id) async {
|
Future<String> cancelPendingTransaction(String tx_slate_id) async {
|
||||||
final String config = await getRealConfig();
|
final String wallet =
|
||||||
final String password =
|
(await _secureStore.read(key: '${_walletId}_wallet'))!;
|
||||||
(await _secureStore.read(key: '${_walletId}_password'))!;
|
|
||||||
|
|
||||||
String? result;
|
String? result;
|
||||||
await m.protect(() async {
|
await m.protect(() async {
|
||||||
result = await compute(
|
result = await compute(
|
||||||
_cancelTransactionWrapper,
|
_cancelTransactionWrapper,
|
||||||
Tuple3(
|
Tuple2(
|
||||||
config,
|
wallet,
|
||||||
password,
|
|
||||||
tx_slate_id,
|
tx_slate_id,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -734,41 +745,71 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
@override
|
@override
|
||||||
Future<String> confirmSend({required Map<String, dynamic> txData}) async {
|
Future<String> confirmSend({required Map<String, dynamic> txData}) async {
|
||||||
try {
|
try {
|
||||||
final config = await getRealConfig();
|
final wallet = await _secureStore.read(key: '${_walletId}_wallet');
|
||||||
final password = await _secureStore.read(key: '${_walletId}_password');
|
|
||||||
final epicboxConfig =
|
final epicboxConfig =
|
||||||
await _secureStore.read(key: '${_walletId}_epicboxConfig');
|
await _secureStore.read(key: '${_walletId}_epicboxConfig');
|
||||||
|
|
||||||
// TODO determine whether it is worth sending change to a change address.
|
// TODO determine whether it is worth sending change to a change address.
|
||||||
dynamic message;
|
dynamic message;
|
||||||
await m.protect(() async {
|
|
||||||
ReceivePort receivePort = await getIsolate({
|
|
||||||
"function": "createTransaction",
|
|
||||||
"config": config,
|
|
||||||
"password": password!,
|
|
||||||
"amount": txData['recipientAmt'],
|
|
||||||
"address": txData['addresss'],
|
|
||||||
"secretKeyIndex": 0,
|
|
||||||
"epicboxConfig": epicboxConfig!,
|
|
||||||
"minimumConfirmations": MINIMUM_CONFIRMATIONS,
|
|
||||||
}, name: walletName);
|
|
||||||
|
|
||||||
message = await receivePort.first;
|
String receiverAddress = txData['addresss'] as String;
|
||||||
if (message is String) {
|
await m.protect(() async {
|
||||||
Logging.instance
|
if (receiverAddress.startsWith("http://") || receiverAddress.startsWith("https://")) {
|
||||||
.log("this is a string $message", level: LogLevel.Error);
|
const int selectionStrategyIsAll = 0;
|
||||||
|
ReceivePort receivePort = await getIsolate({
|
||||||
|
"function": "txHttpSend",
|
||||||
|
"wallet": wallet!,
|
||||||
|
"selectionStrategyIsAll": selectionStrategyIsAll,
|
||||||
|
"minimumConfirmations": MINIMUM_CONFIRMATIONS,
|
||||||
|
"message": "",
|
||||||
|
"amount": txData['recipientAmt'],
|
||||||
|
"address": txData['addresss']
|
||||||
|
}, name: walletName);
|
||||||
|
|
||||||
|
message = await receivePort.first;
|
||||||
|
if (message is String) {
|
||||||
|
Logging.instance
|
||||||
|
.log("this is a string $message", level: LogLevel.Error);
|
||||||
|
stop(receivePort);
|
||||||
|
throw Exception("txHttpSend isolate failed");
|
||||||
|
}
|
||||||
stop(receivePort);
|
stop(receivePort);
|
||||||
throw Exception("createTransaction isolate failed");
|
Logging.instance.log('Closing txHttpSend!\n $message',
|
||||||
|
level: LogLevel.Info);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ReceivePort receivePort = await getIsolate({
|
||||||
|
"function": "createTransaction",
|
||||||
|
"wallet": wallet!,
|
||||||
|
"amount": txData['recipientAmt'],
|
||||||
|
"address": txData['addresss'],
|
||||||
|
"secretKeyIndex": 0,
|
||||||
|
"epicboxConfig": epicboxConfig!,
|
||||||
|
"minimumConfirmations": MINIMUM_CONFIRMATIONS,
|
||||||
|
}, name: walletName);
|
||||||
|
|
||||||
|
message = await receivePort.first;
|
||||||
|
if (message is String) {
|
||||||
|
Logging.instance
|
||||||
|
.log("this is a string $message", level: LogLevel.Error);
|
||||||
|
stop(receivePort);
|
||||||
|
throw Exception("createTransaction isolate failed");
|
||||||
|
}
|
||||||
|
stop(receivePort);
|
||||||
|
Logging.instance.log('Closing createTransaction!\n $message',
|
||||||
|
level: LogLevel.Info);
|
||||||
}
|
}
|
||||||
stop(receivePort);
|
|
||||||
Logging.instance.log('Closing createTransaction!\n $message',
|
|
||||||
level: LogLevel.Info);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// return message;
|
// return message;
|
||||||
final String sendTx = message['result'] as String;
|
final String sendTx = message['result'] as String;
|
||||||
|
if (sendTx.contains("Error")) {
|
||||||
|
throw BadEpicHttpAddressException(message: sendTx);
|
||||||
|
}
|
||||||
|
|
||||||
await putSendToAddresses(sendTx);
|
await putSendToAddresses(sendTx);
|
||||||
|
|
||||||
|
|
||||||
Logging.instance.log("CONFIRM_RESULT_IS $sendTx", level: LogLevel.Info);
|
Logging.instance.log("CONFIRM_RESULT_IS $sendTx", level: LogLevel.Info);
|
||||||
|
|
||||||
final decodeData = json.decode(sendTx);
|
final decodeData = json.decode(sendTx);
|
||||||
|
@ -777,22 +818,30 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
String errorMessage = decodeData[1] as String;
|
String errorMessage = decodeData[1] as String;
|
||||||
throw Exception("Transaction failed with error code $errorMessage");
|
throw Exception("Transaction failed with error code $errorMessage");
|
||||||
} else {
|
} else {
|
||||||
final postSlateRequest = decodeData[1];
|
|
||||||
final postToServer = await postSlate(
|
//If it's HTTP send no need to post to epicbox
|
||||||
txData['addresss'] as String, postSlateRequest as String);
|
if (!(receiverAddress.startsWith("http://") || receiverAddress.startsWith("https://"))) {
|
||||||
Logging.instance
|
final postSlateRequest = decodeData[1];
|
||||||
.log("POST_SLATE_IS $postToServer", level: LogLevel.Info);
|
final postToServer = await postSlate(
|
||||||
//await postSlate
|
txData['addresss'] as String, postSlateRequest as String);
|
||||||
|
Logging.instance
|
||||||
|
.log("POST_SLATE_IS $postToServer", level: LogLevel.Info);
|
||||||
|
}
|
||||||
|
|
||||||
final txCreateResult = decodeData[0];
|
final txCreateResult = decodeData[0];
|
||||||
// //TODO: second problem
|
// //TODO: second problem
|
||||||
final transaction = txCreateResult[0];
|
final transaction = json.decode(txCreateResult as String);
|
||||||
|
|
||||||
// final wallet = await Hive.openBox<dynamic>(_walletId);
|
Logger.print("TX_IS $transaction");
|
||||||
// final slateToAddresses = (await wallet.get("slate_to_address")) as Map?;
|
final tx = transaction[0];
|
||||||
// slateToAddresses![transaction[0]['tx_slate_id']] = txData['addresss'];
|
final txLogEntry = json.decode(tx as String);
|
||||||
// await wallet.put('slate_to_address', slateToAddresses);
|
final txLogEntryFirst = txLogEntry[0];
|
||||||
// return transaction[0]['tx_slate_id'] as String;
|
Logger.print("TX_LOG_ENTRY_IS $txLogEntryFirst");
|
||||||
return "";
|
final wallet = await Hive.openBox<dynamic>(_walletId);
|
||||||
|
final slateToAddresses = (await wallet.get("slate_to_address")) as Map?;
|
||||||
|
slateToAddresses?[txLogEntryFirst['tx_slate_id']] = txData['addresss'];
|
||||||
|
await wallet.put('slate_to_address', slateToAddresses);
|
||||||
|
return txLogEntryFirst['tx_slate_id'] as String;
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("Error sending $e - $s", level: LogLevel.Error);
|
Logging.instance.log("Error sending $e - $s", level: LogLevel.Error);
|
||||||
|
@ -806,8 +855,7 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
Future<String> _getCurrentAddressForChain(
|
Future<String> _getCurrentAddressForChain(
|
||||||
int chain,
|
int chain,
|
||||||
) async {
|
) async {
|
||||||
final config = await getRealConfig();
|
final wallet = await _secureStore.read(key: '${_walletId}_wallet');
|
||||||
final password = await _secureStore.read(key: '${_walletId}_password');
|
|
||||||
final epicboxConfig =
|
final epicboxConfig =
|
||||||
await _secureStore.read(key: '${_walletId}_epicboxConfig');
|
await _secureStore.read(key: '${_walletId}_epicboxConfig');
|
||||||
|
|
||||||
|
@ -815,7 +863,7 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
await m.protect(() async {
|
await m.protect(() async {
|
||||||
walletAddress = await compute(
|
walletAddress = await compute(
|
||||||
_initGetAddressInfoWrapper,
|
_initGetAddressInfoWrapper,
|
||||||
Tuple4(config, password!, chain, epicboxConfig!),
|
Tuple3(wallet!, chain, epicboxConfig!),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
Logging.instance
|
Logging.instance
|
||||||
|
@ -920,6 +968,13 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
Logging.instance.log("Opening existing ${coin.prettyName} wallet",
|
Logging.instance.log("Opening existing ${coin.prettyName} wallet",
|
||||||
level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
|
|
||||||
|
final config = await getRealConfig();
|
||||||
|
final password =
|
||||||
|
await _secureStore.read(key: '${_walletId}_password');
|
||||||
|
|
||||||
|
final walletOpen = openWallet(config!, password!);
|
||||||
|
await _secureStore.write(key: '${_walletId}_wallet', value: walletOpen);
|
||||||
|
|
||||||
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) == null) {
|
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) == null) {
|
||||||
debugPrint("Exception was thrown");
|
debugPrint("Exception was thrown");
|
||||||
throw Exception(
|
throw Exception(
|
||||||
|
@ -937,8 +992,7 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> storeEpicboxInfo() async {
|
Future<void> storeEpicboxInfo() async {
|
||||||
final config = await getRealConfig();
|
final wallet = await _secureStore.read(key: '${_walletId}_wallet');
|
||||||
final password = await _secureStore.read(key: '${_walletId}_password');
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
Logging.instance.log("This index is $index", level: LogLevel.Info);
|
Logging.instance.log("This index is $index", level: LogLevel.Info);
|
||||||
|
@ -948,7 +1002,7 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
await m.protect(() async {
|
await m.protect(() async {
|
||||||
walletAddress = await compute(
|
walletAddress = await compute(
|
||||||
_initGetAddressInfoWrapper,
|
_initGetAddressInfoWrapper,
|
||||||
Tuple4(config, password!, index, epicboxConfig!),
|
Tuple3(wallet!, index, epicboxConfig!),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
Logging.instance
|
Logging.instance
|
||||||
|
@ -1008,6 +1062,10 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Open wallet
|
||||||
|
final walletOpen = openWallet(stringConfig, password);
|
||||||
|
await _secureStore.write(key: '${_walletId}_wallet', value: walletOpen);
|
||||||
|
|
||||||
//Store Epic box address info
|
//Store Epic box address info
|
||||||
await storeEpicboxInfo();
|
await storeEpicboxInfo();
|
||||||
|
|
||||||
|
@ -1106,16 +1164,14 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
Future<int> nativeFee(int satoshiAmount,
|
Future<int> nativeFee(int satoshiAmount,
|
||||||
{bool ifErrorEstimateFee = false}) async {
|
{bool ifErrorEstimateFee = false}) async {
|
||||||
final config = await getRealConfig();
|
final wallet = await _secureStore.read(key: '${_walletId}_wallet');
|
||||||
final password = await _secureStore.read(key: '${_walletId}_password');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String? transactionFees;
|
String? transactionFees;
|
||||||
await m.protect(() async {
|
await m.protect(() async {
|
||||||
ReceivePort receivePort = await getIsolate({
|
ReceivePort receivePort = await getIsolate({
|
||||||
"function": "getTransactionFees",
|
"function": "getTransactionFees",
|
||||||
"config": config,
|
"wallet": wallet!,
|
||||||
"password": password!,
|
|
||||||
"amount": satoshiAmount,
|
"amount": satoshiAmount,
|
||||||
"minimumConfirmations": MINIMUM_CONFIRMATIONS,
|
"minimumConfirmations": MINIMUM_CONFIRMATIONS,
|
||||||
}, name: walletName);
|
}, name: walletName);
|
||||||
|
@ -1241,8 +1297,8 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
Future<bool> startScans() async {
|
Future<bool> startScans() async {
|
||||||
try {
|
try {
|
||||||
String stringConfig = await getConfig();
|
|
||||||
final password = await _secureStore.read(key: '${_walletId}_password');
|
final wallet = await _secureStore.read(key: '${_walletId}_wallet');
|
||||||
|
|
||||||
var restoreHeight =
|
var restoreHeight =
|
||||||
DB.instance.get<dynamic>(boxName: walletId, key: "restoreHeight");
|
DB.instance.get<dynamic>(boxName: walletId, key: "restoreHeight");
|
||||||
|
@ -1272,8 +1328,7 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
await m.protect(() async {
|
await m.protect(() async {
|
||||||
ReceivePort receivePort = await getIsolate({
|
ReceivePort receivePort = await getIsolate({
|
||||||
"function": "scanOutPuts",
|
"function": "scanOutPuts",
|
||||||
"config": stringConfig,
|
"wallet": wallet!,
|
||||||
"password": password,
|
|
||||||
"startHeight": lastScannedBlock,
|
"startHeight": lastScannedBlock,
|
||||||
"numberOfBlocks": MAX_PER_LOOP,
|
"numberOfBlocks": MAX_PER_LOOP,
|
||||||
}, name: walletName);
|
}, name: walletName);
|
||||||
|
@ -1356,9 +1411,6 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
//Store Epic box address info
|
|
||||||
await storeEpicboxInfo();
|
|
||||||
|
|
||||||
await DB.instance
|
await DB.instance
|
||||||
.put<dynamic>(boxName: walletId, key: "restoreHeight", value: height);
|
.put<dynamic>(boxName: walletId, key: "restoreHeight", value: height);
|
||||||
|
|
||||||
|
@ -1387,27 +1439,13 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
await DB.instance
|
await DB.instance
|
||||||
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false);
|
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false);
|
||||||
|
|
||||||
//Scan wallet
|
//Open Wallet
|
||||||
await m.protect(() async {
|
final walletOpen = openWallet(stringConfig, password);
|
||||||
ReceivePort receivePort = await getIsolate({
|
await _secureStore.write(key: '${_walletId}_wallet', value: walletOpen);
|
||||||
"function": "scanOutPuts",
|
|
||||||
"config": stringConfig,
|
//Store Epic box address info
|
||||||
"password": password,
|
await storeEpicboxInfo();
|
||||||
"startHeight": 1550000,
|
|
||||||
"numberOfBlocks": 100,
|
|
||||||
}, name: walletName);
|
|
||||||
|
|
||||||
var message = await receivePort.first;
|
|
||||||
if (message is String) {
|
|
||||||
Logging.instance
|
|
||||||
.log("this is a string $message", level: LogLevel.Error);
|
|
||||||
stop(receivePort);
|
|
||||||
throw Exception("scanOutPuts isolate failed");
|
|
||||||
}
|
|
||||||
stop(receivePort);
|
|
||||||
Logging.instance
|
|
||||||
.log('Closing scanOutPuts!\n $message', level: LogLevel.Info);
|
|
||||||
});
|
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log("Error recovering wallet $e\n$s", level: LogLevel.Error);
|
.log("Error recovering wallet $e\n$s", level: LogLevel.Error);
|
||||||
|
@ -1588,16 +1626,14 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
currentReceivingIndex++) {
|
currentReceivingIndex++) {
|
||||||
final currentAddress =
|
final currentAddress =
|
||||||
await _getCurrentAddressForChain(currentReceivingIndex);
|
await _getCurrentAddressForChain(currentReceivingIndex);
|
||||||
final config = await getRealConfig();
|
final wallet = await _secureStore.read(key: '${_walletId}_wallet');
|
||||||
final password = await _secureStore.read(key: '${_walletId}_password');
|
|
||||||
final epicboxConfig =
|
final epicboxConfig =
|
||||||
await _secureStore.read(key: '${_walletId}_epicboxConfig');
|
await _secureStore.read(key: '${_walletId}_epicboxConfig');
|
||||||
dynamic subscribeRequest;
|
dynamic subscribeRequest;
|
||||||
await m.protect(() async {
|
await m.protect(() async {
|
||||||
ReceivePort receivePort = await getIsolate({
|
ReceivePort receivePort = await getIsolate({
|
||||||
"function": "subscribeRequest",
|
"function": "subscribeRequest",
|
||||||
"config": config,
|
"wallet": wallet,
|
||||||
"password": password,
|
|
||||||
"secretKeyIndex": currentReceivingIndex,
|
"secretKeyIndex": currentReceivingIndex,
|
||||||
"epicboxConfig": epicboxConfig,
|
"epicboxConfig": epicboxConfig,
|
||||||
}, name: walletName);
|
}, name: walletName);
|
||||||
|
@ -1636,8 +1672,7 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
await m.protect(() async {
|
await m.protect(() async {
|
||||||
ReceivePort receivePort = await getIsolate({
|
ReceivePort receivePort = await getIsolate({
|
||||||
"function": "getPendingSlates",
|
"function": "getPendingSlates",
|
||||||
"config": config,
|
"wallet": wallet!,
|
||||||
"password": password,
|
|
||||||
"secretKeyIndex": currentReceivingIndex,
|
"secretKeyIndex": currentReceivingIndex,
|
||||||
"slates": encoded,
|
"slates": encoded,
|
||||||
}, name: walletName);
|
}, name: walletName);
|
||||||
|
@ -1668,8 +1703,7 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
await m.protect(() async {
|
await m.protect(() async {
|
||||||
ReceivePort receivePort = await getIsolate({
|
ReceivePort receivePort = await getIsolate({
|
||||||
"function": "processSlates",
|
"function": "processSlates",
|
||||||
"config": config,
|
"wallet": wallet!,
|
||||||
"password": password,
|
|
||||||
"slates": slateMessage
|
"slates": slateMessage
|
||||||
}, name: walletName);
|
}, name: walletName);
|
||||||
|
|
||||||
|
@ -1689,51 +1723,54 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
await deleteSlate(currentAddress,
|
await deleteSlate(currentAddress,
|
||||||
subscribeRequest['signature'] as String, slate as String);
|
subscribeRequest['signature'] as String, slate as String);
|
||||||
}
|
}
|
||||||
var decodedResponse = json.decode(response);
|
|
||||||
Logging.instance.log("PROCESS_SLATE_RESPONSE $response",
|
|
||||||
level: LogLevel.Info);
|
|
||||||
|
|
||||||
final processStatus = json.decode(decodedResponse[0] as String);
|
if (response.contains("Error Wallet store error: DB Not Found Error")) {
|
||||||
String slateStatus = processStatus['status'] as String;
|
//Already processed - to be deleted
|
||||||
// Logging.instance.log("THIS_TEXT $processStatus");
|
Logging.instance.log("DELETING_PROCESSED_SLATE",
|
||||||
if (slateStatus == "PendingProcessing") {
|
level: LogLevel.Info);
|
||||||
//Encrypt slate
|
final slateDelete = await deleteSlate(currentAddress, subscribeRequest['signature'] as String, slate as String);
|
||||||
//
|
Logging.instance.log("DELETE_SLATE_RESPONSE $slateDelete",
|
||||||
String encryptedSlate = await getEncryptedSlate(
|
|
||||||
config,
|
|
||||||
password!,
|
|
||||||
slateSender,
|
|
||||||
currentReceivingIndex,
|
|
||||||
epicboxConfig!,
|
|
||||||
decodedResponse[1] as String);
|
|
||||||
|
|
||||||
final postSlateToServer =
|
|
||||||
await postSlate(slateSender, encryptedSlate);
|
|
||||||
|
|
||||||
await deleteSlate(currentAddress,
|
|
||||||
subscribeRequest['signature'] as String, slate as String);
|
|
||||||
Logging.instance.log("POST_SLATE_RESPONSE $postSlateToServer",
|
|
||||||
level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
} else {
|
} else {
|
||||||
//Finalise Slate
|
var decodedResponse = json.decode(response);
|
||||||
final processSlate = json.decode(decodedResponse[1] as String);
|
final processStatus = json.decode(decodedResponse[0] as String);
|
||||||
Logging.instance.log(
|
String slateStatus = processStatus['status'] as String;
|
||||||
"PROCESSED_SLATE_TO_FINALIZE $processSlate",
|
if (slateStatus == "PendingProcessing") {
|
||||||
level: LogLevel.Info);
|
//Encrypt slate
|
||||||
final tx = json.decode(processSlate[0] as String);
|
String encryptedSlate = await getEncryptedSlate(
|
||||||
Logging.instance.log("TX_IS $tx", level: LogLevel.Info);
|
wallet!,
|
||||||
String txSlateId = tx[0]['tx_slate_id'] as String;
|
slateSender,
|
||||||
Logging.instance
|
currentReceivingIndex,
|
||||||
.log("TX_SLATE_ID_IS $txSlateId", level: LogLevel.Info);
|
epicboxConfig!,
|
||||||
//
|
decodedResponse[1] as String);
|
||||||
final postToNode = await postSlateToNode(
|
|
||||||
config, password!, currentReceivingIndex, txSlateId);
|
final postSlateToServer =
|
||||||
await deleteSlate(currentAddress,
|
await postSlate(slateSender, encryptedSlate);
|
||||||
subscribeRequest['signature'] as String, slate as String);
|
|
||||||
Logging.instance.log("POST_SLATE_RESPONSE $postToNode",
|
await deleteSlate(currentAddress,
|
||||||
level: LogLevel.Info);
|
subscribeRequest['signature'] as String, slate as String);
|
||||||
//Post Slate to Node
|
Logging.instance.log("POST_SLATE_RESPONSE $postSlateToServer",
|
||||||
Logging.instance.log("Finalise slate", level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
|
} else {
|
||||||
|
//Finalise Slate
|
||||||
|
final processSlate = json.decode(decodedResponse[1] as String);
|
||||||
|
Logging.instance.log(
|
||||||
|
"PROCESSED_SLATE_TO_FINALIZE $processSlate",
|
||||||
|
level: LogLevel.Info);
|
||||||
|
final tx = json.decode(processSlate[0] as String);
|
||||||
|
Logging.instance.log("TX_IS $tx", level: LogLevel.Info);
|
||||||
|
String txSlateId = tx[0]['tx_slate_id'] as String;
|
||||||
|
Logging.instance
|
||||||
|
.log("TX_SLATE_ID_IS $txSlateId", level: LogLevel.Info);
|
||||||
|
final postToNode = await postSlateToNode(
|
||||||
|
wallet!, txSlateId);
|
||||||
|
await deleteSlate(currentAddress,
|
||||||
|
subscribeRequest['signature'] as String, slate as String);
|
||||||
|
Logging.instance.log("POST_SLATE_RESPONSE $postToNode",
|
||||||
|
level: LogLevel.Info);
|
||||||
|
//Post Slate to Node
|
||||||
|
Logging.instance.log("Finalise slate", level: LogLevel.Info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("$e\n$s", level: LogLevel.Info);
|
Logging.instance.log("$e\n$s", level: LogLevel.Info);
|
||||||
|
@ -1751,8 +1788,7 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
Future<bool> processAllCancels() async {
|
Future<bool> processAllCancels() async {
|
||||||
Logging.instance.log("processAllCancels", level: LogLevel.Info);
|
Logging.instance.log("processAllCancels", level: LogLevel.Info);
|
||||||
final config = await getRealConfig();
|
final wallet = await _secureStore.read(key: '${_walletId}_wallet');
|
||||||
final password = await _secureStore.read(key: '${_walletId}_password');
|
|
||||||
final epicboxConfig =
|
final epicboxConfig =
|
||||||
await _secureStore.read(key: '${_walletId}_epicboxConfig');
|
await _secureStore.read(key: '${_walletId}_epicboxConfig');
|
||||||
final int? receivingIndex = DB.instance
|
final int? receivingIndex = DB.instance
|
||||||
|
@ -1768,8 +1804,7 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
await m.protect(() async {
|
await m.protect(() async {
|
||||||
ReceivePort receivePort = await getIsolate({
|
ReceivePort receivePort = await getIsolate({
|
||||||
"function": "subscribeRequest",
|
"function": "subscribeRequest",
|
||||||
"config": config,
|
"wallet": wallet!,
|
||||||
"password": password,
|
|
||||||
"secretKeyIndex": currentReceivingIndex,
|
"secretKeyIndex": currentReceivingIndex,
|
||||||
"epicboxConfig": epicboxConfig,
|
"epicboxConfig": epicboxConfig,
|
||||||
}, name: walletName);
|
}, name: walletName);
|
||||||
|
@ -1827,9 +1862,11 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
/// Refreshes display data for the wallet
|
/// Refreshes display data for the wallet
|
||||||
@override
|
@override
|
||||||
Future<void> refresh() async {
|
Future<void> refresh() async {
|
||||||
Logging.instance.log("Calling refresh", level: LogLevel.Info);
|
Logging.instance
|
||||||
|
.log("$walletId $walletName Calling refresh", level: LogLevel.Info);
|
||||||
if (refreshMutex) {
|
if (refreshMutex) {
|
||||||
Logging.instance.log("refreshMutex denied", level: LogLevel.Info);
|
Logging.instance.log("$walletId $walletName refreshMutex denied",
|
||||||
|
level: LogLevel.Info);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
refreshMutex = true;
|
refreshMutex = true;
|
||||||
|
@ -1920,14 +1957,15 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
if (shouldAutoSync) {
|
if (shouldAutoSync) {
|
||||||
timer ??= Timer.periodic(const Duration(seconds: 60), (timer) async {
|
timer ??= Timer.periodic(const Duration(seconds: 60), (timer) async {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"Periodic refresh check for $walletId in object instance: $hashCode",
|
"Periodic refresh check for $walletId $walletName in object instance: $hashCode",
|
||||||
level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
// chain height check currently broken
|
// chain height check currently broken
|
||||||
// if ((await chainHeight) != (await storedChainHeight)) {
|
// if ((await chainHeight) != (await storedChainHeight)) {
|
||||||
if (await refreshIfThereIsNewData()) {
|
if (await refreshIfThereIsNewData()) {
|
||||||
await refresh();
|
await refresh();
|
||||||
GlobalEventBus.instance.fire(UpdatedInBackgroundEvent(
|
GlobalEventBus.instance.fire(UpdatedInBackgroundEvent(
|
||||||
"New data found in $walletName in background!", walletId));
|
"New data found in $walletId $walletName in background!",
|
||||||
|
walletId));
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
});
|
});
|
||||||
|
@ -2036,16 +2074,14 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
Future<TransactionData> _fetchTransactionData() async {
|
Future<TransactionData> _fetchTransactionData() async {
|
||||||
final currentChainHeight = await chainHeight;
|
final currentChainHeight = await chainHeight;
|
||||||
final config = await getRealConfig();
|
final wallet = await _secureStore.read(key: '${_walletId}_wallet');
|
||||||
final password = await _secureStore.read(key: '${_walletId}_password');
|
|
||||||
const refreshFromNode = 0;
|
const refreshFromNode = 0;
|
||||||
|
|
||||||
dynamic message;
|
dynamic message;
|
||||||
await m.protect(() async {
|
await m.protect(() async {
|
||||||
ReceivePort receivePort = await getIsolate({
|
ReceivePort receivePort = await getIsolate({
|
||||||
"function": "getTransactions",
|
"function": "getTransactions",
|
||||||
"config": config,
|
"wallet": wallet!,
|
||||||
"password": password!,
|
|
||||||
"refreshFromNode": refreshFromNode,
|
"refreshFromNode": refreshFromNode,
|
||||||
}, name: walletName);
|
}, name: walletName);
|
||||||
|
|
||||||
|
@ -2232,6 +2268,12 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool validateAddress(String address) {
|
bool validateAddress(String address) {
|
||||||
|
if (address.startsWith("http://") || address.startsWith("https://")) {
|
||||||
|
if (Uri.tryParse(address) != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String validate = validateSendAddress(address);
|
String validate = validateSendAddress(address);
|
||||||
if (int.parse(validate) == 1) {
|
if (int.parse(validate) == 1) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1470,8 +1470,8 @@ class FiroWallet extends CoinServiceAPI {
|
||||||
@override
|
@override
|
||||||
Future<void> refresh() async {
|
Future<void> refresh() async {
|
||||||
if (refreshMutex) {
|
if (refreshMutex) {
|
||||||
Logging.instance
|
Logging.instance.log("$walletId $walletName refreshMutex denied",
|
||||||
.log("$walletName refreshMutex denied", level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
refreshMutex = true;
|
refreshMutex = true;
|
||||||
|
@ -1559,7 +1559,8 @@ class FiroWallet extends CoinServiceAPI {
|
||||||
if (shouldNotify) {
|
if (shouldNotify) {
|
||||||
await refresh();
|
await refresh();
|
||||||
GlobalEventBus.instance.fire(UpdatedInBackgroundEvent(
|
GlobalEventBus.instance.fire(UpdatedInBackgroundEvent(
|
||||||
"New data found in $walletName in background!", walletId));
|
"New data found in $walletId $walletName in background!",
|
||||||
|
walletId));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -390,8 +390,8 @@ class MoneroWallet extends CoinServiceAPI {
|
||||||
@override
|
@override
|
||||||
Future<void> refresh() async {
|
Future<void> refresh() async {
|
||||||
if (refreshMutex) {
|
if (refreshMutex) {
|
||||||
Logging.instance
|
Logging.instance.log("$walletId $walletName refreshMutex denied",
|
||||||
.log("$walletId refreshMutex denied", level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
refreshMutex = true;
|
refreshMutex = true;
|
||||||
|
@ -465,7 +465,8 @@ class MoneroWallet extends CoinServiceAPI {
|
||||||
// if (await refreshIfThereIsNewData()) {
|
// if (await refreshIfThereIsNewData()) {
|
||||||
await refresh();
|
await refresh();
|
||||||
GlobalEventBus.instance.fire(UpdatedInBackgroundEvent(
|
GlobalEventBus.instance.fire(UpdatedInBackgroundEvent(
|
||||||
"New data found in $walletName in background!", walletId));
|
"New data found in $walletId $walletName in background!",
|
||||||
|
walletId));
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
});
|
});
|
||||||
|
@ -475,7 +476,8 @@ class MoneroWallet extends CoinServiceAPI {
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
await walletBase?.save();
|
await walletBase?.save();
|
||||||
GlobalEventBus.instance.fire(UpdatedInBackgroundEvent(
|
GlobalEventBus.instance.fire(UpdatedInBackgroundEvent(
|
||||||
"New data found in $walletName in background!", walletId));
|
"New data found in $walletId $walletName in background!",
|
||||||
|
walletId));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -866,7 +868,7 @@ class MoneroWallet extends CoinServiceAPI {
|
||||||
// Use new index to derive a new receiving address
|
// Use new index to derive a new receiving address
|
||||||
final newReceivingAddress = await _generateAddressForChain(0, curIndex);
|
final newReceivingAddress = await _generateAddressForChain(0, curIndex);
|
||||||
Logging.instance.log("xmr address in init existing: $newReceivingAddress",
|
Logging.instance.log("xmr address in init existing: $newReceivingAddress",
|
||||||
level: LogLevel.Fatal);
|
level: LogLevel.Info);
|
||||||
_currentReceivingAddress = Future(() => newReceivingAddress);
|
_currentReceivingAddress = Future(() => newReceivingAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ class NotificationsService extends ChangeNotifier {
|
||||||
late NodeService nodeService;
|
late NodeService nodeService;
|
||||||
late TradesService tradesService;
|
late TradesService tradesService;
|
||||||
late Prefs prefs;
|
late Prefs prefs;
|
||||||
|
late ChangeNow changeNow;
|
||||||
|
|
||||||
NotificationsService._();
|
NotificationsService._();
|
||||||
static final NotificationsService _instance = NotificationsService._();
|
static final NotificationsService _instance = NotificationsService._();
|
||||||
|
@ -26,10 +27,12 @@ class NotificationsService extends ChangeNotifier {
|
||||||
required NodeService nodeService,
|
required NodeService nodeService,
|
||||||
required TradesService tradesService,
|
required TradesService tradesService,
|
||||||
required Prefs prefs,
|
required Prefs prefs,
|
||||||
|
required ChangeNow changeNow,
|
||||||
}) async {
|
}) async {
|
||||||
this.nodeService = nodeService;
|
this.nodeService = nodeService;
|
||||||
this.tradesService = tradesService;
|
this.tradesService = tradesService;
|
||||||
this.prefs = prefs;
|
this.prefs = prefs;
|
||||||
|
this.changeNow = changeNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
// watched transactions
|
// watched transactions
|
||||||
|
@ -177,7 +180,7 @@ class NotificationsService extends ChangeNotifier {
|
||||||
for (final notification in _watchedChangeNowTradeNotifications) {
|
for (final notification in _watchedChangeNowTradeNotifications) {
|
||||||
final id = notification.changeNowId!;
|
final id = notification.changeNowId!;
|
||||||
|
|
||||||
final result = await ChangeNow.getTransactionStatus(id: id);
|
final result = await changeNow.getTransactionStatus(id: id);
|
||||||
|
|
||||||
ChangeNowTransactionStatus? status = result.value?.status;
|
ChangeNowTransactionStatus? status = result.value?.status;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:core' as core;
|
import 'dart:core' as core;
|
||||||
|
import 'dart:core';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -11,6 +12,8 @@ import 'package:stackwallet/utilities/enums/log_level_enum.dart';
|
||||||
export 'enums/log_level_enum.dart';
|
export 'enums/log_level_enum.dart';
|
||||||
|
|
||||||
class Logging {
|
class Logging {
|
||||||
|
static const isArmLinux =
|
||||||
|
bool.fromEnvironment("IS_ARM");
|
||||||
static final isTestEnv = Platform.environment["FLUTTER_TEST"] == "true";
|
static final isTestEnv = Platform.environment["FLUTTER_TEST"] == "true";
|
||||||
Logging._();
|
Logging._();
|
||||||
static final Logging _instance = Logging._();
|
static final Logging _instance = Logging._();
|
||||||
|
@ -25,7 +28,7 @@ class Logging {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initInIsolate() async {
|
Future<void> initInIsolate() async {
|
||||||
if (isTestEnv) {
|
if (isTestEnv || isArmLinux) {
|
||||||
// do this for now until we mock Isar properly for testing
|
// do this for now until we mock Isar properly for testing
|
||||||
isar = null;
|
isar = null;
|
||||||
return;
|
return;
|
||||||
|
@ -42,7 +45,7 @@ class Logging {
|
||||||
core.bool printToConsole = true,
|
core.bool printToConsole = true,
|
||||||
core.bool printFullLength = false,
|
core.bool printFullLength = false,
|
||||||
}) {
|
}) {
|
||||||
if (isTestEnv) {
|
if (isTestEnv || isArmLinux) {
|
||||||
Logger.print(object, normalLength: !printFullLength);
|
Logger.print(object, normalLength: !printFullLength);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,20 @@ endfunction()
|
||||||
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
|
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
|
||||||
add_subdirectory(${FLUTTER_MANAGED_DIR})
|
add_subdirectory(${FLUTTER_MANAGED_DIR})
|
||||||
|
|
||||||
|
# build libjsoncpp and libsecret for flutter_secure_storage
|
||||||
|
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/jsoncpp/build/pkg-config")
|
||||||
|
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/pc")
|
||||||
|
|
||||||
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/jsoncpp/include)
|
||||||
|
|
||||||
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/libsecret)
|
||||||
|
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/libsecret/_build)
|
||||||
|
|
||||||
|
add_library(jsoncpp SHARED IMPORTED)
|
||||||
|
set_target_properties(jsoncpp PROPERTIES IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/jsoncpp/build/src/lib_json/libjsoncpp.so")
|
||||||
|
add_library(secret-1 SHARED IMPORTED)
|
||||||
|
set_target_properties(secret-1 PROPERTIES IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/libsecret/_build/libsecret/libsecret-1.so")
|
||||||
|
|
||||||
# System-level dependencies.
|
# System-level dependencies.
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
|
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
|
||||||
|
@ -71,8 +85,12 @@ add_executable(${BINARY_NAME}
|
||||||
apply_standard_settings(${BINARY_NAME})
|
apply_standard_settings(${BINARY_NAME})
|
||||||
|
|
||||||
# Add dependency libraries. Add any application-specific dependencies here.
|
# Add dependency libraries. Add any application-specific dependencies here.
|
||||||
|
target_link_libraries(${BINARY_NAME} PRIVATE -static-libgcc -static-libstdc++)
|
||||||
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
|
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
|
||||||
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
|
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
|
||||||
|
target_link_libraries(${BINARY_NAME} PRIVATE jsoncpp)
|
||||||
|
target_link_libraries(${BINARY_NAME} PRIVATE secret-1)
|
||||||
|
|
||||||
|
|
||||||
# Run the Flutter tool portions of the build. This must not be removed.
|
# Run the Flutter tool portions of the build. This must not be removed.
|
||||||
add_dependencies(${BINARY_NAME} flutter_assemble)
|
add_dependencies(${BINARY_NAME} flutter_assemble)
|
||||||
|
@ -125,6 +143,20 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libepiccash
|
||||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_liblelantus/scripts/linux/build/libmobileliblelantus.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_liblelantus/scripts/linux/build/libmobileliblelantus.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
COMPONENT Runtime)
|
COMPONENT Runtime)
|
||||||
|
|
||||||
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/jsoncpp/build/src/lib_json/libjsoncpp.so.1.7.4" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/jsoncpp/build/src/lib_json/libjsoncpp.so.1" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/jsoncpp/build/src/lib_json/libjsoncpp.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
|
||||||
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/libsecret/_build/libsecret/libsecret-1.so.0.0.0" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/libsecret/_build/libsecret/libsecret-1.so.0" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/linux/build/libsecret/_build/libsecret/libsecret-1.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
COMPONENT Runtime)
|
||||||
|
|
||||||
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
|
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
|
||||||
install(FILES "${bundled_library}"
|
install(FILES "${bundled_library}"
|
||||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
# for arm
|
||||||
|
# flutter-elinux clean
|
||||||
|
# flutter-elinux pub get
|
||||||
|
# flutter-elinux build linux --dart-define="IS_ARM=true"
|
||||||
|
mkdir build
|
||||||
|
./build_secure_storage_deps.sh &
|
||||||
(cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh ) &
|
(cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh ) &
|
||||||
(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) &
|
(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh ) &
|
||||||
(cd ../../crypto_plugins/flutter_libmonero/scripts/linux && ./build_monero_all.sh && ./build_sharedfile.sh ) &
|
(cd ../../crypto_plugins/flutter_libmonero/scripts/linux && ./build_monero_all.sh && ./build_sharedfile.sh ) &
|
||||||
|
|
25
scripts/linux/build_secure_storage_deps.sh
Executable file
25
scripts/linux/build_secure_storage_deps.sh
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/bin/bash
|
||||||
|
LINUX_DIRECTORY=$(pwd)
|
||||||
|
mkdir build
|
||||||
|
|
||||||
|
# Build JsonCPP
|
||||||
|
cd build
|
||||||
|
git clone https://github.com/open-source-parsers/jsoncpp.git
|
||||||
|
cd jsoncpp
|
||||||
|
git checkout 1.7.4
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=release -DBUILD_STATIC_LIBS=ON -DBUILD_SHARED_LIBS=ON -DARCHIVE_INSTALL_DIR=. -G "Unix Makefiles" ..
|
||||||
|
make -j$(nproc)
|
||||||
|
|
||||||
|
cd $LINUX_DIRECTORY
|
||||||
|
# Build libSecret
|
||||||
|
# sudo apt install meson libgirepository1.0-dev valac xsltproc gi-docgen docbook-xsl
|
||||||
|
# sudo apt install python3-pip
|
||||||
|
#pip3 install --user meson --upgrade
|
||||||
|
# pip3 install --user gi-docgen
|
||||||
|
cd build
|
||||||
|
git clone https://gitlab.gnome.org/GNOME/libsecret.git
|
||||||
|
cd libsecret
|
||||||
|
meson _build
|
||||||
|
ninja -C _build
|
15
scripts/linux/pc/libsecret-1.pc
Normal file
15
scripts/linux/pc/libsecret-1.pc
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
prefix=/usr/local
|
||||||
|
libdir=${prefix}/lib/x86_64-linux-gnu
|
||||||
|
includedir=${prefix}/include
|
||||||
|
|
||||||
|
exec_prefix=${prefix}
|
||||||
|
datarootdir=${prefix}/share
|
||||||
|
datadir=${datarootdir}
|
||||||
|
sysconfdir=${prefix}/etc
|
||||||
|
|
||||||
|
Name: libsecret-1
|
||||||
|
Description: GObject bindings for Secret Service API
|
||||||
|
Version: 0.20.5
|
||||||
|
Requires: glib-2.0 >= 2.44, gio-2.0 >= 2.44, gio-unix-2.0 >= 2.44
|
||||||
|
Requires.private: libgcrypt >= 1.2.2
|
||||||
|
Libs: -L${libdir} -lsecret-1
|
109
test/screen_tests/exchange/exchange_view_test.dart
Normal file
109
test/screen_tests/exchange/exchange_view_test.dart
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
import 'package:mockito/annotations.dart';
|
||||||
|
import 'package:stackwallet/services/change_now/change_now.dart';
|
||||||
|
import 'package:stackwallet/services/trade_notes_service.dart';
|
||||||
|
import 'package:stackwallet/services/trade_service.dart';
|
||||||
|
import 'package:stackwallet/utilities/prefs.dart';
|
||||||
|
|
||||||
|
@GenerateMocks([Prefs, TradesService, TradeNotesService, ChangeNow])
|
||||||
|
void main() {
|
||||||
|
// testWidgets("ExchangeView builds correctly with no trade history",
|
||||||
|
// (widgetTester) async {
|
||||||
|
// final prefs = MockPrefs();
|
||||||
|
// final tradeService = MockTradesService();
|
||||||
|
//
|
||||||
|
// when(prefs.exchangeRateType)
|
||||||
|
// .thenAnswer((realInvocation) => ExchangeRateType.estimated);
|
||||||
|
//
|
||||||
|
// when(tradeService.trades).thenAnswer((realInvocation) => []);
|
||||||
|
//
|
||||||
|
// await widgetTester.pumpWidget(
|
||||||
|
// ProviderScope(
|
||||||
|
// overrides: [
|
||||||
|
// prefsChangeNotifierProvider
|
||||||
|
// .overrideWithProvider(ChangeNotifierProvider((ref) => prefs)),
|
||||||
|
// tradesServiceProvider.overrideWithProvider(
|
||||||
|
// ChangeNotifierProvider((ref) => tradeService)),
|
||||||
|
// ],
|
||||||
|
// child: const MaterialApp(
|
||||||
|
// home: Material(child: ExchangeView()),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// await widgetTester.pumpAndSettle();
|
||||||
|
//
|
||||||
|
// expect(find.byType(TextFormField), findsNWidgets(2));
|
||||||
|
// expect(find.byType(SvgPicture), findsNWidgets(6));
|
||||||
|
//
|
||||||
|
// expect(find.text("You will send"), findsOneWidget);
|
||||||
|
// expect(find.text("You will receive"), findsOneWidget);
|
||||||
|
// expect(find.text("Exchange"), findsOneWidget);
|
||||||
|
// expect(find.text("Estimated rate"), findsOneWidget);
|
||||||
|
// expect(find.text("Trades"), findsOneWidget);
|
||||||
|
// expect(find.text("-"), findsNWidgets(2));
|
||||||
|
//
|
||||||
|
// expect(find.text("Trades will appear here"), findsOneWidget);
|
||||||
|
//
|
||||||
|
// expect(find.byType(TextButton), findsNWidgets(2));
|
||||||
|
// expect(find.byType(TradeCard), findsNothing);
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// testWidgets("ExchangeView builds correctly with one trade history",
|
||||||
|
// (widgetTester) async {
|
||||||
|
// final prefs = MockPrefs();
|
||||||
|
// final tradeService = MockTradesService();
|
||||||
|
//
|
||||||
|
// when(prefs.exchangeRateType)
|
||||||
|
// .thenAnswer((realInvocation) => ExchangeRateType.estimated);
|
||||||
|
//
|
||||||
|
// when(tradeService.trades).thenAnswer((realInvocation) => [
|
||||||
|
// ExchangeTransaction(
|
||||||
|
// id: "some id",
|
||||||
|
// payinAddress: "adr",
|
||||||
|
// payoutAddress: "adr2",
|
||||||
|
// payinExtraId: "",
|
||||||
|
// payoutExtraId: "",
|
||||||
|
// fromCurrency: "btc",
|
||||||
|
// toCurrency: "xmr",
|
||||||
|
// amount: "42",
|
||||||
|
// refundAddress: "",
|
||||||
|
// refundExtraId: "refundExtraId",
|
||||||
|
// payoutExtraIdName: "",
|
||||||
|
// uuid: "dhjkfg872tr8yugsd",
|
||||||
|
// date: DateTime(1999),
|
||||||
|
// statusString: "Waiting",
|
||||||
|
// statusObject: null)
|
||||||
|
// ]);
|
||||||
|
//
|
||||||
|
// await widgetTester.pumpWidget(
|
||||||
|
// ProviderScope(
|
||||||
|
// overrides: [
|
||||||
|
// prefsChangeNotifierProvider
|
||||||
|
// .overrideWithProvider(ChangeNotifierProvider((ref) => prefs)),
|
||||||
|
// tradesServiceProvider.overrideWithProvider(
|
||||||
|
// ChangeNotifierProvider((ref) => tradeService)),
|
||||||
|
// ],
|
||||||
|
// child: const MaterialApp(
|
||||||
|
// home: Material(child: ExchangeView()),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// await widgetTester.pumpAndSettle();
|
||||||
|
//
|
||||||
|
// expect(find.byType(TextFormField), findsNWidgets(2));
|
||||||
|
// expect(find.byType(SvgPicture), findsNWidgets(7));
|
||||||
|
//
|
||||||
|
// expect(find.text("You will send"), findsOneWidget);
|
||||||
|
// expect(find.text("You will receive"), findsOneWidget);
|
||||||
|
// expect(find.text("Exchange"), findsOneWidget);
|
||||||
|
// expect(find.text("Estimated rate"), findsOneWidget);
|
||||||
|
// expect(find.text("Trades"), findsOneWidget);
|
||||||
|
// expect(find.text("-"), findsNWidgets(2));
|
||||||
|
//
|
||||||
|
// expect(find.text("Trades will appear here"), findsNothing);
|
||||||
|
//
|
||||||
|
// expect(find.byType(TextButton), findsNWidgets(2));
|
||||||
|
// expect(find.byType(TradeCard), findsOneWidget);
|
||||||
|
// });
|
||||||
|
}
|
317
test/screen_tests/exchange/exchange_view_test.mocks.dart
Normal file
317
test/screen_tests/exchange/exchange_view_test.mocks.dart
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
// Mocks generated by Mockito 5.2.0 from annotations
|
||||||
|
// in stackwallet/test/screen_tests/exchange/exchange_view_test.dart.
|
||||||
|
// Do not manually edit this file.
|
||||||
|
|
||||||
|
import 'dart:async' as _i6;
|
||||||
|
import 'dart:ui' as _i7;
|
||||||
|
|
||||||
|
import 'package:mockito/mockito.dart' as _i1;
|
||||||
|
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'
|
||||||
|
as _i9;
|
||||||
|
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'
|
||||||
|
as _i4;
|
||||||
|
import 'package:stackwallet/services/change_now/change_now.dart' as _i11;
|
||||||
|
import 'package:stackwallet/services/trade_notes_service.dart' as _i10;
|
||||||
|
import 'package:stackwallet/services/trade_service.dart' as _i8;
|
||||||
|
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i5;
|
||||||
|
import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i3;
|
||||||
|
import 'package:stackwallet/utilities/prefs.dart' as _i2;
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: avoid_redundant_argument_values
|
||||||
|
// ignore_for_file: avoid_setters_without_getters
|
||||||
|
// ignore_for_file: comment_references
|
||||||
|
// ignore_for_file: implementation_imports
|
||||||
|
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
||||||
|
// ignore_for_file: prefer_const_constructors
|
||||||
|
// ignore_for_file: unnecessary_parenthesis
|
||||||
|
// ignore_for_file: camel_case_types
|
||||||
|
|
||||||
|
/// A class which mocks [Prefs].
|
||||||
|
///
|
||||||
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
|
class MockPrefs extends _i1.Mock implements _i2.Prefs {
|
||||||
|
MockPrefs() {
|
||||||
|
_i1.throwOnMissingStub(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isInitialized =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#isInitialized), returnValue: false)
|
||||||
|
as bool);
|
||||||
|
@override
|
||||||
|
int get lastUnlockedTimeout => (super
|
||||||
|
.noSuchMethod(Invocation.getter(#lastUnlockedTimeout), returnValue: 0)
|
||||||
|
as int);
|
||||||
|
@override
|
||||||
|
set lastUnlockedTimeout(int? lastUnlockedTimeout) => super.noSuchMethod(
|
||||||
|
Invocation.setter(#lastUnlockedTimeout, lastUnlockedTimeout),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
int get lastUnlocked =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#lastUnlocked), returnValue: 0)
|
||||||
|
as int);
|
||||||
|
@override
|
||||||
|
set lastUnlocked(int? lastUnlocked) =>
|
||||||
|
super.noSuchMethod(Invocation.setter(#lastUnlocked, lastUnlocked),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
int get currentNotificationId =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#currentNotificationId),
|
||||||
|
returnValue: 0) as int);
|
||||||
|
@override
|
||||||
|
List<String> get walletIdsSyncOnStartup =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#walletIdsSyncOnStartup),
|
||||||
|
returnValue: <String>[]) as List<String>);
|
||||||
|
@override
|
||||||
|
set walletIdsSyncOnStartup(List<String>? walletIdsSyncOnStartup) =>
|
||||||
|
super.noSuchMethod(
|
||||||
|
Invocation.setter(#walletIdsSyncOnStartup, walletIdsSyncOnStartup),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
_i3.SyncingType get syncType =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#syncType),
|
||||||
|
returnValue: _i3.SyncingType.currentWalletOnly) as _i3.SyncingType);
|
||||||
|
@override
|
||||||
|
set syncType(_i3.SyncingType? syncType) =>
|
||||||
|
super.noSuchMethod(Invocation.setter(#syncType, syncType),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
bool get wifiOnly =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#wifiOnly), returnValue: false)
|
||||||
|
as bool);
|
||||||
|
@override
|
||||||
|
set wifiOnly(bool? wifiOnly) =>
|
||||||
|
super.noSuchMethod(Invocation.setter(#wifiOnly, wifiOnly),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
bool get showFavoriteWallets =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#showFavoriteWallets),
|
||||||
|
returnValue: false) as bool);
|
||||||
|
@override
|
||||||
|
set showFavoriteWallets(bool? showFavoriteWallets) => super.noSuchMethod(
|
||||||
|
Invocation.setter(#showFavoriteWallets, showFavoriteWallets),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
String get language =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#language), returnValue: '')
|
||||||
|
as String);
|
||||||
|
@override
|
||||||
|
set language(String? newLanguage) =>
|
||||||
|
super.noSuchMethod(Invocation.setter(#language, newLanguage),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
String get currency =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#currency), returnValue: '')
|
||||||
|
as String);
|
||||||
|
@override
|
||||||
|
set currency(String? newCurrency) =>
|
||||||
|
super.noSuchMethod(Invocation.setter(#currency, newCurrency),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
_i4.ExchangeRateType get exchangeRateType =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#exchangeRateType),
|
||||||
|
returnValue: _i4.ExchangeRateType.estimated) as _i4.ExchangeRateType);
|
||||||
|
@override
|
||||||
|
set exchangeRateType(_i4.ExchangeRateType? exchangeRateType) =>
|
||||||
|
super.noSuchMethod(Invocation.setter(#exchangeRateType, exchangeRateType),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
bool get useBiometrics =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#useBiometrics), returnValue: false)
|
||||||
|
as bool);
|
||||||
|
@override
|
||||||
|
set useBiometrics(bool? useBiometrics) =>
|
||||||
|
super.noSuchMethod(Invocation.setter(#useBiometrics, useBiometrics),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
bool get hasPin =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#hasPin), returnValue: false)
|
||||||
|
as bool);
|
||||||
|
@override
|
||||||
|
set hasPin(bool? hasPin) =>
|
||||||
|
super.noSuchMethod(Invocation.setter(#hasPin, hasPin),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
bool get showTestNetCoins =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#showTestNetCoins),
|
||||||
|
returnValue: false) as bool);
|
||||||
|
@override
|
||||||
|
set showTestNetCoins(bool? showTestNetCoins) =>
|
||||||
|
super.noSuchMethod(Invocation.setter(#showTestNetCoins, showTestNetCoins),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
bool get isAutoBackupEnabled =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#isAutoBackupEnabled),
|
||||||
|
returnValue: false) as bool);
|
||||||
|
@override
|
||||||
|
set isAutoBackupEnabled(bool? isAutoBackupEnabled) => super.noSuchMethod(
|
||||||
|
Invocation.setter(#isAutoBackupEnabled, isAutoBackupEnabled),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
set autoBackupLocation(String? autoBackupLocation) => super.noSuchMethod(
|
||||||
|
Invocation.setter(#autoBackupLocation, autoBackupLocation),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
_i5.BackupFrequencyType get backupFrequencyType =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#backupFrequencyType),
|
||||||
|
returnValue: _i5.BackupFrequencyType.everyTenMinutes)
|
||||||
|
as _i5.BackupFrequencyType);
|
||||||
|
@override
|
||||||
|
set backupFrequencyType(_i5.BackupFrequencyType? backupFrequencyType) =>
|
||||||
|
super.noSuchMethod(
|
||||||
|
Invocation.setter(#backupFrequencyType, backupFrequencyType),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
set lastAutoBackup(DateTime? lastAutoBackup) =>
|
||||||
|
super.noSuchMethod(Invocation.setter(#lastAutoBackup, lastAutoBackup),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
bool get hasListeners =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false)
|
||||||
|
as bool);
|
||||||
|
@override
|
||||||
|
_i6.Future<void> init() => (super.noSuchMethod(Invocation.method(#init, []),
|
||||||
|
returnValue: Future<void>.value(),
|
||||||
|
returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
|
||||||
|
@override
|
||||||
|
_i6.Future<void> incrementCurrentNotificationIndex() => (super.noSuchMethod(
|
||||||
|
Invocation.method(#incrementCurrentNotificationIndex, []),
|
||||||
|
returnValue: Future<void>.value(),
|
||||||
|
returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
|
||||||
|
@override
|
||||||
|
void addListener(_i7.VoidCallback? listener) =>
|
||||||
|
super.noSuchMethod(Invocation.method(#addListener, [listener]),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
void removeListener(_i7.VoidCallback? listener) =>
|
||||||
|
super.noSuchMethod(Invocation.method(#removeListener, [listener]),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
void dispose() => super.noSuchMethod(Invocation.method(#dispose, []),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
void notifyListeners() =>
|
||||||
|
super.noSuchMethod(Invocation.method(#notifyListeners, []),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A class which mocks [TradesService].
|
||||||
|
///
|
||||||
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
|
class MockTradesService extends _i1.Mock implements _i8.TradesService {
|
||||||
|
MockTradesService() {
|
||||||
|
_i1.throwOnMissingStub(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<_i9.ExchangeTransaction> get trades =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#trades),
|
||||||
|
returnValue: <_i9.ExchangeTransaction>[])
|
||||||
|
as List<_i9.ExchangeTransaction>);
|
||||||
|
@override
|
||||||
|
bool get hasListeners =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false)
|
||||||
|
as bool);
|
||||||
|
@override
|
||||||
|
_i6.Future<void> add(
|
||||||
|
{_i9.ExchangeTransaction? trade, bool? shouldNotifyListeners}) =>
|
||||||
|
(super.noSuchMethod(
|
||||||
|
Invocation.method(#add, [],
|
||||||
|
{#trade: trade, #shouldNotifyListeners: shouldNotifyListeners}),
|
||||||
|
returnValue: Future<void>.value(),
|
||||||
|
returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
|
||||||
|
@override
|
||||||
|
_i6.Future<void> edit(
|
||||||
|
{_i9.ExchangeTransaction? trade, bool? shouldNotifyListeners}) =>
|
||||||
|
(super.noSuchMethod(
|
||||||
|
Invocation.method(#edit, [],
|
||||||
|
{#trade: trade, #shouldNotifyListeners: shouldNotifyListeners}),
|
||||||
|
returnValue: Future<void>.value(),
|
||||||
|
returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
|
||||||
|
@override
|
||||||
|
_i6.Future<void> delete(
|
||||||
|
{_i9.ExchangeTransaction? trade, bool? shouldNotifyListeners}) =>
|
||||||
|
(super.noSuchMethod(
|
||||||
|
Invocation.method(#delete, [],
|
||||||
|
{#trade: trade, #shouldNotifyListeners: shouldNotifyListeners}),
|
||||||
|
returnValue: Future<void>.value(),
|
||||||
|
returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
|
||||||
|
@override
|
||||||
|
_i6.Future<void> deleteByUuid({String? uuid, bool? shouldNotifyListeners}) =>
|
||||||
|
(super.noSuchMethod(
|
||||||
|
Invocation.method(#deleteByUuid, [],
|
||||||
|
{#uuid: uuid, #shouldNotifyListeners: shouldNotifyListeners}),
|
||||||
|
returnValue: Future<void>.value(),
|
||||||
|
returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
|
||||||
|
@override
|
||||||
|
void addListener(_i7.VoidCallback? listener) =>
|
||||||
|
super.noSuchMethod(Invocation.method(#addListener, [listener]),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
void removeListener(_i7.VoidCallback? listener) =>
|
||||||
|
super.noSuchMethod(Invocation.method(#removeListener, [listener]),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
void dispose() => super.noSuchMethod(Invocation.method(#dispose, []),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
void notifyListeners() =>
|
||||||
|
super.noSuchMethod(Invocation.method(#notifyListeners, []),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A class which mocks [TradeNotesService].
|
||||||
|
///
|
||||||
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
|
class MockTradeNotesService extends _i1.Mock implements _i10.TradeNotesService {
|
||||||
|
MockTradeNotesService() {
|
||||||
|
_i1.throwOnMissingStub(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, String> get all => (super.noSuchMethod(Invocation.getter(#all),
|
||||||
|
returnValue: <String, String>{}) as Map<String, String>);
|
||||||
|
@override
|
||||||
|
bool get hasListeners =>
|
||||||
|
(super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false)
|
||||||
|
as bool);
|
||||||
|
@override
|
||||||
|
String getNote({String? tradeId}) =>
|
||||||
|
(super.noSuchMethod(Invocation.method(#getNote, [], {#tradeId: tradeId}),
|
||||||
|
returnValue: '') as String);
|
||||||
|
@override
|
||||||
|
_i6.Future<void> set({String? tradeId, String? note}) => (super.noSuchMethod(
|
||||||
|
Invocation.method(#set, [], {#tradeId: tradeId, #note: note}),
|
||||||
|
returnValue: Future<void>.value(),
|
||||||
|
returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
|
||||||
|
@override
|
||||||
|
_i6.Future<void> delete({String? tradeId}) =>
|
||||||
|
(super.noSuchMethod(Invocation.method(#delete, [], {#tradeId: tradeId}),
|
||||||
|
returnValue: Future<void>.value(),
|
||||||
|
returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
|
||||||
|
@override
|
||||||
|
void addListener(_i7.VoidCallback? listener) =>
|
||||||
|
super.noSuchMethod(Invocation.method(#addListener, [listener]),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
void removeListener(_i7.VoidCallback? listener) =>
|
||||||
|
super.noSuchMethod(Invocation.method(#removeListener, [listener]),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
void dispose() => super.noSuchMethod(Invocation.method(#dispose, []),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
@override
|
||||||
|
void notifyListeners() =>
|
||||||
|
super.noSuchMethod(Invocation.method(#notifyListeners, []),
|
||||||
|
returnValueForMissingStub: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A class which mocks [ChangeNow].
|
||||||
|
///
|
||||||
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
|
class MockChangeNow extends _i1.Mock implements _i11.ChangeNow {
|
||||||
|
MockChangeNow() {
|
||||||
|
_i1.throwOnMissingStub(this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,15 +20,15 @@ void main() {
|
||||||
group("getAvailableCurrencies", () {
|
group("getAvailableCurrencies", () {
|
||||||
test("getAvailableCurrencies succeeds without options", () async {
|
test("getAvailableCurrencies succeeds without options", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse("https://api.changenow.io/v1/currencies"),
|
Uri.parse("https://api.ChangeNow.io/v1/currencies"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async =>
|
)).thenAnswer((realInvocation) async =>
|
||||||
Response(jsonEncode(availableCurrenciesJSON), 200));
|
Response(jsonEncode(availableCurrenciesJSON), 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getAvailableCurrencies();
|
final result = await ChangeNow.instance.getAvailableCurrencies();
|
||||||
|
|
||||||
expect(result.exception, null);
|
expect(result.exception, null);
|
||||||
expect(result.value == null, false);
|
expect(result.value == null, false);
|
||||||
|
@ -37,15 +37,16 @@ void main() {
|
||||||
|
|
||||||
test("getAvailableCurrencies succeeds with active option", () async {
|
test("getAvailableCurrencies succeeds with active option", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse("https://api.changenow.io/v1/currencies?active=true"),
|
Uri.parse("https://api.ChangeNow.io/v1/currencies?active=true"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async =>
|
)).thenAnswer((realInvocation) async =>
|
||||||
Response(jsonEncode(availableCurrenciesJSONActive), 200));
|
Response(jsonEncode(availableCurrenciesJSONActive), 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getAvailableCurrencies(active: true);
|
final result =
|
||||||
|
await ChangeNow.instance.getAvailableCurrencies(active: true);
|
||||||
|
|
||||||
expect(result.exception, null);
|
expect(result.exception, null);
|
||||||
expect(result.value == null, false);
|
expect(result.value == null, false);
|
||||||
|
@ -54,15 +55,16 @@ void main() {
|
||||||
|
|
||||||
test("getAvailableCurrencies succeeds with fixedRate option", () async {
|
test("getAvailableCurrencies succeeds with fixedRate option", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse("https://api.changenow.io/v1/currencies?fixedRate=true"),
|
Uri.parse("https://api.ChangeNow.io/v1/currencies?fixedRate=true"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async =>
|
)).thenAnswer((realInvocation) async =>
|
||||||
Response(jsonEncode(availableCurrenciesJSONFixedRate), 200));
|
Response(jsonEncode(availableCurrenciesJSONFixedRate), 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getAvailableCurrencies(fixedRate: true);
|
final result =
|
||||||
|
await ChangeNow.instance.getAvailableCurrencies(fixedRate: true);
|
||||||
|
|
||||||
expect(result.exception, null);
|
expect(result.exception, null);
|
||||||
expect(result.value == null, false);
|
expect(result.value == null, false);
|
||||||
|
@ -72,17 +74,17 @@ void main() {
|
||||||
test("getAvailableCurrencies succeeds with fixedRate and active options",
|
test("getAvailableCurrencies succeeds with fixedRate and active options",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/currencies?fixedRate=true&active=true"),
|
"https://api.ChangeNow.io/v1/currencies?fixedRate=true&active=true"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async =>
|
)).thenAnswer((realInvocation) async =>
|
||||||
Response(jsonEncode(availableCurrenciesJSONActiveFixedRate), 200));
|
Response(jsonEncode(availableCurrenciesJSONActiveFixedRate), 200));
|
||||||
|
|
||||||
final result =
|
final result = await ChangeNow.instance
|
||||||
await ChangeNow.getAvailableCurrencies(active: true, fixedRate: true);
|
.getAvailableCurrencies(active: true, fixedRate: true);
|
||||||
|
|
||||||
expect(result.exception, null);
|
expect(result.exception, null);
|
||||||
expect(result.value == null, false);
|
expect(result.value == null, false);
|
||||||
|
@ -93,15 +95,15 @@ void main() {
|
||||||
"getAvailableCurrencies fails with ChangeNowExceptionType.serializeResponseError",
|
"getAvailableCurrencies fails with ChangeNowExceptionType.serializeResponseError",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse("https://api.changenow.io/v1/currencies"),
|
Uri.parse("https://api.ChangeNow.io/v1/currencies"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async =>
|
)).thenAnswer((realInvocation) async =>
|
||||||
Response('{"some unexpected": "but valid json data"}', 200));
|
Response('{"some unexpected": "but valid json data"}', 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getAvailableCurrencies();
|
final result = await ChangeNow.instance.getAvailableCurrencies();
|
||||||
|
|
||||||
expect(result.exception!.type,
|
expect(result.exception!.type,
|
||||||
ChangeNowExceptionType.serializeResponseError);
|
ChangeNowExceptionType.serializeResponseError);
|
||||||
|
@ -110,14 +112,14 @@ void main() {
|
||||||
|
|
||||||
test("getAvailableCurrencies fails for any other reason", () async {
|
test("getAvailableCurrencies fails for any other reason", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse("https://api.changenow.io/v1/currencies"),
|
Uri.parse("https://api.ChangeNow.io/v1/currencies"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response("", 400));
|
)).thenAnswer((realInvocation) async => Response("", 400));
|
||||||
|
|
||||||
final result = await ChangeNow.getAvailableCurrencies();
|
final result = await ChangeNow.instance.getAvailableCurrencies();
|
||||||
|
|
||||||
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
||||||
expect(result.value == null, true);
|
expect(result.value == null, true);
|
||||||
|
@ -127,15 +129,16 @@ void main() {
|
||||||
group("getPairedCurrencies", () {
|
group("getPairedCurrencies", () {
|
||||||
test("getPairedCurrencies succeeds without fixedRate option", () async {
|
test("getPairedCurrencies succeeds without fixedRate option", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse("https://api.changenow.io/v1/currencies-to/XMR"),
|
Uri.parse("https://api.ChangeNow.io/v1/currencies-to/XMR"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async =>
|
)).thenAnswer((realInvocation) async =>
|
||||||
Response(jsonEncode(getPairedCurrenciesJSON), 200));
|
Response(jsonEncode(getPairedCurrenciesJSON), 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getPairedCurrencies(ticker: "XMR");
|
final result =
|
||||||
|
await ChangeNow.instance.getPairedCurrencies(ticker: "XMR");
|
||||||
|
|
||||||
expect(result.exception, null);
|
expect(result.exception, null);
|
||||||
expect(result.value == null, false);
|
expect(result.value == null, false);
|
||||||
|
@ -144,17 +147,17 @@ void main() {
|
||||||
|
|
||||||
test("getPairedCurrencies succeeds with fixedRate option", () async {
|
test("getPairedCurrencies succeeds with fixedRate option", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/currencies-to/XMR?fixedRate=true"),
|
"https://api.ChangeNow.io/v1/currencies-to/XMR?fixedRate=true"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async =>
|
)).thenAnswer((realInvocation) async =>
|
||||||
Response(jsonEncode(getPairedCurrenciesJSONFixedRate), 200));
|
Response(jsonEncode(getPairedCurrenciesJSONFixedRate), 200));
|
||||||
|
|
||||||
final result =
|
final result = await ChangeNow.instance
|
||||||
await ChangeNow.getPairedCurrencies(ticker: "XMR", fixedRate: true);
|
.getPairedCurrencies(ticker: "XMR", fixedRate: true);
|
||||||
|
|
||||||
expect(result.exception, null);
|
expect(result.exception, null);
|
||||||
expect(result.value == null, false);
|
expect(result.value == null, false);
|
||||||
|
@ -165,15 +168,16 @@ void main() {
|
||||||
"getPairedCurrencies fails with ChangeNowExceptionType.serializeResponseError A",
|
"getPairedCurrencies fails with ChangeNowExceptionType.serializeResponseError A",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse("https://api.changenow.io/v1/currencies-to/XMR"),
|
Uri.parse("https://api.ChangeNow.io/v1/currencies-to/XMR"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async =>
|
)).thenAnswer((realInvocation) async =>
|
||||||
Response('[{"some unexpected": "but valid json data"}]', 200));
|
Response('[{"some unexpected": "but valid json data"}]', 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getPairedCurrencies(ticker: "XMR");
|
final result =
|
||||||
|
await ChangeNow.instance.getPairedCurrencies(ticker: "XMR");
|
||||||
|
|
||||||
expect(result.exception!.type,
|
expect(result.exception!.type,
|
||||||
ChangeNowExceptionType.serializeResponseError);
|
ChangeNowExceptionType.serializeResponseError);
|
||||||
|
@ -182,15 +186,15 @@ void main() {
|
||||||
|
|
||||||
test("getPairedCurrencies fails for any other reason", () async {
|
test("getPairedCurrencies fails for any other reason", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse("https://api.changenow.io/v1/currencies"),
|
Uri.parse("https://api.ChangeNow.io/v1/currencies"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response("", 400));
|
)).thenAnswer((realInvocation) async => Response("", 400));
|
||||||
|
|
||||||
final result =
|
final result = await ChangeNow.instance
|
||||||
await ChangeNow.getPairedCurrencies(ticker: "XMR", fixedRate: true);
|
.getPairedCurrencies(ticker: "XMR", fixedRate: true);
|
||||||
|
|
||||||
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
||||||
expect(result.value == null, true);
|
expect(result.value == null, true);
|
||||||
|
@ -200,16 +204,16 @@ void main() {
|
||||||
group("getMinimalExchangeAmount", () {
|
group("getMinimalExchangeAmount", () {
|
||||||
test("getMinimalExchangeAmount succeeds", () async {
|
test("getMinimalExchangeAmount succeeds", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/min-amount/xmr_btc?api_key=testAPIKEY"),
|
"https://api.ChangeNow.io/v1/min-amount/xmr_btc?api_key=testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer(
|
)).thenAnswer(
|
||||||
(realInvocation) async => Response('{"minAmount": 42}', 200));
|
(realInvocation) async => Response('{"minAmount": 42}', 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getMinimalExchangeAmount(
|
final result = await ChangeNow.instance.getMinimalExchangeAmount(
|
||||||
fromTicker: "xmr",
|
fromTicker: "xmr",
|
||||||
toTicker: "btc",
|
toTicker: "btc",
|
||||||
apiKey: "testAPIKEY",
|
apiKey: "testAPIKEY",
|
||||||
|
@ -224,15 +228,15 @@ void main() {
|
||||||
"getMinimalExchangeAmount fails with ChangeNowExceptionType.serializeResponseError",
|
"getMinimalExchangeAmount fails with ChangeNowExceptionType.serializeResponseError",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/min-amount/xmr_btc?api_key=testAPIKEY"),
|
"https://api.ChangeNow.io/v1/min-amount/xmr_btc?api_key=testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getMinimalExchangeAmount(
|
final result = await ChangeNow.instance.getMinimalExchangeAmount(
|
||||||
fromTicker: "xmr",
|
fromTicker: "xmr",
|
||||||
toTicker: "btc",
|
toTicker: "btc",
|
||||||
apiKey: "testAPIKEY",
|
apiKey: "testAPIKEY",
|
||||||
|
@ -245,15 +249,15 @@ void main() {
|
||||||
|
|
||||||
test("getMinimalExchangeAmount fails for any other reason", () async {
|
test("getMinimalExchangeAmount fails for any other reason", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/min-amount/xmr_btc?api_key=testAPIKEY"),
|
"https://api.ChangeNow.io/v1/min-amount/xmr_btc?api_key=testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||||
|
|
||||||
final result = await ChangeNow.getMinimalExchangeAmount(
|
final result = await ChangeNow.instance.getMinimalExchangeAmount(
|
||||||
fromTicker: "xmr",
|
fromTicker: "xmr",
|
||||||
toTicker: "btc",
|
toTicker: "btc",
|
||||||
apiKey: "testAPIKEY",
|
apiKey: "testAPIKEY",
|
||||||
|
@ -267,17 +271,17 @@ void main() {
|
||||||
group("getEstimatedExchangeAmount", () {
|
group("getEstimatedExchangeAmount", () {
|
||||||
test("getEstimatedExchangeAmount succeeds", () async {
|
test("getEstimatedExchangeAmount succeeds", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/exchange-amount/42/xmr_btc?api_key=testAPIKEY"),
|
"https://api.ChangeNow.io/v1/exchange-amount/42/xmr_btc?api_key=testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response(
|
)).thenAnswer((realInvocation) async => Response(
|
||||||
'{"estimatedAmount": 58.4142873, "transactionSpeedForecast": "10-60", "warningMessage": null}',
|
'{"estimatedAmount": 58.4142873, "transactionSpeedForecast": "10-60", "warningMessage": null}',
|
||||||
200));
|
200));
|
||||||
|
|
||||||
final result = await ChangeNow.getEstimatedExchangeAmount(
|
final result = await ChangeNow.instance.getEstimatedExchangeAmount(
|
||||||
fromTicker: "xmr",
|
fromTicker: "xmr",
|
||||||
toTicker: "btc",
|
toTicker: "btc",
|
||||||
fromAmount: Decimal.fromInt(42),
|
fromAmount: Decimal.fromInt(42),
|
||||||
|
@ -293,15 +297,15 @@ void main() {
|
||||||
"getEstimatedExchangeAmount fails with ChangeNowExceptionType.serializeResponseError",
|
"getEstimatedExchangeAmount fails with ChangeNowExceptionType.serializeResponseError",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/exchange-amount/42/xmr_btc?api_key=testAPIKEY"),
|
"https://api.ChangeNow.io/v1/exchange-amount/42/xmr_btc?api_key=testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getEstimatedExchangeAmount(
|
final result = await ChangeNow.instance.getEstimatedExchangeAmount(
|
||||||
fromTicker: "xmr",
|
fromTicker: "xmr",
|
||||||
toTicker: "btc",
|
toTicker: "btc",
|
||||||
fromAmount: Decimal.fromInt(42),
|
fromAmount: Decimal.fromInt(42),
|
||||||
|
@ -315,15 +319,15 @@ void main() {
|
||||||
|
|
||||||
test("getEstimatedExchangeAmount fails for any other reason", () async {
|
test("getEstimatedExchangeAmount fails for any other reason", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/exchange-amount/42/xmr_btc?api_key=testAPIKEY"),
|
"https://api.ChangeNow.io/v1/exchange-amount/42/xmr_btc?api_key=testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||||
|
|
||||||
final result = await ChangeNow.getEstimatedExchangeAmount(
|
final result = await ChangeNow.instance.getEstimatedExchangeAmount(
|
||||||
fromTicker: "xmr",
|
fromTicker: "xmr",
|
||||||
toTicker: "btc",
|
toTicker: "btc",
|
||||||
fromAmount: Decimal.fromInt(42),
|
fromAmount: Decimal.fromInt(42),
|
||||||
|
@ -338,16 +342,17 @@ void main() {
|
||||||
group("getEstimatedFixedRateExchangeAmount", () {
|
group("getEstimatedFixedRateExchangeAmount", () {
|
||||||
test("getEstimatedFixedRateExchangeAmount succeeds", () async {
|
test("getEstimatedFixedRateExchangeAmount succeeds", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
|
"https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async =>
|
)).thenAnswer((realInvocation) async =>
|
||||||
Response(jsonEncode(estFixedRateExchangeAmountJSON), 200));
|
Response(jsonEncode(estFixedRateExchangeAmountJSON), 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getEstimatedFixedRateExchangeAmount(
|
final result =
|
||||||
|
await ChangeNow.instance.getEstimatedFixedRateExchangeAmount(
|
||||||
fromTicker: "xmr",
|
fromTicker: "xmr",
|
||||||
toTicker: "btc",
|
toTicker: "btc",
|
||||||
fromAmount: Decimal.fromInt(10),
|
fromAmount: Decimal.fromInt(10),
|
||||||
|
@ -364,15 +369,16 @@ void main() {
|
||||||
"getEstimatedFixedRateExchangeAmount fails with ChangeNowExceptionType.serializeResponseError",
|
"getEstimatedFixedRateExchangeAmount fails with ChangeNowExceptionType.serializeResponseError",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
|
"https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getEstimatedFixedRateExchangeAmount(
|
final result =
|
||||||
|
await ChangeNow.instance.getEstimatedFixedRateExchangeAmount(
|
||||||
fromTicker: "xmr",
|
fromTicker: "xmr",
|
||||||
toTicker: "btc",
|
toTicker: "btc",
|
||||||
fromAmount: Decimal.fromInt(10),
|
fromAmount: Decimal.fromInt(10),
|
||||||
|
@ -387,15 +393,16 @@ void main() {
|
||||||
test("getEstimatedFixedRateExchangeAmount fails for any other reason",
|
test("getEstimatedFixedRateExchangeAmount fails for any other reason",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
|
"https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||||
|
|
||||||
final result = await ChangeNow.getEstimatedFixedRateExchangeAmount(
|
final result =
|
||||||
|
await ChangeNow.instance.getEstimatedFixedRateExchangeAmount(
|
||||||
fromTicker: "xmr",
|
fromTicker: "xmr",
|
||||||
toTicker: "btc",
|
toTicker: "btc",
|
||||||
fromAmount: Decimal.fromInt(10),
|
fromAmount: Decimal.fromInt(10),
|
||||||
|
@ -410,16 +417,16 @@ void main() {
|
||||||
group("getAvailableFixedRateMarkets", () {
|
group("getAvailableFixedRateMarkets", () {
|
||||||
test("getAvailableFixedRateMarkets succeeds", () async {
|
test("getAvailableFixedRateMarkets succeeds", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/market-info/fixed-rate/testAPIKEY"),
|
"https://api.ChangeNow.io/v1/market-info/fixed-rate/testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async =>
|
)).thenAnswer((realInvocation) async =>
|
||||||
Response(jsonEncode(fixedRateMarketsJSON), 200));
|
Response(jsonEncode(fixedRateMarketsJSON), 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getAvailableFixedRateMarkets(
|
final result = await ChangeNow.instance.getAvailableFixedRateMarkets(
|
||||||
apiKey: "testAPIKEY",
|
apiKey: "testAPIKEY",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -432,15 +439,15 @@ void main() {
|
||||||
"getAvailableFixedRateMarkets fails with ChangeNowExceptionType.serializeResponseError",
|
"getAvailableFixedRateMarkets fails with ChangeNowExceptionType.serializeResponseError",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/market-info/fixed-rate/testAPIKEY"),
|
"https://api.ChangeNow.io/v1/market-info/fixed-rate/testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getAvailableFixedRateMarkets(
|
final result = await ChangeNow.instance.getAvailableFixedRateMarkets(
|
||||||
apiKey: "testAPIKEY",
|
apiKey: "testAPIKEY",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -451,15 +458,15 @@ void main() {
|
||||||
|
|
||||||
test("getAvailableFixedRateMarkets fails for any other reason", () async {
|
test("getAvailableFixedRateMarkets fails for any other reason", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/market-info/fixed-rate/testAPIKEY"),
|
"https://api.ChangeNow.io/v1/market-info/fixed-rate/testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||||
|
|
||||||
final result = await ChangeNow.getAvailableFixedRateMarkets(
|
final result = await ChangeNow.instance.getAvailableFixedRateMarkets(
|
||||||
apiKey: "testAPIKEY",
|
apiKey: "testAPIKEY",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -471,10 +478,10 @@ void main() {
|
||||||
group("createStandardExchangeTransaction", () {
|
group("createStandardExchangeTransaction", () {
|
||||||
test("createStandardExchangeTransaction succeeds", () async {
|
test("createStandardExchangeTransaction succeeds", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.post(
|
when(client.post(
|
||||||
Uri.parse("https://api.changenow.io/v1/transactions/testAPIKEY"),
|
Uri.parse("https://api.ChangeNow.io/v1/transactions/testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body:
|
body:
|
||||||
'{"from":"xmr","to":"btc","address":"bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5","amount":"0.3","flow":"standard","extraId":"","userId":"","contactEmail":"","refundAddress":"888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H","refundExtraId":""}',
|
'{"from":"xmr","to":"btc","address":"bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5","amount":"0.3","flow":"standard","extraId":"","userId":"","contactEmail":"","refundAddress":"888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H","refundExtraId":""}',
|
||||||
|
@ -482,7 +489,7 @@ void main() {
|
||||||
)).thenAnswer((realInvocation) async =>
|
)).thenAnswer((realInvocation) async =>
|
||||||
Response(jsonEncode(createStandardTransactionResponse), 200));
|
Response(jsonEncode(createStandardTransactionResponse), 200));
|
||||||
|
|
||||||
final result = await ChangeNow.createStandardExchangeTransaction(
|
final result = await ChangeNow.instance.createStandardExchangeTransaction(
|
||||||
fromTicker: "xmr",
|
fromTicker: "xmr",
|
||||||
toTicker: "btc",
|
toTicker: "btc",
|
||||||
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
|
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
|
||||||
|
@ -501,17 +508,17 @@ void main() {
|
||||||
"createStandardExchangeTransaction fails with ChangeNowExceptionType.serializeResponseError",
|
"createStandardExchangeTransaction fails with ChangeNowExceptionType.serializeResponseError",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.post(
|
when(client.post(
|
||||||
Uri.parse("https://api.changenow.io/v1/transactions/testAPIKEY"),
|
Uri.parse("https://api.ChangeNow.io/v1/transactions/testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body:
|
body:
|
||||||
'{"from":"xmr","to":"btc","address":"bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5","amount":"0.3","flow":"standard","extraId":"","userId":"","contactEmail":"","refundAddress":"888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H","refundExtraId":""}',
|
'{"from":"xmr","to":"btc","address":"bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5","amount":"0.3","flow":"standard","extraId":"","userId":"","contactEmail":"","refundAddress":"888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H","refundExtraId":""}',
|
||||||
encoding: null,
|
encoding: null,
|
||||||
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
||||||
|
|
||||||
final result = await ChangeNow.createStandardExchangeTransaction(
|
final result = await ChangeNow.instance.createStandardExchangeTransaction(
|
||||||
fromTicker: "xmr",
|
fromTicker: "xmr",
|
||||||
toTicker: "btc",
|
toTicker: "btc",
|
||||||
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
|
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
|
||||||
|
@ -529,17 +536,17 @@ void main() {
|
||||||
test("createStandardExchangeTransaction fails for any other reason",
|
test("createStandardExchangeTransaction fails for any other reason",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.post(
|
when(client.post(
|
||||||
Uri.parse("https://api.changenow.io/v1/transactions/testAPIKEY"),
|
Uri.parse("https://api.ChangeNow.io/v1/transactions/testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body:
|
body:
|
||||||
'{"from":"xmr","to":"btc","address":"bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5","amount":"0.3","flow":"standard","extraId":"","userId":"","contactEmail":"","refundAddress":"888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H","refundExtraId":""}',
|
'{"from":"xmr","to":"btc","address":"bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5","amount":"0.3","flow":"standard","extraId":"","userId":"","contactEmail":"","refundAddress":"888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H","refundExtraId":""}',
|
||||||
encoding: null,
|
encoding: null,
|
||||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||||
|
|
||||||
final result = await ChangeNow.createStandardExchangeTransaction(
|
final result = await ChangeNow.instance.createStandardExchangeTransaction(
|
||||||
fromTicker: "xmr",
|
fromTicker: "xmr",
|
||||||
toTicker: "btc",
|
toTicker: "btc",
|
||||||
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
|
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
|
||||||
|
@ -557,11 +564,11 @@ void main() {
|
||||||
group("createFixedRateExchangeTransaction", () {
|
group("createFixedRateExchangeTransaction", () {
|
||||||
test("createFixedRateExchangeTransaction succeeds", () async {
|
test("createFixedRateExchangeTransaction succeeds", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.post(
|
when(client.post(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/transactions/fixed-rate/testAPIKEY"),
|
"https://api.ChangeNow.io/v1/transactions/fixed-rate/testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body:
|
body:
|
||||||
'{"from":"btc","to":"eth","address":"0x57f31ad4b64095347F87eDB1675566DAfF5EC886","amount":"0.3","flow":"fixed-rate","extraId":"","userId":"","contactEmail":"","refundAddress":"","refundExtraId":"","rateId":""}',
|
'{"from":"btc","to":"eth","address":"0x57f31ad4b64095347F87eDB1675566DAfF5EC886","amount":"0.3","flow":"fixed-rate","extraId":"","userId":"","contactEmail":"","refundAddress":"","refundExtraId":"","rateId":""}',
|
||||||
|
@ -570,7 +577,8 @@ void main() {
|
||||||
'{"payinAddress": "33eFX2jfeWbXMSmRe9ewUUTrmSVSxZi5cj", "payoutAddress": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886","payoutExtraId": "", "fromCurrency": "btc", "toCurrency": "eth", "refundAddress": "","refundExtraId": "","validUntil": "2019-09-09T14:01:04.921Z","id": "a5c73e2603f40d","amount": 62.9737711}',
|
'{"payinAddress": "33eFX2jfeWbXMSmRe9ewUUTrmSVSxZi5cj", "payoutAddress": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886","payoutExtraId": "", "fromCurrency": "btc", "toCurrency": "eth", "refundAddress": "","refundExtraId": "","validUntil": "2019-09-09T14:01:04.921Z","id": "a5c73e2603f40d","amount": 62.9737711}',
|
||||||
200));
|
200));
|
||||||
|
|
||||||
final result = await ChangeNow.createFixedRateExchangeTransaction(
|
final result =
|
||||||
|
await ChangeNow.instance.createFixedRateExchangeTransaction(
|
||||||
fromTicker: "btc",
|
fromTicker: "btc",
|
||||||
toTicker: "eth",
|
toTicker: "eth",
|
||||||
receivingAddress: "0x57f31ad4b64095347F87eDB1675566DAfF5EC886",
|
receivingAddress: "0x57f31ad4b64095347F87eDB1675566DAfF5EC886",
|
||||||
|
@ -589,11 +597,11 @@ void main() {
|
||||||
"createFixedRateExchangeTransaction fails with ChangeNowExceptionType.serializeResponseError",
|
"createFixedRateExchangeTransaction fails with ChangeNowExceptionType.serializeResponseError",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.post(
|
when(client.post(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/transactions/fixed-rate/testAPIKEY"),
|
"https://api.ChangeNow.io/v1/transactions/fixed-rate/testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body:
|
body:
|
||||||
'{"from":"btc","to":"eth","address":"0x57f31ad4b64095347F87eDB1675566DAfF5EC886","amount":"0.3","flow":"fixed-rate","extraId":"","userId":"","contactEmail":"","refundAddress":"","refundExtraId":"","rateId":""}',
|
'{"from":"btc","to":"eth","address":"0x57f31ad4b64095347F87eDB1675566DAfF5EC886","amount":"0.3","flow":"fixed-rate","extraId":"","userId":"","contactEmail":"","refundAddress":"","refundExtraId":"","rateId":""}',
|
||||||
|
@ -601,7 +609,8 @@ void main() {
|
||||||
)).thenAnswer((realInvocation) async =>
|
)).thenAnswer((realInvocation) async =>
|
||||||
Response('{"id": "a5c73e2603f40d","amount": 62.9737711}', 200));
|
Response('{"id": "a5c73e2603f40d","amount": 62.9737711}', 200));
|
||||||
|
|
||||||
final result = await ChangeNow.createFixedRateExchangeTransaction(
|
final result =
|
||||||
|
await ChangeNow.instance.createFixedRateExchangeTransaction(
|
||||||
fromTicker: "btc",
|
fromTicker: "btc",
|
||||||
toTicker: "eth",
|
toTicker: "eth",
|
||||||
receivingAddress: "0x57f31ad4b64095347F87eDB1675566DAfF5EC886",
|
receivingAddress: "0x57f31ad4b64095347F87eDB1675566DAfF5EC886",
|
||||||
|
@ -619,18 +628,19 @@ void main() {
|
||||||
test("createFixedRateExchangeTransaction fails for any other reason",
|
test("createFixedRateExchangeTransaction fails for any other reason",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.post(
|
when(client.post(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/transactions/fixed-rate/testAPIKEY"),
|
"https://api.ChangeNow.io/v1/transactions/fixed-rate/testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body:
|
body:
|
||||||
'{"from": "btc","to": "eth","address": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886", "amount": "1.12345","extraId": "", "userId": "","contactEmail": "","refundAddress": "", "refundExtraId": "", "rateId": "" }',
|
'{"from": "btc","to": "eth","address": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886", "amount": "1.12345","extraId": "", "userId": "","contactEmail": "","refundAddress": "", "refundExtraId": "", "rateId": "" }',
|
||||||
encoding: null,
|
encoding: null,
|
||||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||||
|
|
||||||
final result = await ChangeNow.createFixedRateExchangeTransaction(
|
final result =
|
||||||
|
await ChangeNow.instance.createFixedRateExchangeTransaction(
|
||||||
fromTicker: "xmr",
|
fromTicker: "xmr",
|
||||||
toTicker: "btc",
|
toTicker: "btc",
|
||||||
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
|
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
|
||||||
|
@ -649,17 +659,17 @@ void main() {
|
||||||
group("getTransactionStatus", () {
|
group("getTransactionStatus", () {
|
||||||
test("getTransactionStatus succeeds", () async {
|
test("getTransactionStatus succeeds", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/transactions/47F87eDB1675566DAfF5EC886/testAPIKEY"),
|
"https://api.ChangeNow.io/v1/transactions/47F87eDB1675566DAfF5EC886/testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response(
|
)).thenAnswer((realInvocation) async => Response(
|
||||||
'{"status": "waiting", "payinAddress": "32Ge2ci26rj1sRGw2NjiQa9L7Xvxtgzhrj", "payoutAddress": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886", "fromCurrency": "btc", "toCurrency": "eth", "id": "50727663e5d9a4", "updatedAt": "2019-08-22T14:47:49.943Z", "expectedSendAmount": 1, "expectedReceiveAmount": 52.31667, "createdAt": "2019-08-22T14:47:49.943Z", "isPartner": false}',
|
'{"status": "waiting", "payinAddress": "32Ge2ci26rj1sRGw2NjiQa9L7Xvxtgzhrj", "payoutAddress": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886", "fromCurrency": "btc", "toCurrency": "eth", "id": "50727663e5d9a4", "updatedAt": "2019-08-22T14:47:49.943Z", "expectedSendAmount": 1, "expectedReceiveAmount": 52.31667, "createdAt": "2019-08-22T14:47:49.943Z", "isPartner": false}',
|
||||||
200));
|
200));
|
||||||
|
|
||||||
final result = await ChangeNow.getTransactionStatus(
|
final result = await ChangeNow.instance.getTransactionStatus(
|
||||||
id: "47F87eDB1675566DAfF5EC886",
|
id: "47F87eDB1675566DAfF5EC886",
|
||||||
apiKey: "testAPIKEY",
|
apiKey: "testAPIKEY",
|
||||||
);
|
);
|
||||||
|
@ -673,15 +683,15 @@ void main() {
|
||||||
"getTransactionStatus fails with ChangeNowExceptionType.serializeResponseError",
|
"getTransactionStatus fails with ChangeNowExceptionType.serializeResponseError",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/transactions/47F87eDB1675566DAfF5EC886/testAPIKEY"),
|
"https://api.ChangeNow.io/v1/transactions/47F87eDB1675566DAfF5EC886/testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getTransactionStatus(
|
final result = await ChangeNow.instance.getTransactionStatus(
|
||||||
id: "47F87eDB1675566DAfF5EC886",
|
id: "47F87eDB1675566DAfF5EC886",
|
||||||
apiKey: "testAPIKEY",
|
apiKey: "testAPIKEY",
|
||||||
);
|
);
|
||||||
|
@ -693,15 +703,15 @@ void main() {
|
||||||
|
|
||||||
test("getTransactionStatus fails for any other reason", () async {
|
test("getTransactionStatus fails for any other reason", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/transactions/47F87eDB1675566DAfF5EC886/testAPIKEY"),
|
"https://api.ChangeNow.io/v1/transactions/47F87eDB1675566DAfF5EC886/testAPIKEY"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||||
|
|
||||||
final result = await ChangeNow.getTransactionStatus(
|
final result = await ChangeNow.instance.getTransactionStatus(
|
||||||
id: "47F87eDB1675566DAfF5EC886",
|
id: "47F87eDB1675566DAfF5EC886",
|
||||||
apiKey: "testAPIKEY",
|
apiKey: "testAPIKEY",
|
||||||
);
|
);
|
||||||
|
@ -714,16 +724,16 @@ void main() {
|
||||||
group("getAvailableFloatingRatePairs", () {
|
group("getAvailableFloatingRatePairs", () {
|
||||||
test("getAvailableFloatingRatePairs succeeds", () async {
|
test("getAvailableFloatingRatePairs succeeds", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/market-info/available-pairs?includePartners=false"),
|
"https://api.ChangeNow.io/v1/market-info/available-pairs?includePartners=false"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async =>
|
)).thenAnswer((realInvocation) async =>
|
||||||
Response('["btc_xmr","btc_firo","btc_doge","eth_ltc"]', 200));
|
Response('["btc_xmr","btc_firo","btc_doge","eth_ltc"]', 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getAvailableFloatingRatePairs();
|
final result = await ChangeNow.instance.getAvailableFloatingRatePairs();
|
||||||
|
|
||||||
expect(result.exception, null);
|
expect(result.exception, null);
|
||||||
expect(result.value == null, false);
|
expect(result.value == null, false);
|
||||||
|
@ -734,15 +744,15 @@ void main() {
|
||||||
"getAvailableFloatingRatePairs fails with ChangeNowExceptionType.serializeResponseError",
|
"getAvailableFloatingRatePairs fails with ChangeNowExceptionType.serializeResponseError",
|
||||||
() async {
|
() async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/market-info/available-pairs?includePartners=false"),
|
"https://api.ChangeNow.io/v1/market-info/available-pairs?includePartners=false"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
||||||
|
|
||||||
final result = await ChangeNow.getAvailableFloatingRatePairs();
|
final result = await ChangeNow.instance.getAvailableFloatingRatePairs();
|
||||||
|
|
||||||
expect(result.exception!.type,
|
expect(result.exception!.type,
|
||||||
ChangeNowExceptionType.serializeResponseError);
|
ChangeNowExceptionType.serializeResponseError);
|
||||||
|
@ -751,15 +761,15 @@ void main() {
|
||||||
|
|
||||||
test("getAvailableFloatingRatePairs fails for any other reason", () async {
|
test("getAvailableFloatingRatePairs fails for any other reason", () async {
|
||||||
final client = MockClient();
|
final client = MockClient();
|
||||||
ChangeNow.client = client;
|
ChangeNow.instance.client = client;
|
||||||
|
|
||||||
when(client.get(
|
when(client.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
"https://api.changenow.io/v1/market-info/available-pairs?includePartners=false"),
|
"https://api.ChangeNow.io/v1/market-info/available-pairs?includePartners=false"),
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||||
|
|
||||||
final result = await ChangeNow.getAvailableFloatingRatePairs();
|
final result = await ChangeNow.instance.getAvailableFloatingRatePairs();
|
||||||
|
|
||||||
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
||||||
expect(result.value == null, true);
|
expect(result.value == null, true);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Mocks generated by Mockito 5.2.0 from annotations
|
// Mocks generated by Mockito 5.2.0 from annotations
|
||||||
// in stackwallet/test/services/change_now_test.dart.
|
// in stackwallet/test/services/change_now/change_now_test.dart.
|
||||||
// Do not manually edit this file.
|
// Do not manually edit this file.
|
||||||
|
|
||||||
import 'dart:async' as _i5;
|
import 'dart:async' as _i5;
|
||||||
|
|
Loading…
Reference in a new issue