CAKE-43 | added the ability to enter an amount for xmr.to exchange in both currencies xmr and btc; added isReceiveAmountEntered to ExchangeViewModel; added receiveAmount and isBTCRequest to XMRTOTradeRequest; added isReceiveAmount to calculateAmount method of ExchangeProvider; fixed XMRTOExchangeProvider

OleksandrSobol committed Sep 25, 2020 at 22:55 UTC bc85058ad8468dd6c009cbe7e82ca9ec989fb3fd
8 files changed +50 -20
lib/exchange/changenow/changenow_exchange_provider.dart
+2 -1
@@ -146,7 +146,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
146
147 @override
148 Future<double> calculateAmount(
149 - {CryptoCurrency from, CryptoCurrency to, double amount}) async {
149 + {CryptoCurrency from, CryptoCurrency to, double amount,
150 + bool isReceiveAmount}) async {
151 final url = apiUri +
152 _exchangeAmountUriSufix +
153 amount.toString() +
lib/exchange/exchange_provider.dart
+1 -1
@@ -20,5 +20,5 @@ abstract class ExchangeProvider {
20 Future<Trade> createTrade({TradeRequest request});
21 Future<Trade> findTradeById({@required String id});
22 Future<double> calculateAmount(
23 - {CryptoCurrency from, CryptoCurrency to, double amount});
23 + {CryptoCurrency from, CryptoCurrency to, double amount, bool isReceiveAmount});
24 }
lib/exchange/morphtoken/morphtoken_exchange_provider.dart
+2 -1
@@ -186,7 +186,8 @@ class MorphTokenExchangeProvider extends ExchangeProvider {
186
187 @override
188 Future<double> calculateAmount(
189 - {CryptoCurrency from, CryptoCurrency to, double amount}) async {
189 + {CryptoCurrency from, CryptoCurrency to, double amount,
190 + bool isReceiveAmount}) async {
191 final url = apiUri + _ratesURISuffix;
192 final response = await get(url);
193 final responseJSON = json.decode(response.body) as Map<String, dynamic>;
lib/exchange/xmrto/xmrto_exchange_provider.dart
+17 -9
@@ -21,8 +21,8 @@ class XMRTOExchangeProvider extends ExchangeProvider {
21 ]);
22
23 static const userAgent = 'CakeWallet/XMR iOS';
24 - static const originalApiUri = 'https://xmr.to/api/v2/xmr2btc';
25 - static const proxyApiUri = 'https://xmrproxy.net/api/v2/xmr2btc';
24 + static const originalApiUri = 'https://xmr.to/api/v3/xmr2btc';
25 + static const proxyApiUri = 'https://xmrproxy.net/api/v3/xmr2btc';
26 static const _orderParameterUriSufix = '/order_parameter_query';
27 static const _orderStatusUriSufix = '/order_status_query/';
28 static const _orderCreateUriSufix = '/order_create/';
@@ -61,9 +61,9 @@ class XMRTOExchangeProvider extends ExchangeProvider {
61 }
62
63 final responseJSON = json.decode(response.body) as Map<String, dynamic>;
64 - double min = responseJSON['lower_limit'] as double;
65 - double max = responseJSON['upper_limit'] as double;
66 - final price = responseJSON['price'] as double;
64 + double min = double.parse(responseJSON['lower_limit'] as String);
65 + double max = double.parse(responseJSON['upper_limit'] as String);
66 + final price = double.parse(responseJSON['price'] as String);
67
68 if (price > 0) {
69 try {
@@ -88,7 +88,12 @@ class XMRTOExchangeProvider extends ExchangeProvider {
88 final _request = request as XMRTOTradeRequest;
89 final url = await getApiUri() + _orderCreateUriSufix;
90 final body = {
91 - 'xmr_amount': _request.amount,
91 + 'amount': _request.isBTCRequest
92 + ? _request.receiveAmount
93 + : _request.amount,
94 + 'amount_currency': _request.isBTCRequest
95 + ? _request.to.toString()
96 + : _request.from.toString(),
97 'btc_dest_address': _request.address
98 };
99 final response = await post(url,
@@ -165,7 +170,8 @@ class XMRTOExchangeProvider extends ExchangeProvider {
170
171 @override
172 Future<double> calculateAmount(
168 - {CryptoCurrency from, CryptoCurrency to, double amount}) async {
173 + {CryptoCurrency from, CryptoCurrency to, double amount,
174 + bool isReceiveAmount}) async {
175 if (from != CryptoCurrency.xmr && to != CryptoCurrency.btc) {
176 return 0;
177 }
@@ -174,7 +180,9 @@ class XMRTOExchangeProvider extends ExchangeProvider {
180 _rate = await _fetchRates();
181 }
182
177 - final double result = _rate * amount;
183 + final double result = isReceiveAmount
184 + ? _rate == 0 ? 0 : amount / _rate
185 + : _rate * amount;
186
187 return double.parse(result.toStringAsFixed(12));
188 }
@@ -185,7 +193,7 @@ class XMRTOExchangeProvider extends ExchangeProvider {
193 final response =
194 await get(url, headers: {'Content-Type': 'application/json'});
195 final responseJSON = json.decode(response.body) as Map<String, dynamic>;
188 - final price = responseJSON['price'] as double;
196 + final price = double.parse(responseJSON['price'] as String);
197
198 return price;
199 } catch (e) {
lib/exchange/xmrto/xmrto_trade_request.dart
+5 -1
@@ -7,12 +7,16 @@ class XMRTOTradeRequest extends TradeRequest {
7 {@required this.from,
8 @required this.to,
9 @required this.amount,
10 + @required this.receiveAmount,
11 @required this.address,
11 - @required this.refundAddress});
12 + @required this.refundAddress,
13 + @required this.isBTCRequest});
14
15 final CryptoCurrency from;
16 final CryptoCurrency to;
17 final String amount;
18 + final String receiveAmount;
19 final String address;
20 final String refundAddress;
21 + final bool isBTCRequest;
22 }
lib/src/screens/dashboard/dashboard_page.dart
+3 -3
@@ -114,9 +114,9 @@ class DashboardPage extends BasePage {
114 alignment: Alignment.centerLeft,
115 ),
116 ActionButton(
117 - image: sendImage,
118 - title: S.of(context).send,
119 - route: Routes.send,
117 + image: exchangeImage,
118 + title: S.of(context).exchange,
119 + route: Routes.exchange,
120 alignment: Alignment.centerLeft,
121 ),
122 ],
lib/src/screens/exchange/exchange_page.dart
+10 -1
@@ -1,4 +1,5 @@
1 import 'dart:ui';
2 +import 'package:cake_wallet/exchange/exchange_provider.dart';
3 import 'package:cake_wallet/exchange/exchange_template.dart';
4 import 'package:cake_wallet/src/screens/base_page.dart';
5 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
@@ -181,7 +182,7 @@ class ExchangePage extends BasePage {
182 exchangeViewModel.wallet.currency
183 ? exchangeViewModel.wallet.address
184 : exchangeViewModel.receiveAddress,
184 - initialIsAmountEditable: false,
185 + initialIsAmountEditable: exchangeViewModel.provider is XMRTOExchangeProvider ? true : false,
186 initialIsAddressEditable:
187 exchangeViewModel.isReceiveAddressEnabled,
188 isAmountEstimated: true,
@@ -487,6 +488,12 @@ class ExchangePage extends BasePage {
488 receiveKey.currentState.isAddressEditable(isEditable: isEnabled);
489 });
490
491 + reaction((_) => exchangeViewModel.provider, (ExchangeProvider provider) {
492 + provider is XMRTOExchangeProvider
493 + ? receiveKey.currentState.isAmountEditable(isEditable: true)
494 + : receiveKey.currentState.isAmountEditable(isEditable: false);
495 + });
496 +
497 // FIXME: FIXME
498
499 // reaction((_) => exchangeViewModel.tradeState, (ExchangeTradeState state) {
@@ -540,6 +547,7 @@ class ExchangePage extends BasePage {
547 if (depositAmountController.text != exchangeViewModel.depositAmount) {
548 exchangeViewModel.changeDepositAmount(
549 amount: depositAmountController.text);
550 + exchangeViewModel.isReceiveAmountEntered = false;
551 }
552 });
553
@@ -550,6 +558,7 @@ class ExchangePage extends BasePage {
558 if (receiveAmountController.text != exchangeViewModel.receiveAmount) {
559 exchangeViewModel.changeReceiveAmount(
560 amount: receiveAmountController.text);
561 + exchangeViewModel.isReceiveAmountEntered = true;
562 }
563 });
564
lib/view_model/exchange/exchange_view_model.dart
+10 -3
@@ -48,6 +48,7 @@ abstract class ExchangeViewModelBase with Store {
48 tradeState = ExchangeTradeStateInitial();
49 _cryptoNumberFormat = NumberFormat()..maximumFractionDigits = 12;
50 provider = providersForCurrentPair().first;
51 + isReceiveAmountEntered = false;
52 loadLimits();
53 }
54
@@ -92,6 +93,8 @@ abstract class ExchangeViewModelBase with Store {
93 @observable
94 bool isReceiveAddressEnabled;
95
96 + bool isReceiveAmountEntered;
97 +
98 Limits limits;
99
100 NumberFormat _cryptoNumberFormat;
@@ -138,7 +141,8 @@ abstract class ExchangeViewModelBase with Store {
141
142 provider
143 .calculateAmount(
141 - from: depositCurrency, to: receiveCurrency, amount: _amount)
144 + from: depositCurrency, to: receiveCurrency, amount: _amount,
145 + isReceiveAmount: true)
146 .then((amount) => _cryptoNumberFormat
147 .format(amount)
148 .toString()
@@ -159,7 +163,8 @@ abstract class ExchangeViewModelBase with Store {
163 final _amount = double.parse(amount);
164 provider
165 .calculateAmount(
162 - from: depositCurrency, to: receiveCurrency, amount: _amount)
166 + from: depositCurrency, to: receiveCurrency, amount: _amount,
167 + isReceiveAmount: false)
168 .then((amount) => _cryptoNumberFormat
169 .format(amount)
170 .toString()
@@ -191,8 +196,10 @@ abstract class ExchangeViewModelBase with Store {
196 from: depositCurrency,
197 to: receiveCurrency,
198 amount: depositAmount,
199 + receiveAmount: receiveAmount,
200 address: receiveAddress,
195 - refundAddress: depositAddress);
201 + refundAddress: depositAddress,
202 + isBTCRequest: isReceiveAmountEntered);
203 amount = depositAmount;
204 currency = depositCurrency;
205 }