Cw 1294 fix xo swaps bug (#2645)
* Improve currency parsing with tag support * changenow currency parsing fix * exolix currency parsing fix * letsExchange currency parsing fix * stealth currency parsing fix * trocador currency parsing fix --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
Serhii committed
Nov 21, 2025 at 23:45 UTC
c552ab86d25307959d0326a963f4c223947d2f10
10 files changed
+218
-54
cw_core/lib/crypto_currency.dart
+16
-1
@@ -1,5 +1,6 @@
1
import 'package:cw_core/currency.dart';
2
import 'package:cw_core/enumerable_item.dart';
3
+import 'package:collection/collection.dart';
4
5
class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implements Currency {
6
const CryptoCurrency({
@@ -336,9 +337,23 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
337
return CryptoCurrency._fullNameCurrencyMap[name.split("(").first.trim().toLowerCase()]!;
338
}
339
339
- static CryptoCurrency? safeParseCurrencyFromString(String? raw, {CryptoCurrency? walletCurrency}) {
340
+ static CryptoCurrency? safeParseCurrencyFromString(
341
+ String? raw, {
342
+ String? tag,
343
+ CryptoCurrency? walletCurrency,
344
+ }) {
345
if (raw == null || raw.isEmpty) return null;
346
347
+ if (tag != null && tag.isNotEmpty) {
348
+ final match = CryptoCurrency.all.firstWhereOrNull(
349
+ (e) =>
350
+ e.title.toUpperCase() == raw.toUpperCase() &&
351
+ e.tag?.toUpperCase() == tag.toUpperCase(),
352
+ );
353
+ if (match != null) return match;
354
+ return null;
355
+ }
356
+
357
try {
358
return CryptoCurrency.fromString(raw, walletCurrency: walletCurrency);
359
} catch (_) {}
cw_evm/lib/evm_chain_wallet.dart
+6
-2
@@ -476,8 +476,12 @@ abstract class EVMChainWalletBase
476
'0x${opReturnMemo.codeUnits.map((char) => char.toRadixString(16).padLeft(2, '0')).join()}';
477
}
478
479
- final CryptoCurrency transactionCurrency =
480
- balance.keys.firstWhere((element) => element.title == _credentials.currency.title);
479
+ final transactionCurrency = balance.keys.firstWhere(
480
+ (currency) =>
481
+ currency.title == _credentials.currency.title &&
482
+ currency.tag == _credentials.currency.tag,
483
+ orElse: () => throw Exception(
484
+ 'Currency ${_credentials.currency.title} ${_credentials.currency.tag} is not accessible in the wallet, try to enable it first.'));
485
486
final currencyBalance = balance[transactionCurrency]!;
487
BigInt totalAmount = BigInt.zero;
cw_solana/lib/solana_wallet.dart
+6
-2
@@ -226,8 +226,12 @@ abstract class SolanaWalletBase
226
227
await _updateBalance();
228
229
- final CryptoCurrency transactionCurrency =
230
- balance.keys.firstWhere((element) => element.title == solCredentials.currency.title);
229
+ final transactionCurrency = balance.keys.firstWhere(
230
+ (currency) =>
231
+ currency.title == credentials.currency.title &&
232
+ currency.tag == credentials.currency.tag,
233
+ orElse: () => throw Exception(
234
+ 'Currency ${credentials.currency.title} ${credentials.currency.tag} is not accessible in the wallet, try to enable it first.'));
235
236
final walletBalanceForCurrency = balance[transactionCurrency]!.balance;
237
cw_tron/lib/tron_wallet.dart
+7
-2
@@ -312,8 +312,13 @@ abstract class TronWalletBase
312
313
final hasMultiDestination = outputs.length > 1;
314
315
- final CryptoCurrency transactionCurrency =
316
- balance.keys.firstWhere((element) => element.title == tronCredentials.currency.title);
315
+ final transactionCurrency = balance.keys.firstWhere(
316
+ (currency) =>
317
+ currency.title == tronCredentials.currency.title &&
318
+ currency.tag == tronCredentials.currency.tag,
319
+ orElse: () => throw Exception(
320
+ 'Currency ${tronCredentials.currency.title} ${tronCredentials.currency.tag} is not accessible in the wallet, try to enable it first.'));
321
+
322
323
final walletBalanceForCurrency = balance[transactionCurrency]!.balance;
324
lib/exchange/provider/changenow_exchange_provider.dart
+13
-7
@@ -278,12 +278,21 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
278
throw Exception('Unexpected http status: ${response.statusCode}');
279
280
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
281
+
282
+ // Parsing 'from' currency
283
final fromCurrency = responseJSON['fromCurrency'] as String;
284
final fromNetwork = responseJSON['fromNetwork'] as String?;
283
- final from = CryptoCurrency.safeParseCurrencyFromString(fromCurrency);
285
+ final _normalizedFromNetwork = _normalizeNetworkType(fromNetwork ?? '');
286
+ final fromTag = fromCurrency == _normalizedFromNetwork ? null : _normalizedFromNetwork;
287
+ final from = CryptoCurrency.safeParseCurrencyFromString(fromCurrency, tag: fromTag);
288
+
289
+ // Parsing 'to' currency
290
final toCurrency = responseJSON['toCurrency'] as String;
291
final toNetwork = responseJSON['toNetwork'] as String?;
286
- final to = CryptoCurrency.safeParseCurrencyFromString(toCurrency);
292
+ final _normalizedToNetwork = _normalizeNetworkType(toNetwork ?? '');
293
+ final toTag = toCurrency == _normalizedToNetwork ? null : _normalizedToNetwork;
294
+ final to = CryptoCurrency.safeParseCurrencyFromString(toCurrency, tag: toTag);
295
+
296
final inputAddress = responseJSON['payinAddress'] as String;
297
final expectedSendAmount = responseJSON['expectedAmountFrom'].toString();
298
final status = responseJSON['status'] as String;
@@ -294,9 +303,6 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
303
final payoutAddress = responseJSON['payoutAddress'] as String;
304
final expiredAt = DateTime.tryParse(expiredAtRaw ?? '')?.toLocal();
305
297
- final _normalizedFromNetwork = _normalizeNetworkType(fromNetwork ?? '');
298
- final _normalizedToNetwork = _normalizeNetworkType(toNetwork ?? '');
299
-
306
return Trade(
307
id: id,
308
from: from,
@@ -309,8 +315,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
315
expiredAt: expiredAt,
316
outputTransaction: outputTransaction,
317
payoutAddress: payoutAddress,
312
- userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_' + '${_normalizedFromNetwork.toUpperCase()}',
313
- userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + '${_normalizedToNetwork.toUpperCase()}',
318
+ userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
319
+ userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
320
);
321
}
322
lib/exchange/provider/exolix_exchange_provider.dart
+13
-4
@@ -360,10 +360,19 @@ class ExolixExchangeProvider extends ExchangeProvider {
360
throw Exception('Unexpected http status: ${response.statusCode}');
361
362
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
363
+
364
+ // Parsing 'from' currency
365
final coinFrom = responseJSON['coinFrom']['coinCode'] as String;
366
final coinFromNetwork = responseJSON['coinFrom']['network'] as String?;
367
+ final fromTag = coinFrom == coinFromNetwork ? null : coinFromNetwork;
368
+ final from = CryptoCurrency.safeParseCurrencyFromString(coinFrom, tag: fromTag);
369
+
370
+ // Parsing 'to' currency
371
final coinTo = responseJSON['coinTo']['coinCode'] as String;
372
final coinToNetwork = responseJSON['coinTo']['network'] as String?;
373
+ final toTag = coinTo == coinToNetwork ? null : coinToNetwork;
374
+ final to = CryptoCurrency.safeParseCurrencyFromString(coinTo, tag: toTag);
375
+
376
final inputAddress = responseJSON['depositAddress'] as String;
377
final amount = responseJSON['amount'].toString();
378
final status = responseJSON['status'] as String;
@@ -373,8 +382,8 @@ class ExolixExchangeProvider extends ExchangeProvider {
382
383
return Trade(
384
id: id,
376
- from: CryptoCurrency.safeParseCurrencyFromString(coinFrom),
377
- to: CryptoCurrency.safeParseCurrencyFromString(coinTo),
385
+ from: from,
386
+ to: to,
387
provider: description,
388
inputAddress: inputAddress,
389
amount: amount,
@@ -382,8 +391,8 @@ class ExolixExchangeProvider extends ExchangeProvider {
391
extraId: extraId,
392
outputTransaction: outputTransaction,
393
payoutAddress: payoutAddress,
385
- userCurrencyFromRaw: '${coinFrom.toUpperCase()}' + '_' + '${coinFromNetwork ?? ''}',
386
- userCurrencyToRaw: '${coinTo.toUpperCase()}' + '_' + '${coinToNetwork ?? ''}',
394
+ userCurrencyFromRaw: '${coinFrom.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
395
+ userCurrencyToRaw: '${coinTo.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
396
);
397
}
398
lib/exchange/provider/letsexchange_exchange_provider.dart
+18
-9
@@ -348,10 +348,22 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
348
throw Exception('LetsExchange fetch trade failed: ${response.body}');
349
}
350
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
351
- final from = responseJSON['coin_from'] as String;
351
+
352
+ // Parsing 'from' currency
353
+ final fromCurrency = responseJSON['coin_from'] as String;
354
final fromNetwork = responseJSON['coin_from_network'] as String?;
353
- final to = responseJSON['coin_to'] as String;
355
+ final normalizedFromNetwork = _normalizeNetworkType(fromNetwork ?? '');
356
+ final fromTag = fromCurrency == normalizedFromNetwork ? null : normalizedFromNetwork;
357
+ final from = CryptoCurrency.safeParseCurrencyFromString(fromCurrency, tag: fromTag);
358
+
359
+ // Parsing 'to' currency
360
+ final toCurrency = responseJSON['coin_to'] as String;
361
final toNetwork = responseJSON['coin_to_network'] as String?;
362
+ final normalizedToNetwork = _normalizeNetworkType(toNetwork ?? '');
363
+ final toTag = toCurrency == normalizedToNetwork ? null : normalizedToNetwork;
364
+ final to = CryptoCurrency.safeParseCurrencyFromString(toCurrency, tag: toTag);
365
+
366
+
367
final payoutAddress = responseJSON['withdrawal'] as String;
368
final depositAddress = responseJSON['deposit'] as String;
369
final refundAddress = responseJSON['return'] as String;
@@ -365,13 +377,10 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
377
final createdAt = DateTime.parse(createdAtString).toLocal();
378
final expiredAt = DateTime.fromMillisecondsSinceEpoch(expiredAtTimestamp * 1000).toLocal();
379
368
- final normalizedFromNetwork = _normalizeNetworkType(fromNetwork ?? '');
369
- final normalizedToNetwork = _normalizeNetworkType(toNetwork ?? '');
370
-
380
return Trade(
381
id: id,
373
- from: CryptoCurrency.safeParseCurrencyFromString(from),
374
- to: CryptoCurrency.safeParseCurrencyFromString(to),
382
+ from: from,
383
+ to: to,
384
provider: description,
385
inputAddress: depositAddress,
386
payoutAddress: payoutAddress,
@@ -383,8 +392,8 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
392
expiredAt: expiredAt,
393
isRefund: status == 'refund',
394
extraId: extraId,
386
- userCurrencyFromRaw: '$from' + '_' + normalizedFromNetwork,
387
- userCurrencyToRaw: '$to' + '_' + '$normalizedToNetwork',
395
+ userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
396
+ userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
397
);
398
}
399
lib/exchange/provider/stealth_ex_exchange_provider.dart
+26
-15
@@ -74,8 +74,8 @@ class StealthExExchangeProvider extends ExchangeProvider {
74
throw Exception('StealthEx fetch limits failed: ${response.body}');
75
}
76
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
77
- final min = toDouble(responseJSON['min_amount']);
78
- final max = responseJSON['max_amount'] as double?;
77
+ final min = _toDouble(responseJSON['min_amount']);
78
+ final max = _toDouble(responseJSON['max_amount']);
79
return Limits(min: min, max: max);
80
} catch (e) {
81
log(e.toString());
@@ -230,8 +230,8 @@ class StealthExExchangeProvider extends ExchangeProvider {
230
final payoutAddress = withdrawal['address'] as String;
231
final depositAddress = deposit['address'] as String;
232
final refundAddress = responseJSON['refund_address'] as String;
233
- final depositAmount = toDouble(deposit['amount']);
234
- final receiveAmount = toDouble(withdrawal['amount']);
233
+ final depositAmount = _toDouble(deposit['amount']);
234
+ final receiveAmount = _toDouble(withdrawal['amount']);
235
final status = responseJSON['status'] as String;
236
final createdAtString = responseJSON['created_at'] as String;
237
final extraId = deposit['extra_id'] as String?;
@@ -342,15 +342,24 @@ class StealthExExchangeProvider extends ExchangeProvider {
342
final withdrawal = responseJSON['withdrawal'] as Map<String, dynamic>;
343
344
final respId = responseJSON['id'] as String;
345
- final from = deposit['symbol'] as String;
345
+
346
+ // Parsing 'from' currency with network tag
347
+ final fromCurrency = deposit['symbol'] as String;
348
final fromNetwork = deposit['network'] as String?;
347
- final to = withdrawal['symbol'] as String;
349
+ final fromTag = fromNetwork == 'mainnet' ? null : fromNetwork;
350
+ final from = CryptoCurrency.safeParseCurrencyFromString(fromCurrency, tag: fromTag);
351
+
352
+ // Parsing 'to' currency with network tag
353
+ final toCurrency = withdrawal['symbol'] as String;
354
final toNetwork = withdrawal['network'] as String?;
355
+ final toTag = toNetwork == 'mainnet' ? null : toNetwork;
356
+ final to = CryptoCurrency.safeParseCurrencyFromString(toCurrency, tag: toTag);
357
+
358
final payoutAddress = withdrawal['address'] as String;
359
final depositAddress = deposit['address'] as String;
360
final refundAddress = responseJSON['refund_address'] as String;
352
- final depositAmount = toDouble(deposit['amount']);
353
- final receiveAmount = toDouble(withdrawal['amount']);
361
+ final depositAmount = _toDouble(deposit['amount']);
362
+ final receiveAmount = _toDouble(withdrawal['amount']);
363
final status = responseJSON['status'] as String;
364
final createdAtString = responseJSON['created_at'] as String;
365
final createdAt = DateTime.parse(createdAtString).toLocal();
@@ -358,8 +367,8 @@ class StealthExExchangeProvider extends ExchangeProvider {
367
368
return Trade(
369
id: respId,
361
- from: CryptoCurrency.safeParseCurrencyFromString(from),
362
- to: CryptoCurrency.safeParseCurrencyFromString(to),
370
+ from: from,
371
+ to: to,
372
provider: description,
373
inputAddress: depositAddress,
374
payoutAddress: payoutAddress,
@@ -370,8 +379,8 @@ class StealthExExchangeProvider extends ExchangeProvider {
379
createdAt: createdAt,
380
isRefund: status == 'refunded',
381
extraId: extraId,
373
- userCurrencyFromRaw: '${from.toUpperCase()}' + '_' + '${fromNetwork?.toUpperCase() ?? ''}',
374
- userCurrencyToRaw: '${to.toUpperCase()}' + '_' + '${toNetwork?.toUpperCase() ?? ''}',
382
+ userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
383
+ userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
384
);
385
}
386
@@ -414,16 +423,18 @@ class StealthExExchangeProvider extends ExchangeProvider {
423
}
424
}
425
417
- double toDouble(dynamic value) {
426
+ static double? _toDouble(dynamic value) {
427
if (value is int) {
428
return value.toDouble();
429
} else if (value is double) {
430
return value;
422
- } else {
423
- return 0.0;
431
+ } else if (value is String) {
432
+ return double.tryParse(value);
433
}
434
+ return null;
435
}
436
437
+
438
String _getName(CryptoCurrency currency) {
439
if (currency == CryptoCurrency.usdcEPoly) return 'usdce';
440
return currency.title.toLowerCase();
lib/exchange/provider/trocador_exchange_provider.dart
+14
-7
@@ -420,15 +420,22 @@ class TrocadorExchangeProvider extends ExchangeProvider {
420
final providerName = responseJSON['provider'] as String;
421
final addressProviderMemo = responseJSON['address_provider_memo'] as String?;
422
423
- final from = responseJSON['ticker_from'] as String;
424
- final networkFrom = responseJSON['network_from'] as String?;
425
- final to = responseJSON['ticker_to'] as String;
423
+ final fromCurrency = responseJSON['ticker_from'] as String;
424
+ final fromNetwork = responseJSON['network_from'] as String?;
425
+ final _normalizedFromNetwork = _normalizeNetworkType(fromNetwork ?? '');
426
+ final fromTag = _normalizedFromNetwork.isEmpty || _normalizedFromNetwork == 'Mainnet' ? null : _normalizedFromNetwork;
427
+ final from = CryptoCurrency.safeParseCurrencyFromString(fromCurrency, tag: fromTag);
428
+
429
+ final toCurrency = responseJSON['ticker_to'] as String;
430
final networkTo = responseJSON['network_to'] as String?;
431
+ final _normalizedToNetwork = _normalizeNetworkType(networkTo ?? '');
432
+ final toTag = _normalizedToNetwork.isEmpty || _normalizedToNetwork == 'Mainnet' ? null : _normalizedToNetwork;
433
+ final to = CryptoCurrency.safeParseCurrencyFromString(toCurrency, tag: toTag);
434
435
return Trade(
436
id: id,
430
- from: CryptoCurrency.safeParseCurrencyFromString(from),
431
- to: CryptoCurrency.safeParseCurrencyFromString(to),
437
+ from: from,
438
+ to: to,
439
provider: description,
440
inputAddress: inputAddress,
441
refundAddress: refundAddress,
@@ -440,8 +447,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
447
providerId: providerId,
448
providerName: providerName,
449
extraId: addressProviderMemo,
443
- userCurrencyFromRaw: '${from.toUpperCase()}' + '_' + _normalizeNetworkType(networkFrom ?? ''),
444
- userCurrencyToRaw: '${to.toUpperCase()}' + '_' + _normalizeNetworkType(networkTo ?? ''), // Handle null network
450
+ userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
451
+ userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
452
);
453
});
454
}
lib/exchange/provider/xoswap_exchange_provider.dart
+99
-5
@@ -43,8 +43,41 @@ class XOSwapExchangeProvider extends ExchangeProvider {
43
'LTC': 'litecoin',
44
'EOS': 'eosio',
45
'XLM': 'stellar',
46
+ 'BASE': 'basemainnet',
47
};
47
-
48
+
49
+ static const supportedTags = [
50
+ 'POL',
51
+ 'ETH',
52
+ 'BTC',
53
+ 'BSC',
54
+ 'SOL',
55
+ 'TRX',
56
+ 'ZEC',
57
+ 'ADA',
58
+ 'DOGE',
59
+ 'XMR',
60
+ 'BCH',
61
+ 'BSV',
62
+ 'XRP',
63
+ 'LTC',
64
+ 'EOS',
65
+ 'XLM',
66
+ 'BASE',
67
+ ];
68
+
69
+
70
+ String _normalizeXOSwapsNetwork(String string) {
71
+ final lower = string.toLowerCase();
72
+
73
+ if (lower.endsWith('matic0a883d9b')) return string.replaceFirst(RegExp(r'matic0a883d9b$', caseSensitive: false), 'POL');
74
+ if (lower.endsWith('matic86e249c1')) return string.replaceFirst(RegExp(r'matic86e249c1$', caseSensitive: false), 'POL');
75
+ if (lower.endsWith('bscddedf0f8')) return string.replaceFirst(RegExp(r'bscddedf0f8$', caseSensitive: false), 'BSC');
76
+ if (lower.endsWith('basemainnetb5a52617')) return string.replaceFirst(RegExp(r'basemainnetb5a52617$', caseSensitive: false), 'BASE');
77
+
78
+ return string;
79
+ }
80
+
81
@override
82
String get title => 'XOSwap';
83
@@ -422,9 +455,46 @@ class XOSwapExchangeProvider extends ExchangeProvider {
455
final pairId = responseJSON['pairId'] as String;
456
final pairParts = pairId.split('_');
457
final fromAsset = pairParts.isNotEmpty ? pairParts[0] : '';
458
+ final normalizedFromAsset = _normalizeXOSwapsNetwork(fromAsset);
459
+ String? fromAssetTag = _extractTagFromAsset(normalizedFromAsset);
460
+
461
+ String fromAssetBase = fromAssetTag != null
462
+ ? normalizedFromAsset.substring(0, normalizedFromAsset.length - fromAssetTag.length)
463
+ : normalizedFromAsset;
464
+
465
+ // Special case for USDT defaulting to ETH tag
466
+ if (fromAssetBase == 'USDT' && fromAssetTag == null) {
467
+ fromAssetTag = 'ETH';
468
+ }
469
+
470
+ // Special case for BASE defaulting to BASE tag
471
+ if (fromAssetBase == 'BASE' && fromAssetTag == null) {
472
+ fromAssetTag = 'BASE';
473
+ fromAssetBase = 'ETH';
474
+ }
475
+
476
final toAsset = pairParts.length > 1 ? pairParts[1] : '';
426
- final fromCurrency = CryptoCurrency.safeParseCurrencyFromString(fromAsset);
427
- final toCurrency = CryptoCurrency.safeParseCurrencyFromString(toAsset);
477
+ final normalizedToAsset = _normalizeXOSwapsNetwork(toAsset);
478
+ String? toAssetTag = _extractTagFromAsset(normalizedToAsset);
479
+
480
+ String toAssetBase = toAssetTag != null
481
+ ? normalizedToAsset.substring(0, normalizedToAsset.length - toAssetTag.length)
482
+ : normalizedToAsset;
483
+
484
+ // Special case for USDT defaulting to ETH tag
485
+ if (toAssetBase == 'USDT' && toAssetTag == null) {
486
+ toAssetTag = 'ETH';
487
+ }
488
+
489
+ // Special case for BASE defaulting to BASE tag
490
+ if (toAssetBase == 'BASE' && toAssetTag == null) {
491
+ toAssetTag = 'ETH';
492
+ toAssetBase = 'BASE';
493
+ }
494
+
495
+ final fromCurrency = CryptoCurrency.safeParseCurrencyFromString(fromAssetBase,tag: fromAssetTag);
496
+ final toCurrency = CryptoCurrency.safeParseCurrencyFromString(toAssetBase,tag: toAssetTag);
497
+
498
499
final amount = responseJSON['amount'] as Map<String, dynamic>;
500
final toAmount = responseJSON['toAmount'] as Map<String, dynamic>;
@@ -439,6 +509,14 @@ class XOSwapExchangeProvider extends ExchangeProvider {
509
final createdAt = DateTime.parse(createdAtString).toLocal();
510
final extraId = responseJSON['payInAddressTag'] as String?;
511
512
+ final userCurrencyFromRaw = fromCurrency != null
513
+ ? '${fromCurrency.title}' + '_' + '${fromCurrency.tag ?? ''}'
514
+ : '${fromAssetBase}' + '_' + '${fromAssetTag ?? ''}';
515
+
516
+ final userCurrencyToRaw = toCurrency != null
517
+ ? '${toCurrency.title}' + '_' + '${toCurrency.tag ?? ''}'
518
+ : '${toAssetBase}' + '_' + '${toAssetTag ?? ''}';
519
+
520
return Trade(
521
id: orderId,
522
from: fromCurrency,
@@ -452,8 +530,8 @@ class XOSwapExchangeProvider extends ExchangeProvider {
530
receiveAmount: receiveAmount,
531
payoutAddress: payoutAddress,
532
extraId: extraId,
455
- userCurrencyFromRaw: '$fromAsset' + '_',
456
- userCurrencyToRaw: '$toAsset' + '_',
533
+ userCurrencyFromRaw: userCurrencyFromRaw,
534
+ userCurrencyToRaw: userCurrencyToRaw,
535
);
536
} catch (e) {
537
printV(e.toString());
@@ -461,6 +539,22 @@ class XOSwapExchangeProvider extends ExchangeProvider {
539
}
540
}
541
542
+ // ensure something remains before tag (at least 2 chars)
543
+ String? _extractTagFromAsset(String asset) {
544
+
545
+
546
+
547
+ for (final tag in supportedTags) {
548
+ if (asset.endsWith(tag)) {
549
+ final prefixLength = asset.length - tag.length;
550
+ if (prefixLength >= 2) {
551
+ return tag;
552
+ }
553
+ }
554
+ }
555
+ return null;
556
+ }
557
+
558
double _toDouble(dynamic value) {
559
if (value is int) {
560
return value.toDouble();