estimated/floating rate fixes and optimizations

This commit is contained in:
julian 2022-09-03 11:41:00 -06:00
parent eb63b1828c
commit e97ccf812e
3 changed files with 198 additions and 223 deletions

View file

@ -1,10 +1,14 @@
import 'package:decimal/decimal.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:stackwallet/models/exchange/change_now/currency.dart';
import 'package:stackwallet/services/change_now/change_now.dart';
import 'package:stackwallet/utilities/logger.dart';
class EstimatedRateExchangeFormState extends ChangeNotifier {
/// used in testing to inject mock
ChangeNow? cnTesting;
Decimal? _fromAmount;
Decimal? _toAmount;
@ -16,9 +20,43 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
Currency? _from;
Currency? _to;
void Function(String)? _onError;
Currency? get from => _from;
Currency? get to => _to;
String get fromAmountString =>
_fromAmount == null ? "" : _fromAmount!.toStringAsFixed(8);
String get toAmountString =>
_toAmount == null ? "" : _toAmount!.toStringAsFixed(8);
String get rateDisplayString {
if (rate == null || from == null || to == null) {
return "N/A";
} else {
return "1 ${from!.ticker.toUpperCase()} ~${rate!.toStringAsFixed(8)} ${to!.ticker.toUpperCase()}";
}
}
bool get canExchange {
return _fromAmount != null &&
_fromAmount != Decimal.zero &&
_toAmount != null &&
rate != null &&
minimumSendWarning.isEmpty;
}
String get minimumSendWarning {
if (_from != null &&
_fromAmount != null &&
_minFromAmount != null &&
_fromAmount! < _minFromAmount!) {
return "Minimum amount ${_minFromAmount!.toString()} ${from!.ticker.toUpperCase()}";
}
return "";
}
Future<void> init(Currency? from, Currency? to) async {
_from = from;
_to = to;
@ -43,10 +81,6 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
final Decimal? newMinFromAmount = _minToAmount;
final Decimal? newMinToAmount = _minFromAmount;
// final Decimal? newRate = rate == null
// ? rate
// : (Decimal.one / rate!).toDecimal(scaleOnInfinitePrecision: 12);
final Currency? newTo = from;
final Currency? newFrom = to;
@ -63,48 +97,11 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
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);
}
}
}
await updateRate();
notifyListeners();
}
String get fromAmountString =>
_fromAmount == null ? "" : _fromAmount!.toStringAsFixed(8);
String get toAmountString =>
_toAmount == null ? "" : _toAmount!.toStringAsFixed(8);
Future<void> updateTo(Currency to, bool shouldNotifyListeners) async {
try {
_to = to;
@ -115,46 +112,8 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
}
await _updateMinFromAmount(shouldNotifyListeners: shouldNotifyListeners);
// await _updateMinToAmount(shouldNotifyListeners: shouldNotifyListeners);
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);
}
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!);
if (amt != null) {
rate =
(amt / _minFromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
}
debugPrint("D");
}
}
await updateRate();
debugPrint(
"_updated TO: _from=${_from!.ticker} _to=${_to!.ticker} _fromAmount=$_fromAmount _toAmount=$_toAmount rate:$rate");
@ -163,7 +122,7 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
notifyListeners();
}
} catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
Logging.instance.log("$e\n$s", level: LogLevel.Error);
}
}
@ -179,40 +138,7 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
await _updateMinFromAmount(shouldNotifyListeners: shouldNotifyListeners);
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);
}
}
}
await updateRate();
debugPrint(
"_updated FROM: _from=${_from!.ticker} _to=${_to!.ticker} _fromAmount=$_fromAmount _toAmount=$_toAmount rate:$rate");
@ -220,55 +146,10 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
notifyListeners();
}
} catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Fatal);
Logging.instance.log("$e\n$s", level: LogLevel.Error);
}
}
String get rateDisplayString {
if (rate == null || from == null || to == null) {
return "N/A";
} else {
return "1 ${from!.ticker.toUpperCase()} ~${rate!.toStringAsFixed(8)} ${to!.ticker.toUpperCase()}";
}
}
bool get canExchange {
return _fromAmount != null &&
_fromAmount != Decimal.zero &&
_toAmount != null &&
rate != null &&
minimumReceiveWarning.isEmpty &&
minimumSendWarning.isEmpty;
}
String get minimumSendWarning {
if (_from != null &&
_fromAmount != null &&
_minFromAmount != null &&
_fromAmount! < _minFromAmount!) {
return "Minimum amount ${_minFromAmount!.toString()} ${from!.ticker.toUpperCase()}";
}
return "";
}
String get minimumReceiveWarning {
// TODO not sure this is needed
// if (_toAmount != null &&
// _minToAmount != null &&
// _toAmount! < _minToAmount!) {
// return "Minimum amount ${_minToAmount!.toString()} ${to.ticker.toUpperCase()}";
// }
return "";
}
// Future<void> _updateMinToAmount({required bool shouldNotifyListeners}) async {
// _minToAmount = await getStandardMinExchangeAmount(from: to!, to: from!);
// if (shouldNotifyListeners) {
// notifyListeners();
// }
// }
Future<void> _updateMinFromAmount(
{required bool shouldNotifyListeners}) async {
_minFromAmount = await getStandardMinExchangeAmount(from: from!, to: to!);
@ -277,48 +158,32 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
}
}
Future<void> setToAmountAndCalculateFromAmount(
Decimal newToAmount,
bool shouldNotifyListeners,
) async {
// if (newToAmount == Decimal.zero) {
// _fromAmount = Decimal.zero;
// _toAmount = Decimal.zero;
// if (shouldNotifyListeners) {
// notifyListeners();
// }
// return;
// }
if (rate != null) {
_fromAmount =
(newToAmount / rate!).toDecimal(scaleOnInfinitePrecision: 12);
}
_toAmount = newToAmount;
if (shouldNotifyListeners) {
notifyListeners();
}
}
// Future<void> setToAmountAndCalculateFromAmount(
// Decimal newToAmount,
// bool shouldNotifyListeners,
// ) async {
// if (newToAmount == Decimal.zero) {
// _fromAmount = Decimal.zero;
// }
//
// _toAmount = newToAmount;
// await updateRate();
// if (shouldNotifyListeners) {
// notifyListeners();
// }
// }
Future<void> setFromAmountAndCalculateToAmount(
Decimal newFromAmount,
bool shouldNotifyListeners,
) async {
// if (newFromAmount == Decimal.zero) {
// _fromAmount = Decimal.zero;
// _toAmount = Decimal.zero;
// if (shouldNotifyListeners) {
// notifyListeners();
// }
// return;
// }
if (rate != null) {
_toAmount = (newFromAmount * rate!);
if (newFromAmount == Decimal.zero) {
_toAmount = Decimal.zero;
}
_fromAmount = newFromAmount;
await updateRate();
if (shouldNotifyListeners) {
notifyListeners();
}
@ -329,8 +194,12 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
required Currency from,
required Currency to,
}) async {
final response = await ChangeNow.instance.getEstimatedExchangeAmount(
fromTicker: from.ticker, toTicker: to.ticker, fromAmount: fromAmount);
final response =
await (cnTesting ?? ChangeNow.instance).getEstimatedExchangeAmount(
fromTicker: from.ticker,
toTicker: to.ticker,
fromAmount: fromAmount,
);
if (response.value != null) {
return response.value!.estimatedAmount;
@ -341,11 +210,31 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
}
}
// Future<Decimal?> getStandardEstimatedFromAmount({
// required Decimal toAmount,
// required Currency from,
// required Currency to,
// }) async {
// final response = await (cnTesting ?? ChangeNow.instance)
// .getEstimatedExchangeAmount(
// fromTicker: from.ticker,
// toTicker: to.ticker,
// fromAmount: toAmount, );
//
// if (response.value != null) {
// return response.value!.fromAmount;
// } else {
// _onError?.call(
// "Failed to fetch estimated amount: ${response.exception?.toString()}");
// return null;
// }
// }
Future<Decimal?> getStandardMinExchangeAmount({
required Currency from,
required Currency to,
}) async {
final response = await ChangeNow.instance
final response = await (cnTesting ?? ChangeNow.instance)
.getMinimalExchangeAmount(fromTicker: from.ticker, toTicker: to.ticker);
if (response.value != null) {
@ -357,8 +246,6 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
}
}
void Function(String)? _onError;
void setOnError({
required void Function(String)? onError,
bool shouldNotifyListeners = false,
@ -368,4 +255,25 @@ class EstimatedRateExchangeFormState extends ChangeNotifier {
notifyListeners();
}
}
Future<void> updateRate() async {
rate = null;
final amount = _fromAmount;
final minAmount = _minFromAmount;
if (amount != null && amount > Decimal.zero) {
Decimal? amt;
if (minAmount != null) {
if (minAmount <= amount) {
amt = await getStandardEstimatedToAmount(
fromAmount: amount, from: _from!, to: _to!);
if (amt != null) {
rate = (amt / amount).toDecimal(scaleOnInfinitePrecision: 12);
}
}
}
if (rate != null && amt != null) {
_toAmount = amt;
}
}
}
}

View file

@ -231,6 +231,65 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
? ref.read(estimatedRateExchangeFormProvider).toAmountString
: ref.read(fixedRateExchangeFormProvider).toAmountString;
_sendFocusNode.addListener(() async {
if (!_sendFocusNode.hasFocus) {
final newFromAmount = Decimal.tryParse(_sendController.text);
if (newFromAmount != null) {
if (ref.read(prefsChangeNotifierProvider).exchangeRateType ==
ExchangeRateType.estimated) {
await ref
.read(estimatedRateExchangeFormProvider)
.setFromAmountAndCalculateToAmount(newFromAmount, true);
} else {
await ref
.read(fixedRateExchangeFormProvider)
.setFromAmountAndCalculateToAmount(newFromAmount, true);
}
} else {
if (ref.read(prefsChangeNotifierProvider).exchangeRateType ==
ExchangeRateType.estimated) {
await ref
.read(estimatedRateExchangeFormProvider)
.setFromAmountAndCalculateToAmount(Decimal.zero, true);
} else {
await ref
.read(fixedRateExchangeFormProvider)
.setFromAmountAndCalculateToAmount(Decimal.zero, true);
}
_receiveController.text = "";
}
}
});
_receiveFocusNode.addListener(() async {
if (!_receiveFocusNode.hasFocus) {
final newToAmount = Decimal.tryParse(_receiveController.text);
if (newToAmount != null) {
if (ref.read(prefsChangeNotifierProvider).exchangeRateType ==
ExchangeRateType.estimated) {
// await ref
// .read(estimatedRateExchangeFormProvider)
// .setToAmountAndCalculateFromAmount(newToAmount, true);
} else {
await ref
.read(fixedRateExchangeFormProvider)
.setToAmountAndCalculateFromAmount(newToAmount, true);
}
} else {
if (ref.read(prefsChangeNotifierProvider).exchangeRateType ==
ExchangeRateType.estimated) {
// await ref
// .read(estimatedRateExchangeFormProvider)
// .setToAmountAndCalculateFromAmount(Decimal.zero, true);
} else {
await ref
.read(fixedRateExchangeFormProvider)
.setToAmountAndCalculateFromAmount(Decimal.zero, true);
}
_sendController.text = "";
}
}
});
super.initState();
}
@ -332,12 +391,12 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
await ref
.read(estimatedRateExchangeFormProvider)
.setFromAmountAndCalculateToAmount(
newFromAmount, true);
newFromAmount, false);
} else {
await ref
.read(fixedRateExchangeFormProvider)
.setFromAmountAndCalculateToAmount(
newFromAmount, true);
newFromAmount, false);
}
} else {
if (ref
@ -347,12 +406,12 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
await ref
.read(estimatedRateExchangeFormProvider)
.setFromAmountAndCalculateToAmount(
Decimal.zero, true);
Decimal.zero, false);
} else {
await ref
.read(fixedRateExchangeFormProvider)
.setFromAmountAndCalculateToAmount(
Decimal.zero, true);
Decimal.zero, false);
}
_receiveController.text = "";
}
@ -631,6 +690,10 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
TextFormField(
focusNode: _receiveFocusNode,
controller: _receiveController,
readOnly: ref
.read(prefsChangeNotifierProvider)
.exchangeRateType ==
ExchangeRateType.estimated,
onTap: () {
if (_receiveController.text == "-") {
_receiveController.text = "";
@ -643,30 +706,30 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
.read(prefsChangeNotifierProvider)
.exchangeRateType ==
ExchangeRateType.estimated) {
await ref
.read(estimatedRateExchangeFormProvider)
.setToAmountAndCalculateFromAmount(
newToAmount, true);
// await ref
// .read(estimatedRateExchangeFormProvider)
// .setToAmountAndCalculateFromAmount(
// newToAmount, false);
} else {
await ref
.read(fixedRateExchangeFormProvider)
.setToAmountAndCalculateFromAmount(
newToAmount, true);
newToAmount, false);
}
} else {
if (ref
.read(prefsChangeNotifierProvider)
.exchangeRateType ==
ExchangeRateType.estimated) {
await ref
.read(estimatedRateExchangeFormProvider)
.setToAmountAndCalculateFromAmount(
Decimal.zero, true);
// await ref
// .read(estimatedRateExchangeFormProvider)
// .setToAmountAndCalculateFromAmount(
// Decimal.zero, false);
} else {
await ref
.read(fixedRateExchangeFormProvider)
.setToAmountAndCalculateFromAmount(
Decimal.zero, true);
Decimal.zero, false);
}
_sendController.text = "";
}

View file

@ -716,6 +716,10 @@ class _WalletInitiatedExchangeViewState
TextFormField(
focusNode: _receiveFocusNode,
controller: _receiveController,
readOnly: ref
.read(prefsChangeNotifierProvider)
.exchangeRateType ==
ExchangeRateType.estimated,
onTap: () {
if (_receiveController.text == "-") {
_receiveController.text = "";
@ -728,10 +732,10 @@ class _WalletInitiatedExchangeViewState
.read(prefsChangeNotifierProvider)
.exchangeRateType ==
ExchangeRateType.estimated) {
await ref
.read(estimatedRateExchangeFormProvider)
.setToAmountAndCalculateFromAmount(
newToAmount, true);
// await ref
// .read(estimatedRateExchangeFormProvider)
// .setToAmountAndCalculateFromAmount(
// newToAmount, true);
} else {
await ref
.read(fixedRateExchangeFormProvider)
@ -743,10 +747,10 @@ class _WalletInitiatedExchangeViewState
.read(prefsChangeNotifierProvider)
.exchangeRateType ==
ExchangeRateType.estimated) {
await ref
.read(estimatedRateExchangeFormProvider)
.setToAmountAndCalculateFromAmount(
Decimal.zero, true);
// await ref
// .read(estimatedRateExchangeFormProvider)
// .setToAmountAndCalculateFromAmount(
// Decimal.zero, true);
} else {
await ref
.read(fixedRateExchangeFormProvider)