From 341e06196da34df29891fb3ec28b47ca94fee3a5 Mon Sep 17 00:00:00 2001 From: Adegoke David <64401859+Blazebrain@users.noreply.github.com> Date: Sun, 21 Jul 2024 00:26:05 +0100 Subject: [PATCH] CW-674: Improve Exchange Flow With Timeout For Rates (#1536) * fix: Improve exchange flow by adding a timeout to the call to fetch rate from providers * fix: Adjust time limit for fetching rate to 7 seconds and add timelimit to fetching limits * Improve loadlimits function [skip ci] --------- Co-authored-by: OmarHatem --- .../provider/sideshift_exchange_provider.dart | 16 ++++- .../exchange/exchange_view_model.dart | 58 ++++++++++++------- 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/lib/exchange/provider/sideshift_exchange_provider.dart b/lib/exchange/provider/sideshift_exchange_provider.dart index 1be4f8045..127421bbd 100644 --- a/lib/exchange/provider/sideshift_exchange_provider.dart +++ b/lib/exchange/provider/sideshift_exchange_provider.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:developer'; import 'package:cake_wallet/.secrets.g.dart' as secrets; import 'package:cake_wallet/exchange/provider/exchange_provider.dart'; @@ -29,6 +30,7 @@ class SideShiftExchangeProvider extends ExchangeProvider { CryptoCurrency.bttc, CryptoCurrency.usdt, CryptoCurrency.eos, + CryptoCurrency.xmr, ]; static const affiliateId = secrets.sideShiftAffiliateId; @@ -137,8 +139,20 @@ class SideShiftExchangeProvider extends ExchangeProvider { final response = await get(uri); final responseJSON = json.decode(response.body) as Map; + if (response.statusCode == 500) { + final responseJSON = json.decode(response.body) as Map; + final error = responseJSON['error']['message'] as String; + + throw Exception('SideShift Internal Server Error: $error'); + } + + if (response.statusCode != 200) { + throw Exception('Unexpected http status: ${response.statusCode}'); + } + return double.parse(responseJSON['rate'] as String); - } catch (_) { + } catch (e) { + log('Error fetching rate in SideShift Provider: ${e.toString()}'); return 0.00; } } diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index 404fa0f25..a97b3dc05 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -405,13 +405,22 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with .where((element) => !isFixedRateMode || element.supportsFixedRate) .toList(); - final result = await Future.wait(_providers.map((element) => element.fetchRate( - from: depositCurrency, - to: receiveCurrency, - amount: amount, - isFixedRateMode: isFixedRateMode, - isReceiveAmount: isFixedRateMode))); - + final result = await Future.wait( + _providers.map( + (element) => element + .fetchRate( + from: depositCurrency, + to: receiveCurrency, + amount: amount, + isFixedRateMode: isFixedRateMode, + isReceiveAmount: isFixedRateMode, + ) + .timeout( + Duration(seconds: 7), + onTimeout: () => 0.0, + ), + ), + ); _sortedAvailableProviders.clear(); for (int i = 0; i < result.length; i++) { @@ -441,22 +450,29 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with double? highestMax = 0.0; try { - for (var provider in selectedProviders) { - /// if this provider is not valid for the current pair, skip it - if (!providersForCurrentPair().contains(provider)) continue; + final result = await Future.wait(selectedProviders + .where((element) => providersForCurrentPair().contains(provider)) + .map((provider) => provider + .fetchLimits( + from: from, + to: to, + isFixedRateMode: isFixedRateMode, + ) + .onError((error, stackTrace) => Limits(max: 0.0, min: double.maxFinite)) + .timeout( + Duration(seconds: 7), + onTimeout: () => Limits(max: 0.0, min: double.maxFinite), + ))); - try { - final tempLimits = - await provider.fetchLimits(from: from, to: to, isFixedRateMode: isFixedRateMode); - - if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) lowestMin = tempLimits.min; - - if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax) - highestMax = tempLimits.max; - } catch (e) { - continue; + result.forEach((tempLimits) { + if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin!) { + lowestMin = tempLimits.min; } - } + + if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax!) { + highestMax = tempLimits.max; + } + }); } on ConcurrentModificationError { /// if user changed the selected providers while fetching limits /// then delay the fetching limits a bit and try again