mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-11-17 01:37:40 +00:00
Merge pull request #667 from cake-tech/CW-271-fixed-rate-incorrect-amount
[Cw 271] fixed-rate incorrect amount
This commit is contained in:
commit
3edba88b96
8 changed files with 70 additions and 49 deletions
|
@ -11,7 +11,6 @@ import 'package:cake_wallet/exchange/trade_request.dart';
|
|||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/changenow/changenow_request.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exeption.dart';
|
||||
|
||||
class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
ChangeNowExchangeProvider()
|
||||
|
@ -21,8 +20,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
.where((i) => i != CryptoCurrency.xhv)
|
||||
.map((i) => CryptoCurrency.all
|
||||
.where((i) => i != CryptoCurrency.xhv)
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true))
|
||||
.where((c) => c != null))
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.expand((i) => i)
|
||||
.toList());
|
||||
|
||||
|
@ -43,6 +41,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => true;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.changeNow;
|
||||
|
@ -96,19 +97,30 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
apiHeaderKey: apiKey,
|
||||
'Content-Type': 'application/json'};
|
||||
final flow = getFlow(isFixedRateMode);
|
||||
final type = isFixedRateMode ? 'reverse' : 'direct';
|
||||
final body = <String, String>{
|
||||
'fromCurrency': normalizeCryptoCurrency(_request.from),
|
||||
'toCurrency': normalizeCryptoCurrency(_request.to),
|
||||
'fromNetwork': networkFor(_request.from),
|
||||
'toNetwork': networkFor(_request.to),
|
||||
'fromAmount': _request.fromAmount,
|
||||
'toAmount': _request.toAmount,
|
||||
if (!isFixedRateMode) 'fromAmount': _request.fromAmount,
|
||||
if (isFixedRateMode) 'toAmount': _request.toAmount,
|
||||
'address': _request.address,
|
||||
'flow': flow,
|
||||
'type': type,
|
||||
'refundAddress': _request.refundAddress
|
||||
};
|
||||
|
||||
if (isFixedRateMode) {
|
||||
// since we schedule to calculate the rate every 5 seconds we need to ensure that
|
||||
// we have the latest rate id with the given inputs before creating the trade
|
||||
await fetchRate(
|
||||
from: _request.from,
|
||||
to: _request.to,
|
||||
amount: double.tryParse(_request.toAmount) ?? 0,
|
||||
isFixedRateMode: true,
|
||||
isReceiveAmount: true,
|
||||
);
|
||||
body['rateId'] = _lastUsedRateId;
|
||||
}
|
||||
|
||||
|
@ -141,7 +153,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
refundAddress: refundAddress,
|
||||
extraId: extraId,
|
||||
createdAt: DateTime.now(),
|
||||
amount: _request.fromAmount,
|
||||
amount: responseJSON['fromAmount']?.toString() ?? _request.fromAmount,
|
||||
state: TradeState.created);
|
||||
}
|
||||
|
||||
|
@ -180,9 +192,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
final extraId = responseJSON['payinExtraId'] as String;
|
||||
final outputTransaction = responseJSON['payoutHash'] as String;
|
||||
final expiredAtRaw = responseJSON['validUntil'] as String;
|
||||
final expiredAt = expiredAtRaw != null
|
||||
? DateTime.parse(expiredAtRaw).toLocal()
|
||||
: null;
|
||||
final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal();
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
|
@ -198,7 +208,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
|
@ -214,10 +224,10 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
final type = isReverse ? 'reverse' : 'direct';
|
||||
final flow = getFlow(isFixedRateMode);
|
||||
final params = <String, String>{
|
||||
'fromCurrency': isReverse ? normalizeCryptoCurrency(to) : normalizeCryptoCurrency(from),
|
||||
'toCurrency': isReverse ? normalizeCryptoCurrency(from) : normalizeCryptoCurrency(to),
|
||||
'fromNetwork': isReverse ? networkFor(to) : networkFor(from),
|
||||
'toNetwork': isReverse ? networkFor(from) : networkFor(to),
|
||||
'fromCurrency': normalizeCryptoCurrency(from),
|
||||
'toCurrency': normalizeCryptoCurrency(to),
|
||||
'fromNetwork': networkFor(from),
|
||||
'toNetwork': networkFor(to),
|
||||
'type': type,
|
||||
'flow': flow};
|
||||
|
||||
|
@ -238,7 +248,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
_lastUsedRateId = rateId;
|
||||
}
|
||||
|
||||
return isReverse ? fromAmount : toAmount;
|
||||
return isReverse ? (amount / fromAmount) : (toAmount / amount);
|
||||
} catch(e) {
|
||||
print(e.toString());
|
||||
return 0.0;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_pair.dart';
|
||||
|
@ -14,6 +13,7 @@ abstract class ExchangeProvider {
|
|||
ExchangeProviderDescription get description;
|
||||
bool get isAvailable;
|
||||
bool get isEnabled;
|
||||
bool get supportsFixedRate;
|
||||
|
||||
@override
|
||||
String toString() => title;
|
||||
|
@ -26,7 +26,7 @@ abstract class ExchangeProvider {
|
|||
required TradeRequest request,
|
||||
required bool isFixedRateMode});
|
||||
Future<Trade> findTradeById({required String id});
|
||||
Future<double> calculateAmount({
|
||||
Future<double> fetchRate({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
|
|
|
@ -66,6 +66,9 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
|
|||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => false;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.morphToken;
|
||||
|
@ -200,7 +203,7 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
|
|
|
@ -12,7 +12,6 @@ import 'package:cw_core/crypto_currency.dart';
|
|||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
|
@ -48,8 +47,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
|
||||
return supportedCurrencies
|
||||
.map((i) => supportedCurrencies
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true))
|
||||
.where((c) => c != null))
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.expand((i) => i)
|
||||
.toList();
|
||||
}
|
||||
|
@ -59,7 +57,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
ExchangeProviderDescription.sideShift;
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
|
@ -81,9 +79,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
|
||||
if (amount > max) return 0.00;
|
||||
|
||||
final estimatedAmount = rate * amount;
|
||||
|
||||
return estimatedAmount;
|
||||
return rate;
|
||||
} catch (_) {
|
||||
return 0.00;
|
||||
}
|
||||
|
@ -257,8 +253,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
state = TradeState.deserialize(raw: status ?? 'created');
|
||||
|
||||
final expiredAtRaw = responseJSON['expiresAtISO'] as String;
|
||||
final expiredAt =
|
||||
expiredAtRaw != null ? DateTime.parse(expiredAtRaw).toLocal() : null;
|
||||
final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal();
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
|
@ -278,6 +273,9 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => true;
|
||||
|
||||
@override
|
||||
String get title => 'SideShift';
|
||||
|
||||
|
|
|
@ -20,8 +20,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
.where((i) => i != CryptoCurrency.zaddr)
|
||||
.map((i) => CryptoCurrency.all
|
||||
.where((i) => i != CryptoCurrency.zaddr)
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true))
|
||||
.where((c) => c != null))
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.expand((i) => i)
|
||||
.toList());
|
||||
|
||||
|
@ -37,7 +36,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
ExchangeProviderDescription.simpleSwap;
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
|
@ -59,9 +58,9 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
final uri = Uri.https(apiAuthority, getEstimatePath, params);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.body == null || response.body == "null") return 0.00;
|
||||
if (response.body == "null") return 0.00;
|
||||
final data = json.decode(response.body) as String;
|
||||
return double.parse(data);
|
||||
return double.parse(data) / amount;
|
||||
} catch (_) {
|
||||
return 0.00;
|
||||
}
|
||||
|
@ -210,6 +209,9 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => false;
|
||||
|
||||
@override
|
||||
String get title => 'SimpleSwap';
|
||||
|
||||
|
|
|
@ -48,6 +48,9 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
|||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => false;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.xmrto;
|
||||
|
@ -191,7 +194,7 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<double> calculateAmount(
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
|
|
|
@ -115,6 +115,11 @@ abstract class SettingsStoreBase with Store {
|
|||
(BalanceDisplayMode mode) => sharedPreferences.setInt(
|
||||
PreferencesKey.currentBalanceDisplayModeKey, mode.serialize()));
|
||||
|
||||
reaction(
|
||||
(_) => disableExchange,
|
||||
(bool disableExchange) => sharedPreferences.setBool(
|
||||
PreferencesKey.disableExchangeKey, disableExchange));
|
||||
|
||||
this
|
||||
.nodes
|
||||
.observe((change) {
|
||||
|
|
|
@ -44,7 +44,6 @@ abstract class ExchangeViewModelBase with Store {
|
|||
ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore,
|
||||
this.tradesStore, this._settingsStore, this.sharedPreferences)
|
||||
: _cryptoNumberFormat = NumberFormat(),
|
||||
isReverse = false,
|
||||
isFixedRateMode = false,
|
||||
isReceiveAmountEntered = false,
|
||||
depositAmount = '',
|
||||
|
@ -112,7 +111,11 @@ abstract class ExchangeViewModelBase with Store {
|
|||
loadLimits();
|
||||
reaction(
|
||||
(_) => isFixedRateMode,
|
||||
(Object _) => loadLimits());
|
||||
(Object _) {
|
||||
loadLimits();
|
||||
_bestRate = 0;
|
||||
_calculateBestRate();
|
||||
});
|
||||
}
|
||||
|
||||
final WalletBase wallet;
|
||||
|
@ -227,8 +230,6 @@ abstract class ExchangeViewModelBase with Store {
|
|||
|
||||
Limits limits;
|
||||
|
||||
bool isReverse;
|
||||
|
||||
NumberFormat _cryptoNumberFormat;
|
||||
|
||||
final SettingsStore _settingsStore;
|
||||
|
@ -258,7 +259,6 @@ abstract class ExchangeViewModelBase with Store {
|
|||
@action
|
||||
Future<void> changeReceiveAmount({required String amount}) async {
|
||||
receiveAmount = amount;
|
||||
isReverse = true;
|
||||
|
||||
if (amount.isEmpty) {
|
||||
depositAmount = '';
|
||||
|
@ -283,7 +283,6 @@ abstract class ExchangeViewModelBase with Store {
|
|||
@action
|
||||
Future<void> changeDepositAmount({required String amount}) async {
|
||||
depositAmount = amount;
|
||||
isReverse = false;
|
||||
|
||||
if (amount.isEmpty) {
|
||||
depositAmount = '';
|
||||
|
@ -311,12 +310,13 @@ abstract class ExchangeViewModelBase with Store {
|
|||
|
||||
final result = await Future.wait<double>(
|
||||
_tradeAvailableProviders
|
||||
.map((element) => element.calculateAmount(
|
||||
.where((element) => !isFixedRateMode || element.supportsFixedRate)
|
||||
.map((element) => element.fetchRate(
|
||||
from: depositCurrency,
|
||||
to: receiveCurrency,
|
||||
amount: amount,
|
||||
isFixedRateMode: isFixedRateMode,
|
||||
isReceiveAmount: false))
|
||||
isReceiveAmount: isFixedRateMode))
|
||||
);
|
||||
|
||||
_sortedAvailableProviders.clear();
|
||||
|
@ -324,7 +324,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
for (int i=0;i<result.length;i++) {
|
||||
if (result[i] != 0) {
|
||||
/// add this provider as its valid for this trade
|
||||
_sortedAvailableProviders[result[i] / amount] = _tradeAvailableProviders[i];
|
||||
_sortedAvailableProviders[result[i]] = _tradeAvailableProviders[i];
|
||||
}
|
||||
}
|
||||
if (_sortedAvailableProviders.isNotEmpty) {
|
||||
|
@ -401,7 +401,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
settleAddress: receiveAddress,
|
||||
refundAddress: depositAddress,
|
||||
);
|
||||
amount = depositAmount;
|
||||
amount = isFixedRateMode ? receiveAmount : depositAmount;
|
||||
}
|
||||
|
||||
if (provider is SimpleSwapExchangeProvider) {
|
||||
|
@ -412,7 +412,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
address: receiveAddress,
|
||||
refundAddress: depositAddress,
|
||||
);
|
||||
amount = depositAmount;
|
||||
amount = isFixedRateMode ? receiveAmount : depositAmount;
|
||||
}
|
||||
|
||||
if (provider is XMRTOExchangeProvider) {
|
||||
|
@ -424,7 +424,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
address: receiveAddress,
|
||||
refundAddress: depositAddress,
|
||||
isBTCRequest: isReceiveAmountEntered);
|
||||
amount = depositAmount;
|
||||
amount = isFixedRateMode ? receiveAmount : depositAmount;
|
||||
}
|
||||
|
||||
if (provider is ChangeNowExchangeProvider) {
|
||||
|
@ -435,8 +435,8 @@ abstract class ExchangeViewModelBase with Store {
|
|||
toAmount: receiveAmount.replaceAll(',', '.'),
|
||||
refundAddress: depositAddress,
|
||||
address: receiveAddress,
|
||||
isReverse: isReverse);
|
||||
amount = isReverse ? receiveAmount : depositAmount;
|
||||
isReverse: isFixedRateMode);
|
||||
amount = isFixedRateMode ? receiveAmount : depositAmount;
|
||||
}
|
||||
|
||||
if (provider is MorphTokenExchangeProvider) {
|
||||
|
@ -446,13 +446,13 @@ abstract class ExchangeViewModelBase with Store {
|
|||
amount: depositAmount.replaceAll(',', '.'),
|
||||
refundAddress: depositAddress,
|
||||
address: receiveAddress);
|
||||
amount = depositAmount;
|
||||
amount = isFixedRateMode ? receiveAmount : depositAmount;
|
||||
}
|
||||
|
||||
amount = amount.replaceAll(',', '.');
|
||||
|
||||
if (limitsState is LimitsLoadedSuccessfully) {
|
||||
if (double.parse(amount) < limits.min!) {
|
||||
if (limits.max != null && double.parse(amount) < limits.min!) {
|
||||
continue;
|
||||
} else if (limits.max != null && double.parse(amount) > limits.max!) {
|
||||
continue;
|
||||
|
|
Loading…
Reference in a new issue