dev
dart 336 lines 12 KB
Raw
1 import 'package:cake_wallet/buy/buy_provider.dart';
2 import 'package:cake_wallet/buy/payment_method.dart';
3 import 'package:cake_wallet/core/selectable_option.dart';
4 import 'package:cake_wallet/entities/calculate_fiat_amount.dart';
5 import 'package:cake_wallet/entities/fiat_currency.dart';
6 import 'package:cake_wallet/entities/provider_types.dart';
7 import 'package:cake_wallet/exchange/limits.dart';
8 import 'package:cw_core/crypto_currency.dart';
9
10 enum ProviderRecommendation { bestRate, lowKyc, successRate }
11
12 extension RecommendationTitle on ProviderRecommendation {
13 String get title {
14 switch (this) {
15 case ProviderRecommendation.bestRate:
16 return 'BEST RATE';
17 case ProviderRecommendation.lowKyc:
18 return 'LOW KYC';
19 case ProviderRecommendation.successRate:
20 return 'HIGHEST SUCCESS RATE';
21 }
22 }
23 }
24
25 ProviderRecommendation? getRecommendationFromString(String title) {
26 switch (title) {
27 case 'BEST RATE':
28 return ProviderRecommendation.bestRate;
29 case 'LowKyc':
30 return ProviderRecommendation.lowKyc;
31 case 'SuccessRate':
32 return ProviderRecommendation.successRate;
33 default:
34 return null;
35 }
36 }
37
38 class Quote extends SelectableOption {
39 Quote({
40 required this.rate,
41 required this.feeAmount,
42 required this.networkFee,
43 required this.transactionFee,
44 required this.payout,
45 required this.provider,
46 required this.paymentType,
47 required this.recommendations,
48 this.isBuyAction = true,
49 this.quoteId,
50 this.rampId,
51 this.rampName,
52 this.rampIconPath,
53 this.limits,
54 this.customPaymentMethodType,
55 }) : super(title: provider.isAggregator ? rampName ?? '' : provider.title);
56
57 final double rate;
58 final double feeAmount;
59 final double networkFee;
60 final double transactionFee;
61 final double payout;
62 final PaymentType paymentType;
63 final BuyProvider provider;
64 final String? quoteId;
65 final List<ProviderRecommendation> recommendations;
66 String? rampId;
67 String? rampName;
68 String? rampIconPath;
69 bool _isSelected = false;
70 bool _isBestRate = false;
71 bool isBuyAction;
72 Limits? limits;
73 String? customPaymentMethodType;
74
75 late FiatCurrency _fiatCurrency;
76 late CryptoCurrency _cryptoCurrency;
77
78 bool get isSelected => _isSelected;
79
80 bool get isBestRate => _isBestRate;
81
82 FiatCurrency get fiatCurrency => _fiatCurrency;
83
84 CryptoCurrency get cryptoCurrency => _cryptoCurrency;
85
86 @override
87 bool get isOptionSelected => this._isSelected;
88
89 @override
90 String get lightIconPath =>
91 provider.isAggregator ? rampIconPath ?? provider.lightIcon : provider.lightIcon;
92
93 @override
94 String get darkIconPath =>
95 provider.isAggregator ? rampIconPath ?? provider.darkIcon : provider.darkIcon;
96
97 @override
98 List<String> get badges => recommendations.map((e) => e.title).toList();
99
100 @override
101 String get topLeftSubTitle => this.rate > 0
102 ? '1 ${cryptoCurrency.toString()} = ${formatWithCommas(rate.toStringAsFixed(2))} ${fiatCurrency.toString()}'
103 : '';
104
105 @override
106 String get bottomLeftSubTitle {
107 if (limits != null) {
108 final min = limits!.min;
109 final max = limits!.max;
110 return 'min: ${formatWithCommas(min?.toString())} ${fiatCurrency.toString()} | max: ${max == double.infinity ? '' : '${formatWithCommas(max?.toString())} ${fiatCurrency.toString()}'}';
111 }
112 return '';
113 }
114
115 @override
116 String? get topRightSubTitle => '';
117
118 @override
119 String get topRightSubTitleLightIconPath => provider.isAggregator ? provider.lightIcon : '';
120
121 @override
122 String get topRightSubTitleDarkIconPath => provider.isAggregator ? provider.darkIcon : '';
123
124 String get quoteTitle => '${provider.title} - ${paymentType.name}';
125
126 String get formatedFee => '$feeAmount ${isBuyAction ? fiatCurrency : cryptoCurrency}';
127
128 set setIsSelected(bool isSelected) => _isSelected = isSelected;
129
130 set setIsBestRate(bool isBestRate) => _isBestRate = isBestRate;
131
132 set setFiatCurrency(FiatCurrency fiatCurrency) => _fiatCurrency = fiatCurrency;
133
134 set setCryptoCurrency(CryptoCurrency cryptoCurrency) => _cryptoCurrency = cryptoCurrency;
135
136 set setLimits(Limits limits) => this.limits = limits;
137
138 factory Quote.fromOnramperJson(Map<String, dynamic> json, bool isBuyAction,
139 Map<String, dynamic> metaData, PaymentType paymentType, String? customPaymentMethodType) {
140 final rate = _toDouble(json['rate']) ?? 0.0;
141 final networkFee = _toDouble(json['networkFee']) ?? 0.0;
142 final transactionFee = _toDouble(json['transactionFee']) ?? 0.0;
143 final feeAmount = double.parse((networkFee + transactionFee).toStringAsFixed(2));
144
145 final rampId = json['ramp'] as String? ?? '';
146 final rampData = metaData[rampId] ?? {};
147 final rampName = rampData['displayName'] as String? ?? '';
148 final rampIconPath = rampData['svg'] as String? ?? '';
149
150 final recommendations = json['recommendations'] != null
151 ? List<String>.from(json['recommendations'] as List<dynamic>)
152 : <String>[];
153
154 final enumRecommendations = recommendations
155 .map((e) => getRecommendationFromString(e))
156 .whereType<ProviderRecommendation>()
157 .toList();
158
159 final availablePaymentMethods = json['availablePaymentMethods'] as List<dynamic>? ?? [];
160 double minLimit = 0.0;
161 double maxLimit = double.infinity;
162
163 for (var paymentMethod in availablePaymentMethods) {
164 if (paymentMethod is Map<String, dynamic>) {
165 final details = paymentMethod['details'] as Map<String, dynamic>?;
166
167 if (details != null) {
168 final limits = details['limits'] as Map<String, dynamic>?;
169
170 if (limits != null && limits.isNotEmpty) {
171 final firstLimitEntry = limits.values.first as Map<String, dynamic>?;
172 if (firstLimitEntry != null) {
173 minLimit = _toDouble(firstLimitEntry['min'])?.roundToDouble() ?? 0.0;
174 maxLimit = _toDouble(firstLimitEntry['max'])?.roundToDouble() ?? double.infinity;
175 break;
176 }
177 }
178 }
179 }
180 }
181
182 return Quote(
183 rate: rate,
184 feeAmount: feeAmount,
185 networkFee: networkFee,
186 transactionFee: transactionFee,
187 payout: json['payout'] as double? ?? 0.0,
188 rampId: rampId,
189 rampName: rampName,
190 rampIconPath: rampIconPath,
191 paymentType: paymentType,
192 customPaymentMethodType: customPaymentMethodType,
193 quoteId: json['quoteId'] as String? ?? '',
194 recommendations: enumRecommendations,
195 provider: ProvidersHelper.getProviderByType(ProviderType.onramper),
196 isBuyAction: isBuyAction,
197 limits: Limits(min: minLimit, max: maxLimit),
198 );
199 }
200
201 factory Quote.fromMoonPayJson(
202 Map<String, dynamic> json, bool isBuyAction, PaymentType paymentType) {
203 final rate = isBuyAction
204 ? json['quoteCurrencyPrice'] as double? ?? 0.0
205 : json['baseCurrencyPrice'] as double? ?? 0.0;
206 final fee = _toDouble(json['feeAmount']) ?? 0.0;
207 final networkFee = _toDouble(json['networkFeeAmount']) ?? 0.0;
208 final transactionFee = _toDouble(json['extraFeeAmount']) ?? 0.0;
209 final feeAmount = double.parse((fee + networkFee + transactionFee).toStringAsFixed(2));
210
211 final baseCurrency = json['baseCurrency'] as Map<String, dynamic>?;
212
213 double minLimit = 0.0;
214 double maxLimit = double.infinity;
215
216 if (baseCurrency != null) {
217 minLimit = _toDouble(baseCurrency['minAmount']) ?? minLimit;
218 maxLimit = _toDouble(baseCurrency['maxAmount']) ?? maxLimit;
219 }
220
221 return Quote(
222 rate: rate,
223 feeAmount: feeAmount,
224 networkFee: networkFee,
225 transactionFee: transactionFee,
226 payout: _toDouble(json['quoteCurrencyAmount']) ?? 0.0,
227 paymentType: paymentType,
228 recommendations: [],
229 quoteId: json['signature'] as String? ?? '',
230 provider: ProvidersHelper.getProviderByType(ProviderType.moonpay),
231 isBuyAction: isBuyAction,
232 limits: Limits(min: minLimit, max: maxLimit),
233 );
234 }
235
236 factory Quote.fromDFXJson(
237 Map<String, dynamic> json,
238 bool isBuyAction,
239 PaymentType paymentType,
240 ) {
241 final rate = _toDouble(json['exchangeRate']) ?? 0.0;
242 final fees = json['fees'] as Map<String, dynamic>;
243
244 final minVolume = _toDouble(json['minVolume']) ?? 0.0;
245 final maxVolume = _toDouble(json['maxVolume']) ?? double.infinity;
246
247 return Quote(
248 rate: isBuyAction ? rate : 1 / rate,
249 feeAmount: _toDouble(json['feeAmount']) ?? 0.0,
250 networkFee: _toDouble(fees['network']) ?? 0.0,
251 transactionFee: _toDouble(fees['rate']) ?? 0.0,
252 payout: _toDouble(json['payout']) ?? 0.0,
253 paymentType: paymentType,
254 recommendations: [ProviderRecommendation.lowKyc],
255 provider: ProvidersHelper.getProviderByType(ProviderType.dfx),
256 isBuyAction: isBuyAction,
257 limits: Limits(min: minVolume, max: maxVolume),
258 );
259 }
260
261 factory Quote.fromRobinhoodJson(
262 Map<String, dynamic> json, bool isBuyAction, PaymentType paymentType) {
263 final networkFee = json['networkFee'] as Map<String, dynamic>;
264 final processingFee = json['processingFee'] as Map<String, dynamic>;
265 final networkFeeAmount = _toDouble(networkFee['fiatAmount']) ?? 0.0;
266 final transactionFeeAmount = _toDouble(processingFee['fiatAmount']) ?? 0.0;
267 final feeAmount = double.parse((networkFeeAmount + transactionFeeAmount).toStringAsFixed(2));
268
269 return Quote(
270 rate: _toDouble(json['price']) ?? 0.0,
271 feeAmount: feeAmount,
272 networkFee: _toDouble(networkFee['fiatAmount']) ?? 0.0,
273 transactionFee: _toDouble(processingFee['fiatAmount']) ?? 0.0,
274 payout: _toDouble(json['cryptoAmount']) ?? 0.0,
275 paymentType: paymentType,
276 recommendations: [],
277 provider: ProvidersHelper.getProviderByType(ProviderType.robinhood),
278 isBuyAction: isBuyAction,
279 limits: Limits(min: 0.0, max: double.infinity),
280 );
281 }
282
283 factory Quote.fromMeldJson(Map<String, dynamic> json, bool isBuyAction, PaymentType paymentType) {
284 final quotes = json['quotes'][0] as Map<String, dynamic>;
285 return Quote(
286 rate: quotes['exchangeRate'] as double? ?? 0.0,
287 feeAmount: quotes['totalFee'] as double? ?? 0.0,
288 networkFee: quotes['networkFee'] as double? ?? 0.0,
289 transactionFee: quotes['transactionFee'] as double? ?? 0.0,
290 payout: quotes['payout'] as double? ?? 0.0,
291 paymentType: paymentType,
292 recommendations: [],
293 provider: ProvidersHelper.getProviderByType(ProviderType.meld),
294 isBuyAction: isBuyAction,
295 limits: Limits(min: 0.0, max: double.infinity),
296 );
297 }
298
299 factory Quote.fromKryptonimJson(
300 Map<String, dynamic> json, bool isBuyAction, PaymentType paymentType) {
301 final fees = json['fees'] as Map<String, dynamic>;
302 // final rate = _toDouble(json['rate']) ?? 0.0;
303 final limits = json['limits'] as Map<String, dynamic>;
304 final minLimit = _toDouble(limits['min_amount']) ?? 0.0;
305 final maxLimit = _toDouble(limits['max_amount']) ?? double.infinity;
306 final convertedAmount = _toDouble(json['converted_amount']) ?? 0.0;
307 final amount = _toDouble(json['amount']) ?? 0.0;
308 final calculatedRate = amount / convertedAmount;
309 return Quote(
310 rate: calculatedRate,
311 feeAmount: _toDouble(fees['totalFee']) ?? 0.0,
312 networkFee: _toDouble(fees['network_fee']) ?? 0.0,
313 transactionFee: _toDouble(fees['operation_fee']) ?? 0.0,
314 payout: _toDouble(json['amount']) ?? 0.0,
315 paymentType: paymentType,
316 recommendations: [],
317 provider: ProvidersHelper.getProviderByType(ProviderType.kriptonim),
318 isBuyAction: isBuyAction,
319 limits: Limits(min: minLimit, max: maxLimit));
320 }
321
322 static double? _toDouble(dynamic value) {
323 if (value is int) {
324 return value.toDouble();
325 } else if (value is double) {
326 return value;
327 } else if (value is String) {
328 return double.tryParse(value);
329 }
330 return null;
331 }
332
333 @override
334 String toString() =>
335 'Quote: rate: $rate, feeAmount: $feeAmount, networkFee: $networkFee, transactionFee: $transactionFee, payout: $payout, paymentType: $paymentType, provider: $provider, quoteId: $quoteId, recommendations: $recommendations, isBuyAction: $isBuyAction, rampId: $rampId, rampName: $rampName, rampIconPath: $rampIconPath, [limits: min: ${limits?.min}, max: ${limits?.max}]';
336 }