feat: migrate Trade data to SQLite with TradeLegacy for backward compatibility (#3106)
* feat: migrate Trade data to SQLite with TradeLegacy for backward compatibility * feat: persist full currency snapshots in sql storage, not raw-only [WIP] * feat: persist full trade currency snapshots in sql storage * refactor trade and currency handling for migration * Minor fixes --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
David Adegoke committed
May 6, 2026 at 23:02 UTC
9f6396f5d8c83f0a6a97ada56eb068ea41ebd5b8
39 files changed
+1003
-825
cw_core/lib/db/sqlite.dart
+67
-1
@@ -41,7 +41,7 @@ Future<void> initDb({String? pathOverride}) async {
41
}
42
}
43
await db?.close();
44
- db = await openDatabase(dbFile.path, version: 5,
44
+ db = await openDatabase(dbFile.path, version: 6,
45
onUpgrade: (Database db, int oldVersion, int newVersion) async {
46
printV("migrating: $oldVersion, $newVersion");
47
if (oldVersion <= 1) {
@@ -93,6 +93,9 @@ CREATE TABLE IF NOT EXISTS BalanceCardStyleSettings (
93
if (oldVersion <= 4) {
94
await _createBridgeTransferTable(db);
95
}
96
+ if (oldVersion <= 5) {
97
+ await _createTradeTable(db);
98
+ }
99
},
100
onCreate: (Database db, int version) async {
101
await db.execute(
@@ -191,10 +194,73 @@ CREATE TABLE BalanceCardStyleSettings (
194
);
195
''');
196
await _createBridgeTransferTable(db);
197
+ await _createTradeTable(db);
198
}
199
);
200
}
201
202
+Future<void> _createTradeTable(Database db) async {
203
+ await db.execute('''
204
+CREATE TABLE IF NOT EXISTS Trade (
205
+ tradeId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
206
+ id TEXT NOT NULL,
207
+ providerRaw INTEGER NOT NULL DEFAULT 0,
208
+ fromTitle TEXT,
209
+ fromName TEXT,
210
+ fromTag TEXT,
211
+ fromFullName TEXT,
212
+ fromDecimals INTEGER,
213
+ fromRaw INTEGER,
214
+ fromIconPath TEXT,
215
+ fromFlatIconPath TEXT,
216
+ fromChainIconPath TEXT,
217
+ toTitle TEXT,
218
+ toName TEXT,
219
+ toTag TEXT,
220
+ toFullName TEXT,
221
+ toDecimals INTEGER,
222
+ toRaw INTEGER,
223
+ toIconPath TEXT,
224
+ toFlatIconPath TEXT,
225
+ toChainIconPath TEXT,
226
+ stateRaw TEXT NOT NULL DEFAULT '',
227
+ createdAt INTEGER,
228
+ expiredAt INTEGER,
229
+ amount TEXT NOT NULL DEFAULT '',
230
+ receiveAmount TEXT,
231
+ inputAddress TEXT,
232
+ extraId TEXT,
233
+ outputTransaction TEXT,
234
+ refundAddress TEXT,
235
+ walletId TEXT,
236
+ payoutAddress TEXT,
237
+ password TEXT,
238
+ providerId TEXT,
239
+ providerName TEXT,
240
+ fromWalletAddress TEXT,
241
+ memo TEXT,
242
+ txId TEXT,
243
+ isRefund INTEGER DEFAULT 0,
244
+ isSendAll INTEGER DEFAULT 0,
245
+ router TEXT,
246
+ needToRegisterInSwapXyz INTEGER DEFAULT 0,
247
+ sourceTokenAddress TEXT,
248
+ sourceTokenDecimals INTEGER,
249
+ routerData TEXT,
250
+ routerValue TEXT,
251
+ routerChainId INTEGER,
252
+ sourceTokenAmountRaw TEXT,
253
+ requiresTokenApproval INTEGER DEFAULT 0,
254
+ chainId INTEGER,
255
+ fee REAL
256
+);
257
+''');
258
+ await db.execute('''
259
+CREATE UNIQUE INDEX IF NOT EXISTS idx_trade_id_unique
260
+ON Trade (id);
261
+''');
262
+}
263
+
264
Future<Map<String, dynamic>> dumpDb() async {
265
try {
266
return await _dumpDb();
cw_core/lib/wallet_info_legacy.dart
+33
-29
@@ -246,35 +246,35 @@ class WalletInfo extends HiveObject {
246
Future<void> migrateToSqlite() async {
247
final di = newWi.DerivationInfo(
248
id: 0,
249
- derivationType: derivationInfo?.derivationType ?? derivationType ?? newWi.DerivationType.unknown,
249
+ derivationType:
250
+ derivationInfo?.derivationType ?? derivationType ?? newWi.DerivationType.unknown,
251
derivationPath: derivationInfo?.derivationPath ?? derivationPath ?? '',
252
);
253
final derivationInfoId = await di.save();
254
final walletInfo = newWi.WalletInfo(
254
- 0,
255
- id,
256
- name,
257
- type,
258
- isRecovery,
259
- restoreHeight,
260
- timestamp,
261
- dirPath,
262
- path,
263
- address,
264
- yatEid,
265
- yatLastUsedAddressRaw,
266
- showIntroCakePayCard,
267
- derivationInfoId,
268
- hardwareWalletType,
269
- parentAddress,
270
- hashedWalletIdentifier,
271
- isNonSeedWallet,
272
- 0,
273
- addressPageType,
274
- false,
275
- true,
276
- null
277
- );
255
+ 0,
256
+ id,
257
+ name,
258
+ type,
259
+ isRecovery,
260
+ restoreHeight,
261
+ timestamp,
262
+ dirPath,
263
+ path,
264
+ address,
265
+ yatEid,
266
+ yatLastUsedAddressRaw,
267
+ showIntroCakePayCard,
268
+ derivationInfoId,
269
+ hardwareWalletType,
270
+ parentAddress,
271
+ hashedWalletIdentifier,
272
+ isNonSeedWallet,
273
+ 0,
274
+ addressPageType,
275
+ false,
276
+ true,
277
+ null);
278
final wiId = await walletInfo.save();
279
for (final address in usedAddresses ?? <String>[]) {
280
await newWi.WalletInfoAddress.insert(wiId, newWi.WalletInfoAddressType.used, address);
@@ -289,8 +289,8 @@ class WalletInfo extends HiveObject {
289
for (final address in addressInfos![i] ?? <AddressInfo>[]) {
290
await newWi.WalletInfoAddressInfo.insert(
291
walletInfoId: wiId,
292
- mapKey: i,
293
- accountIndex: address.accountIndex??0,
292
+ mapKey: i,
293
+ accountIndex: address.accountIndex ?? 0,
294
address: address.address,
295
label: address.label,
296
);
@@ -304,8 +304,12 @@ class WalletInfo extends HiveObject {
304
final sw = Stopwatch()..start();
305
final list = box.values.toList();
306
for (final wi in list) {
307
- await wi.migrateToSqlite();
308
- await wi.delete();
307
+ try {
308
+ await wi.migrateToSqlite();
309
+ await wi.delete();
310
+ } catch (e) {
311
+ printV('Error migrating WalletInfo ${wi.id}: $e');
312
+ }
313
}
314
printV('Migrating WalletInfo to SQLite: end (${sw.elapsedMilliseconds}ms)');
315
}
integration_test/robots/transactions_page_robot.dart
+2
-2
@@ -385,8 +385,8 @@ class TransactionsPageRobot {
385
386
Future<void> _verifyTradeListItemDisplay(TradeListItem item) async {
387
final keyId = 'trade_list_item_${item.trade.id}_key';
388
- final from = item.trade.from?.toString() ?? item.trade.userCurrencyFrom.toString();
389
- final to = item.trade.to?.toString() ?? item.trade.userCurrencyTo.toString();
388
+ final from = item.trade.from?.toString() ?? '';
389
+ final to = item.trade.to?.toString() ?? '';
390
391
//* ==============Confirm it has the right key for this item ========
392
commonTestCases.hasValueKey(keyId);
lib/core/backup_service.dart
+2
@@ -19,6 +19,7 @@ import 'package:cake_wallet/entities/encrypt.dart';
19
import 'package:cake_wallet/entities/preferences_key.dart';
20
import 'package:cake_wallet/entities/secret_store_key.dart';
21
import 'package:cw_core/wallet_info.dart';
22
+import 'package:cake_wallet/exchange/trade_legacy.dart';
23
import 'package:cake_wallet/.secrets.g.dart' as secrets;
24
import 'package:cake_wallet/wallet_types.g.dart';
25
import 'package:cake_backup/backup.dart' as cake_backup;
@@ -110,6 +111,7 @@ class $BackupService {
111
112
Future<void> verifyWallets() async {
113
await performHiveMigration(); // for backups made before sqlite migration
114
+ await performTradeHiveMigration(_secureStorage);
115
correctWallets = (await WalletInfo.getAll()).where((info) => availableWalletTypes.contains(info.type)).toList();
116
117
if (correctWallets.isEmpty) {
lib/core/trade_monitor.dart
+3
-11
@@ -20,7 +20,6 @@ import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart';
20
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
21
import 'package:cake_wallet/exchange/provider/xoswap_exchange_provider.dart';
22
import 'package:cw_core/utils/print_verbose.dart';
23
-import 'package:hive/hive.dart';
23
import 'package:cake_wallet/store/app_store.dart';
24
import 'package:shared_preferences/shared_preferences.dart';
25
@@ -30,13 +29,11 @@ class TradeMonitor {
29
30
TradeMonitor({
31
required this.tradesStore,
33
- required this.trades,
32
required this.appStore,
33
required this.preferences,
34
});
35
36
final TradesStore tradesStore;
39
- final Box<Trade> trades;
37
final AppStore appStore;
38
final Map<String, Timer> _tradeTimers = {};
39
final SharedPreferences preferences;
@@ -54,7 +51,7 @@ class TradeMonitor {
51
case ExchangeProviderDescription.exolix:
52
return ExolixExchangeProvider();
53
case ExchangeProviderDescription.thorChain:
57
- return ThorChainExchangeProvider(tradesStore: trades);
54
+ return ThorChainExchangeProvider();
55
case ExchangeProviderDescription.swapTrade:
56
return SwapTradeExchangeProvider();
57
case ExchangeProviderDescription.letsExchange:
@@ -62,7 +59,7 @@ class TradeMonitor {
59
case ExchangeProviderDescription.stealthEx:
60
return StealthExExchangeProvider();
61
case ExchangeProviderDescription.chainflip:
65
- return ChainflipExchangeProvider(tradesStore: trades);
62
+ return ChainflipExchangeProvider();
63
case ExchangeProviderDescription.xoSwap:
64
return XOSwapExchangeProvider();
65
case ExchangeProviderDescription.swapsXyz:
@@ -187,12 +184,7 @@ class TradeMonitor {
184
185
try {
186
final updated = await provider.findTradeById(id: trade.id);
190
- trade
191
- ..stateRaw = updated.state.raw
192
- ..receiveAmount = updated.receiveAmount ?? trade.receiveAmount
193
- ..outputTransaction = updated.outputTransaction ?? trade.outputTransaction
194
- ..userCurrencyToRaw = updated.userCurrencyToRaw
195
- ..userCurrencyFromRaw = updated.userCurrencyFromRaw;
187
+ trade.mergeFindTradeByIdResult(updated);
188
printV('Trade ${trade.id} updated: ${trade.state}');
189
await trade.save();
190
lib/di.dart
+3
-12
@@ -329,7 +329,6 @@ var _isSetupFinished = false;
329
late Box<Node> _nodeSource;
330
late Box<Node> _powNodeSource;
331
late Box<Contact> _contactSource;
332
-late Box<Trade> _tradesSource;
332
late Box<Template> _templates;
333
late Box<ExchangeTemplate> _exchangeTemplates;
334
late Box<TransactionDescription> _transactionDescriptionBox;
@@ -341,7 +340,6 @@ Future<void> setup({
340
required Box<Node> nodeSource,
341
required Box<Node> powNodeSource,
342
required Box<Contact> contactSource,
344
- required Box<Trade> tradesSource,
343
required Box<Template> templates,
344
required Box<ExchangeTemplate> exchangeTemplates,
345
required Box<TransactionDescription> transactionDescriptionBox,
@@ -355,7 +353,6 @@ Future<void> setup({
353
_nodeSource = nodeSource;
354
_powNodeSource = powNodeSource;
355
_contactSource = contactSource;
358
- _tradesSource = tradesSource;
356
_templates = templates;
357
_exchangeTemplates = exchangeTemplates;
358
_transactionDescriptionBox = transactionDescriptionBox;
@@ -402,7 +399,7 @@ Future<void> setup({
399
nodeListStore: getIt.get<NodeListStore>(),
400
themeStore: getIt.get<ThemeStore>()));
401
getIt.registerSingleton<TradesStore>(
405
- TradesStore(tradesSource: _tradesSource, appStore: getIt.get<AppStore>()));
402
+ TradesStore(appStore: getIt.get<AppStore>()));
403
getIt.registerSingleton<OrdersStore>(
404
OrdersStore(ordersSource: _ordersSource, settingsStore: getIt.get<SettingsStore>()));
405
getIt.registerSingleton<BridgeTransfersStore>(BridgeTransfersStore());
@@ -569,7 +566,6 @@ Future<void> setup({
566
getIt.registerFactory(
567
() => ExchangeViewModel(
568
getIt.get<AppStore>(),
572
- _tradesSource,
569
getIt.get<ExchangeTemplateStore>(),
570
getIt.get<TradesStore>(),
571
getIt.get<SharedPreferences>(),
@@ -583,7 +579,6 @@ Future<void> setup({
579
getIt.registerSingleton(
580
TradeMonitor(
581
tradesStore: getIt.get<TradesStore>(),
586
- trades: _tradesSource,
582
appStore: getIt.get<AppStore>(),
583
preferences: getIt.get<SharedPreferences>(),
584
),
@@ -1258,7 +1253,6 @@ Future<void> setup({
1253
getIt.registerFactory(
1254
() => ExchangeTradeViewModel(
1255
wallet: getIt.get<AppStore>().wallet!,
1261
- trades: _tradesSource,
1256
tradesStore: getIt.get<TradesStore>(),
1257
sendViewModel: getIt.get<SendViewModel>(),
1258
feesViewModel: getIt.get<FeesViewModel>(),
@@ -1471,11 +1465,8 @@ Future<void> setup({
1465
getIt.registerFactoryParam<TransactionSuccessPage, String, void>(
1466
(content, _) => TransactionSuccessPage(content: content));
1467
1474
- getIt.registerFactoryParam<TradeDetailsViewModel, Trade, void>((trade, _) =>
1475
- TradeDetailsViewModel(
1476
- tradeForDetails: trade,
1477
- trades: _tradesSource,
1478
- appStore: getIt.get<AppStore>()));
1468
+ getIt.registerFactoryParam<TradeDetailsViewModel, Trade, void>(
1469
+ (trade, _) => TradeDetailsViewModel(tradeForDetails: trade, appStore: getIt.get<AppStore>()));
1470
1471
getIt.registerFactory(() => CakeFeaturesViewModel(getIt.get<CakePayService>()));
1472
lib/entities/default_settings_migration.dart
+1
-3
@@ -13,7 +13,6 @@ import 'package:cake_wallet/entities/haven_seed_store.dart';
13
import 'package:cake_wallet/entities/node_list.dart';
14
import 'package:cake_wallet/entities/preferences_key.dart';
15
import 'package:cake_wallet/entities/secret_store_key.dart';
16
-import 'package:cake_wallet/exchange/trade.dart';
16
import 'package:cake_wallet/monero/monero.dart';
17
import 'package:cake_wallet/wownero/wownero.dart';
18
import 'package:collection/collection.dart';
@@ -64,11 +63,10 @@ Future<void> defaultSettingsMigration(
63
required SecureStorage secureStorage,
64
required Box<Node> nodes,
65
required Box<Node> powNodes,
67
- required Box<Trade> tradeSource,
66
required Box<Contact> contactSource,
67
required Box<HavenSeedStore> havenSeedStore}) async {
68
if (Platform.isIOS) {
71
- await ios_migrate_v1(tradeSource, contactSource);
69
+ await ios_migrate_v1(contactSource);
70
}
71
72
// check current nodes for nullability regardless of the version
lib/entities/fs_migration.dart
+12
-9
@@ -29,7 +29,7 @@ Future<void> migrate_android_v1() async {
29
await android_migrate_wallets(appDocDir: appDocDir);
30
}
31
32
-Future<void> ios_migrate_v1(Box<Trade> tradeSource, Box<Contact> contactSource) async {
32
+Future<void> ios_migrate_v1(Box<Contact> contactSource) async {
33
final prefs = await SharedPreferences.getInstance();
34
35
if (prefs.getBool('ios_migration_v1_completed') ?? false) {
@@ -40,7 +40,7 @@ Future<void> ios_migrate_v1(Box<Trade> tradeSource, Box<Contact> contactSource)
40
await ios_migrate_pin();
41
await ios_migrate_wallet_passwords();
42
await ios_migrate_wallet_info();
43
- await ios_migrate_trades_list(tradeSource);
43
+ await ios_migrate_trades_list();
44
await ios_migrate_address_book(contactSource);
45
46
await prefs.setBool('ios_migration_v1_completed', true);
@@ -343,7 +343,7 @@ Future<void> ios_migrate_wallet_info() async {
343
}
344
}
345
346
-Future<void> ios_migrate_trades_list(Box<Trade> tradeSource) async {
346
+Future<void> ios_migrate_trades_list() async {
347
final prefs = await SharedPreferences.getInstance();
348
349
if (prefs.getBool('ios_migration_trade_list_completed') ?? false) {
@@ -366,7 +366,8 @@ Future<void> ios_migrate_trades_list(Box<Trade> tradeSource) async {
366
final key = masterPassword!.replaceAll('-', '');
367
final decoded = await ios_legacy_helper.decrypt(content, key: key, salt: secrets.salt);
368
final decodedJson = json.decode(decoded) as List<dynamic>;
369
- final trades = decodedJson.map((dynamic el) {
369
+
370
+ for (final dynamic el in decodedJson) {
371
final elAsMap = el as Map<String, dynamic>;
372
final providerAsString = elAsMap['provider'] as String;
373
final fromAsString = elAsMap['from'] as String;
@@ -393,17 +394,19 @@ Future<void> ios_migrate_trades_list(Box<Trade> tradeSource) async {
394
break;
395
}
396
396
- return Trade(
397
+ if (provider == null) continue;
398
+
399
+ await Trade(
400
id: tradeId,
398
- provider: provider!,
401
+ provider: provider,
402
from: from,
403
to: to,
404
createdAt: date,
405
amount: '',
406
receiveAmount: '',
404
- );
405
- });
406
- await tradeSource.addAll(trades);
407
+ ).save();
408
+ }
409
+
410
await prefs.setBool('ios_migration_trade_list_completed', true);
411
} catch (e) {
412
printV(e.toString());
lib/exchange/provider/chainflip_exchange_provider.dart
+24
-50
@@ -8,15 +8,13 @@ import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
8
import 'package:cake_wallet/exchange/trade.dart';
9
import 'package:cake_wallet/exchange/trade_request.dart';
10
import 'package:cake_wallet/exchange/trade_state.dart';
11
-import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
11
import 'package:cw_core/crypto_currency.dart';
12
import 'package:cw_core/utils/print_verbose.dart';
14
-import 'package:hive/hive.dart';
13
import 'package:cw_core/utils/proxy_wrapper.dart';
14
import 'package:cake_wallet/utils/exchange_provider_logger.dart';
15
16
class ChainflipExchangeProvider extends ExchangeProvider {
19
- ChainflipExchangeProvider({required this.tradesStore});
17
+ ChainflipExchangeProvider();
18
19
static final List<CryptoCurrency> _supported = [
20
CryptoCurrency.btc,
@@ -41,8 +39,6 @@ class ChainflipExchangeProvider extends ExchangeProvider {
39
static const _affiliateBps = secrets.chainflipAffiliateFee;
40
static const _affiliateKey = secrets.chainflipApiKey;
41
44
- final Box<Trade> tradesStore;
45
-
42
@override
43
String get title => 'Chainflip';
44
@@ -229,19 +225,18 @@ class ChainflipExchangeProvider extends ExchangeProvider {
225
);
226
227
return Trade(
232
- id: id,
233
- from: request.fromCurrency,
234
- to: request.toCurrency,
235
- provider: description,
236
- inputAddress: swapResponse['address'].toString(),
237
- createdAt: DateTime.now(),
238
- amount: request.fromAmount,
239
- receiveAmount: request.toAmount,
240
- state: TradeState.waiting,
241
- payoutAddress: request.toAddress,
242
- userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
243
- userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
244
- isSendAll: isSendAll);
228
+ id: id,
229
+ from: request.fromCurrency,
230
+ to: request.toCurrency,
231
+ provider: description,
232
+ inputAddress: swapResponse['address'].toString(),
233
+ createdAt: DateTime.now(),
234
+ amount: request.fromAmount,
235
+ receiveAmount: request.toAmount,
236
+ state: TradeState.waiting,
237
+ payoutAddress: request.toAddress,
238
+ isSendAll: isSendAll,
239
+ );
240
} catch (e, s) {
241
ExchangeProviderLogger.logError(
242
provider: description,
@@ -296,29 +291,19 @@ class ChainflipExchangeProvider extends ExchangeProvider {
291
final to = status['destinationAsset'].toString();
292
293
final newTrade = Trade(
299
- id: id,
300
- from: _toCurrency(status['sourceAsset'].toString()),
301
- to: _toCurrency(status['destinationAsset'].toString()),
302
- provider: description,
303
- amount: depositAmount,
304
- receiveAmount: amount,
305
- state: currentState,
306
- payoutAddress: status['destinationAddress'].toString(),
307
- outputTransaction: status['swapEgress']?['transactionReference']?.toString(),
308
- isRefund: isRefund,
309
- userCurrencyFromRaw: '${from.toUpperCase()}' + '_',
310
- userCurrencyToRaw: '${to.toUpperCase()}' + '_',
294
+ id: id,
295
+ from: _toCurrency(from),
296
+ to: _toCurrency(to),
297
+ provider: description,
298
+ amount: depositAmount,
299
+ receiveAmount: amount,
300
+ state: currentState,
301
+ payoutAddress: status['destinationAddress'].toString(),
302
+ outputTransaction:
303
+ status['swapEgress']?['transactionReference']?.toString(),
304
+ isRefund: isRefund,
305
);
306
313
- // Find trade and update receiveAmount with the real value received
314
- final storedTrade = _getStoredTrade(id);
315
-
316
- if (storedTrade != null) {
317
- storedTrade.$2.receiveAmount = newTrade.receiveAmount;
318
- storedTrade.$2.outputTransaction = newTrade.outputTransaction;
319
- tradesStore.put(storedTrade.$1, storedTrade.$2);
320
- }
321
-
307
return newTrade;
308
} catch (e) {
309
printV(e.toString());
@@ -368,17 +353,6 @@ class ChainflipExchangeProvider extends ExchangeProvider {
353
return currency;
354
}
355
371
- (dynamic, Trade)? _getStoredTrade(String id) {
372
- for (var i = tradesStore.length -1; i >= 0; i--) {
373
- Trade? t = tradesStore.getAt(i);
374
-
375
- if (t != null && t.id == id)
376
- return (i, t);
377
- }
378
-
379
- return null;
380
- }
381
-
356
String _amountToNative(double amount, CryptoCurrency currency) =>
357
(amount * pow(10, currency.decimals)).toInt().toString();
358
lib/exchange/provider/changenow_exchange_provider.dart
-6
@@ -9,7 +9,6 @@ import 'package:cake_wallet/exchange/trade.dart';
9
import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
10
import 'package:cake_wallet/exchange/trade_request.dart';
11
import 'package:cake_wallet/exchange/trade_state.dart';
12
-import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
12
import 'package:cake_wallet/store/settings_store.dart';
13
import 'package:cake_wallet/utils/distribution_info.dart';
14
import 'package:cw_core/utils/proxy_wrapper.dart';
@@ -248,8 +247,6 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
247
receiveAmount: toAmount ?? request.toAmount,
248
state: TradeState.created,
249
payoutAddress: payoutAddress,
251
- userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
252
- userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
250
isSendAll: isSendAll,
251
);
252
}
@@ -315,9 +312,6 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
312
expiredAt: expiredAt,
313
outputTransaction: outputTransaction,
314
payoutAddress: payoutAddress,
318
- userCurrencyFromRaw:
319
- '${fromCurrency.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
320
- userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
315
);
316
}
317
lib/exchange/provider/exchange_provider.dart
+6
-8
@@ -1,4 +1,3 @@
1
-import 'package:cake_wallet/exchange/exchange_pair.dart';
1
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
2
import 'package:cake_wallet/exchange/limits.dart';
3
import 'package:cake_wallet/exchange/trade.dart';
@@ -31,13 +30,12 @@ abstract class ExchangeProvider {
30
31
Future<Trade> findTradeById({required String id});
32
34
- Future<double> fetchRate({
35
- required CryptoCurrency from,
36
- required CryptoCurrency to,
37
- required double amount,
38
- required bool isFixedRateMode,
39
- required bool isReceiveAmount
40
- });
33
+ Future<double> fetchRate(
34
+ {required CryptoCurrency from,
35
+ required CryptoCurrency to,
36
+ required double amount,
37
+ required bool isFixedRateMode,
38
+ required bool isReceiveAmount});
39
40
Future<bool> checkIsAvailable();
41
}
lib/exchange/provider/exolix_exchange_provider.dart
+10
-14
@@ -314,8 +314,6 @@ class ExolixExchangeProvider extends ExchangeProvider {
314
receiveAmount: receiveAmount ?? request.toAmount,
315
state: TradeState.created,
316
payoutAddress: payoutAddress,
317
- userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
318
- userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
317
isSendAll: isSendAll,
318
);
319
}
@@ -363,18 +361,16 @@ class ExolixExchangeProvider extends ExchangeProvider {
361
final payoutAddress = responseJSON['withdrawalAddress'] as String;
362
363
return Trade(
366
- id: id,
367
- from: from,
368
- to: to,
369
- provider: description,
370
- inputAddress: inputAddress,
371
- amount: amount,
372
- state: TradeState.deserialize(raw: _prepareStatus(status)),
373
- extraId: extraId,
374
- outputTransaction: outputTransaction,
375
- payoutAddress: payoutAddress,
376
- userCurrencyFromRaw: '${coinFrom.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
377
- userCurrencyToRaw: '${coinTo.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
364
+ id: id,
365
+ from: from,
366
+ to: to,
367
+ provider: description,
368
+ inputAddress: inputAddress,
369
+ amount: amount,
370
+ state: TradeState.deserialize(raw: _prepareStatus(status)),
371
+ extraId: extraId,
372
+ outputTransaction: outputTransaction,
373
+ payoutAddress: payoutAddress,
374
);
375
}
376
lib/exchange/provider/jupiter_exchange_provider.dart
-2
@@ -367,8 +367,6 @@ class JupiterExchangeProvider extends ExchangeProvider {
367
receiveAmount: receiveAmount,
368
payoutAddress: request.toAddress,
369
isSendAll: isSendAll,
370
- userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? 'SOL'}',
371
- userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? 'SOL'}',
370
routerData: transaction,
371
routerValue: requestId,
372
fee: totalFeeInSol,
lib/exchange/provider/letsexchange_exchange_provider.dart
+9
-25
@@ -9,7 +9,6 @@ import 'package:cake_wallet/exchange/trade.dart';
9
import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
10
import 'package:cake_wallet/exchange/trade_request.dart';
11
import 'package:cake_wallet/exchange/trade_state.dart';
12
-import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
12
import 'package:cw_core/utils/proxy_wrapper.dart';
13
import 'package:cw_core/crypto_currency.dart';
14
import 'package:cw_core/utils/print_verbose.dart';
@@ -76,13 +75,12 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
75
}
76
77
@override
79
- Future<double> fetchRate({
80
- required CryptoCurrency from,
81
- required CryptoCurrency to,
82
- required double amount,
83
- required bool isFixedRateMode,
84
- required bool isReceiveAmount
85
- }) async {
78
+ Future<double> fetchRate(
79
+ {required CryptoCurrency from,
80
+ required CryptoCurrency to,
81
+ required double amount,
82
+ required bool isFixedRateMode,
83
+ required bool isReceiveAmount}) async {
84
final networkFrom = _getNetworkType(from);
85
final networkTo = _getNetworkType(to);
86
try {
@@ -191,14 +189,13 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
189
'Authorization': apiKey
190
};
191
194
- final uri = Uri.https(_baseUrl,
195
- isFixedRateMode ? _createTransactionRevertPath : _createTransactionPath);
192
+ final uri = Uri.https(
193
+ _baseUrl, isFixedRateMode ? _createTransactionRevertPath : _createTransactionPath);
194
final response = await ProxyWrapper().post(
195
clearnetUri: uri,
196
headers: headers,
197
body: json.encode(tradeParams),
198
);
201
-
199
200
if (response.statusCode != 200) {
201
ExchangeProviderLogger.logError(
@@ -304,8 +301,6 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
301
createdAt: createdAt,
302
expiredAt: expiredAt,
303
extraId: extraId,
307
- userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
308
- userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
304
isSendAll: isSendAll,
305
);
306
} catch (e, s) {
@@ -342,7 +337,6 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
337
338
final url = Uri.https(_baseUrl, '$_getTransactionPath/$id');
339
final response = await ProxyWrapper().get(clearnetUri: url, headers: headers);
345
-
340
341
if (response.statusCode != 200) {
342
throw Exception('LetsExchange fetch trade failed: ${response.body}');
@@ -363,7 +357,6 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
357
final toTag = toCurrency == normalizedToNetwork ? null : normalizedToNetwork;
358
final to = CryptoCurrency.safeParseCurrencyFromString(toCurrency, tag: toTag);
359
366
-
360
final payoutAddress = responseJSON['withdrawal'] as String;
361
final depositAddress = responseJSON['deposit'] as String;
362
final refundAddress = responseJSON['return'] as String;
@@ -371,15 +364,8 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
364
final receiveAmount = responseJSON['withdrawal_amount'] as String;
365
final status = responseJSON['status'] as String;
366
374
- // We ignore the created_at from response and use DateTime.now() instead
375
- final createdAtString = responseJSON['created_at'] as String;
376
- final expiredAtTimestamp = responseJSON['expired_at'] as int;
377
-
367
final extraId = responseJSON['deposit_extra_id'] as String?;
368
380
- final createdAt = DateTime.parse(createdAtString).toLocal();
381
- final expiredAt = DateTime.fromMillisecondsSinceEpoch(expiredAtTimestamp * 1000).toLocal();
382
-
369
return Trade(
370
id: id,
371
from: from,
@@ -393,8 +379,6 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
379
state: TradeState.deserialize(raw: status),
380
isRefund: status == 'refund',
381
extraId: extraId,
396
- userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
397
- userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
382
);
383
}
384
@@ -412,7 +396,7 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
396
headers: headers,
397
body: json.encode(params),
398
);
415
-
399
+
400
if (response.statusCode != 200) {
401
throw Exception('LetsExchange fetch info failed: ${response.body}');
402
}
lib/exchange/provider/near_Intents_exchange_provider.dart
-7
@@ -9,7 +9,6 @@ import 'package:cake_wallet/exchange/trade.dart';
9
import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
10
import 'package:cake_wallet/exchange/trade_request.dart';
11
import 'package:cake_wallet/exchange/trade_state.dart';
12
-import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
12
import 'package:cw_core/amount_converter.dart';
13
import 'package:cw_core/utils/proxy_wrapper.dart';
14
import 'package:cw_core/crypto_currency.dart';
@@ -286,10 +285,6 @@ class NearIntentsExchangeProvider extends ExchangeProvider {
285
receiveAmount: quoteObj['amountOutFormatted']?.toString(),
286
memo: depositMemo,
287
isSendAll: isSendAll,
289
- userCurrencyFromRaw:
290
- '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
291
- userCurrencyToRaw:
292
- '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
288
);
289
290
ExchangeProviderLogger.logSuccess(
@@ -415,8 +410,6 @@ class NearIntentsExchangeProvider extends ExchangeProvider {
410
txId: originTxHash,
411
extraId: depositMemo,
412
isRefund: statusRaw == 'REFUNDED',
418
- userCurrencyFromRaw: '${from?.$1.toUpperCase()}' + '_' + '${from?.$2?.toUpperCase() ?? ''}',
419
- userCurrencyToRaw: '${to?.$1.toUpperCase()}' + '_' + '${to?.$2?.toUpperCase() ?? ''}',
413
);
414
}
415
lib/exchange/provider/sideshift_exchange_provider.dart
+18
-15
@@ -9,7 +9,6 @@ import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
9
import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
10
import 'package:cake_wallet/exchange/trade_request.dart';
11
import 'package:cake_wallet/exchange/trade_state.dart';
12
-import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
12
import 'package:cw_core/utils/proxy_wrapper.dart';
13
import 'package:cw_core/crypto_currency.dart';
14
import 'package:cw_core/utils/print_verbose.dart';
@@ -337,8 +336,6 @@ class SideShiftExchangeProvider extends ExchangeProvider {
336
createdAt: DateTime.now(),
337
isSendAll: isSendAll,
338
extraId: depositMemo,
340
- userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
341
- userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
339
);
340
}
341
@@ -377,19 +374,25 @@ class SideShiftExchangeProvider extends ExchangeProvider {
374
final expiredAt = isVariable ? null : DateTime.tryParse(expiredAtRaw)?.toLocal();
375
final depositMemo = responseJSON['depositMemo'] as String?;
376
377
+ final fromParsed = CryptoCurrency.safeParseCurrencyFromString(
378
+ fromCurrency,
379
+ tag: fromNetwork,
380
+ );
381
+ final toParsed = CryptoCurrency.safeParseCurrencyFromString(
382
+ toCurrency,
383
+ tag: toNetwork,
384
+ );
385
return Trade(
381
- id: id,
382
- from: CryptoCurrency.safeParseCurrencyFromString(fromCurrency),
383
- to: CryptoCurrency.safeParseCurrencyFromString(toCurrency),
384
- provider: description,
385
- inputAddress: inputAddress,
386
- amount: expectedSendAmount ?? '',
387
- state: TradeState.deserialize(raw: status ?? 'created'),
388
- expiredAt: expiredAt,
389
- payoutAddress: settleAddress,
390
- extraId: depositMemo,
391
- userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_' + _normalizeNetworkType(fromNetwork ?? ''),
392
- userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + _normalizeNetworkType(toNetwork ?? ''),
386
+ id: id,
387
+ from: fromParsed,
388
+ to: toParsed,
389
+ provider: description,
390
+ inputAddress: inputAddress,
391
+ amount: expectedSendAmount ?? '',
392
+ state: TradeState.deserialize(raw: status ?? 'created'),
393
+ expiredAt: expiredAt,
394
+ payoutAddress: settleAddress,
395
+ extraId: depositMemo,
396
);
397
}
398
lib/exchange/provider/simpleswap_exchange_provider.dart
+5
-7
@@ -9,7 +9,6 @@ import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
9
import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
10
import 'package:cake_wallet/exchange/trade_request.dart';
11
import 'package:cake_wallet/exchange/trade_state.dart';
12
-import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
12
import 'package:cake_wallet/utils/device_info.dart';
13
import 'package:cw_core/utils/proxy_wrapper.dart';
14
import 'package:cw_core/crypto_currency.dart';
@@ -290,8 +289,6 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
289
payoutAddress: payoutAddress,
290
createdAt: DateTime.now(),
291
isSendAll: isSendAll,
293
- userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
294
- userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
292
);
293
}
294
@@ -326,18 +323,19 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
323
final status = responseJSON['status'] as String;
324
final payoutAddress = responseJSON['address_to'] as String;
325
326
+ final fromParsed =
327
+ CryptoCurrency.safeParseCurrencyFromString(fromCurrency);
328
+ final toParsed = CryptoCurrency.safeParseCurrencyFromString(toCurrency);
329
return Trade(
330
id: id,
331
- from: CryptoCurrency.safeParseCurrencyFromString(fromCurrency),
332
- to: CryptoCurrency.safeParseCurrencyFromString(toCurrency),
331
+ from: fromParsed,
332
+ to: toParsed,
333
extraId: extraId,
334
provider: description,
335
inputAddress: inputAddress,
336
amount: expectedSendAmount,
337
state: TradeState.deserialize(raw: status),
338
payoutAddress: payoutAddress,
339
- userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_',
340
- userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_',
339
);
340
}
341
lib/exchange/provider/stealth_ex_exchange_provider.dart
-6
@@ -9,7 +9,6 @@ import 'package:cake_wallet/exchange/trade.dart';
9
import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
10
import 'package:cake_wallet/exchange/trade_request.dart';
11
import 'package:cake_wallet/exchange/trade_state.dart';
12
-import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
12
import 'package:cw_core/utils/proxy_wrapper.dart';
13
import 'package:cw_core/crypto_currency.dart';
14
import 'package:cake_wallet/utils/exchange_provider_logger.dart';
@@ -299,8 +298,6 @@ class StealthExExchangeProvider extends ExchangeProvider {
298
createdAt: createdAt,
299
expiredAt: expiredAt,
300
extraId: extraId,
302
- userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
303
- userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
301
isSendAll: isSendAll,
302
);
303
} catch (e, s) {
@@ -377,9 +374,6 @@ class StealthExExchangeProvider extends ExchangeProvider {
374
createdAt: createdAt,
375
isRefund: status == 'refunded',
376
extraId: extraId,
380
- userCurrencyFromRaw:
381
- '${fromCurrency.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
382
- userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
377
);
378
}
379
lib/exchange/provider/swapsxyz_exchange_provider.dart
-6
@@ -407,10 +407,6 @@ class SwapsXyzExchangeProvider extends ExchangeProvider {
407
requiresTokenApproval: requiresTokenApproval,
408
routerData: routerData,
409
routerValue: txValue,
410
- userCurrencyFromRaw:
411
- '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
412
- userCurrencyToRaw:
413
- '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
410
);
411
412
return trade;
@@ -554,8 +550,6 @@ class SwapsXyzExchangeProvider extends ExchangeProvider {
550
state: state,
551
createdAt: createdAt,
552
refundAddress: refundAddress,
557
- userCurrencyFromRaw: '${fromSymbol.toUpperCase()}' + '_',
558
- userCurrencyToRaw: '${toSymbol.toUpperCase()}' + '_',
553
);
554
}
555
lib/exchange/provider/swaptrade_exchange_provider.dart
-4
@@ -297,8 +297,6 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
297
state: TradeState.created,
298
payoutAddress: request.toAddress,
299
isSendAll: isSendAll,
300
- userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
301
- userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
300
);
301
} catch (e, s) {
302
ExchangeProviderLogger.logError(
@@ -374,8 +372,6 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
372
receiveAmount: expectedReceiveAmount,
373
memo: memo,
374
createdAt: DateTime.tryParse(createdAt ?? ''),
377
- userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_',
378
- userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_',
375
);
376
} catch (e) {
377
printV("error getting trade: ${e.toString()}");
lib/exchange/provider/thorchain_exchange.provider.dart
+1
-9
@@ -6,15 +6,13 @@ import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
6
import 'package:cake_wallet/exchange/trade.dart';
7
import 'package:cake_wallet/exchange/trade_request.dart';
8
import 'package:cake_wallet/exchange/trade_state.dart';
9
-import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
9
import 'package:cw_core/utils/proxy_wrapper.dart';
10
import 'package:cw_core/crypto_currency.dart';
11
import 'package:cw_core/utils/print_verbose.dart';
13
-import 'package:hive/hive.dart';
12
import 'package:cake_wallet/utils/exchange_provider_logger.dart';
13
14
class ThorChainExchangeProvider extends ExchangeProvider {
17
- ThorChainExchangeProvider({required this.tradesStore});
15
+ ThorChainExchangeProvider();
16
17
static final isRefundAddressSupported = [CryptoCurrency.eth];
18
@@ -26,8 +24,6 @@ class ThorChainExchangeProvider extends ExchangeProvider {
24
static const _affiliateBps = '175';
25
static const _nameLookUpPath = 'v2/thorname/lookup/';
26
29
- final Box<Trade> tradesStore;
30
-
27
@override
28
String get title => 'THORChain';
29
@@ -195,8 +191,6 @@ class ThorChainExchangeProvider extends ExchangeProvider {
191
payoutAddress: request.toAddress,
192
memo: memo,
193
isSendAll: isSendAll,
198
- userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
199
- userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
194
);
195
}
196
@@ -254,8 +248,6 @@ class ThorChainExchangeProvider extends ExchangeProvider {
248
state: currentState,
249
memo: memo,
250
isRefund: isRefund,
257
- userCurrencyFromRaw: '${tx['chain'] as String? ?? ''}' + '_',
258
- userCurrencyToRaw: '$toAsset' + '_',
251
);
252
}
253
lib/exchange/provider/trocador_exchange_provider.dart
-5
@@ -392,8 +392,6 @@ class TrocadorExchangeProvider extends ExchangeProvider {
392
payoutAddress: payoutAddress,
393
isSendAll: isSendAll,
394
extraId: addressProviderMemo,
395
- userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
396
- userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
395
);
396
}
397
@@ -456,9 +454,6 @@ class TrocadorExchangeProvider extends ExchangeProvider {
454
providerId: providerId,
455
providerName: providerName,
456
extraId: addressProviderMemo,
459
- userCurrencyFromRaw:
460
- '${fromCurrency.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
461
- userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
457
);
458
});
459
}
lib/exchange/provider/xoswap_exchange_provider.dart
-12
@@ -423,8 +423,6 @@ class XOSwapExchangeProvider extends ExchangeProvider {
423
receiveAmount: receiveAmount.toString(),
424
payoutAddress: payoutAddress,
425
extraId: extraId,
426
- userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
427
- userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
426
isSendAll: isSendAll,
427
);
428
} catch (e, s) {
@@ -529,14 +527,6 @@ class XOSwapExchangeProvider extends ExchangeProvider {
527
final createdAt = DateTime.parse(createdAtString).toLocal();
528
final extraId = responseJSON['payInAddressTag'] as String?;
529
532
- final userCurrencyFromRaw = fromCurrency != null
533
- ? '${fromCurrency.title}' + '_' + '${fromCurrency.tag ?? ''}'
534
- : '${fromAssetBase}' + '_' + '${fromAssetTag ?? ''}';
535
-
536
- final userCurrencyToRaw = toCurrency != null
537
- ? '${toCurrency.title}' + '_' + '${toCurrency.tag ?? ''}'
538
- : '${toAssetBase}' + '_' + '${toAssetTag ?? ''}';
539
-
530
return Trade(
531
id: orderId,
532
from: fromCurrency,
@@ -550,8 +540,6 @@ class XOSwapExchangeProvider extends ExchangeProvider {
540
receiveAmount: receiveAmount,
541
payoutAddress: payoutAddress,
542
extraId: extraId,
553
- userCurrencyFromRaw: userCurrencyFromRaw,
554
- userCurrencyToRaw: userCurrencyToRaw,
543
);
544
} catch (e) {
545
printV(e.toString());
lib/exchange/trade.dart
+199
-291
@@ -1,19 +1,22 @@
1
+import 'dart:async';
2
+
3
import 'package:cake_wallet/evm/evm.dart';
4
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
5
import 'package:cake_wallet/exchange/trade_state.dart';
6
import 'package:cw_core/crypto_currency.dart';
7
+import 'package:cw_core/db/sqlite.dart';
8
import 'package:cw_core/format_amount.dart';
9
import 'package:cw_core/generate_name.dart';
7
-import 'package:cw_core/hive_type_ids.dart';
8
-import 'package:hive/hive.dart';
10
+import 'package:sqflite/sqflite.dart';
11
10
-class Trade extends HiveObject {
12
+class Trade {
13
Trade({
14
+ this.internalId = 0,
15
required this.id,
16
required this.amount,
17
ExchangeProviderDescription? provider,
15
- CryptoCurrency? from,
16
- CryptoCurrency? to,
18
+ this.from,
19
+ this.to,
20
TradeState? state,
21
this.receiveAmount,
22
this.createdAt,
@@ -34,8 +37,6 @@ class Trade extends HiveObject {
37
this.isRefund,
38
this.isSendAll,
39
this.router,
37
- this.userCurrencyFromRaw,
38
- this.userCurrencyToRaw,
40
// The following fields are used for SwapXyz trades only
41
this.needToRegisterInSwapXyz,
42
this.sourceTokenAddress,
@@ -48,364 +49,271 @@ class Trade extends HiveObject {
49
this.chainId,
50
}) {
51
if (provider != null) providerRaw = provider.raw;
51
-
52
- fromRaw = from?.raw ?? -1;
53
- toRaw = to?.raw ?? -1;
54
-
52
if (state != null) stateRaw = state.raw;
53
}
54
58
- static const typeId = TRADE_TYPE_ID;
55
+ static const tableName = 'Trade';
56
+ static const selfIdColumn = 'tradeId';
57
+
58
static const boxName = 'Trades';
59
static const boxKey = 'tradesBoxKey';
60
62
- @HiveField(0, defaultValue: '')
61
+ static final StreamController<void> onChanged = StreamController<void>.broadcast();
62
+
63
+ int internalId;
64
+
65
String id;
66
65
- @HiveField(1, defaultValue: 0)
66
- late int providerRaw;
67
+ int providerRaw = 0;
68
69
ExchangeProviderDescription get provider =>
70
ExchangeProviderDescription.deserialize(raw: providerRaw);
71
71
- @HiveField(2, defaultValue: -1)
72
- int fromRaw = -1;
73
-
74
- CryptoCurrency? get from => CryptoCurrency.safeDeserialize(raw: fromRaw);
75
-
76
- @HiveField(3, defaultValue: -1)
77
- int toRaw = -1;
72
+ CryptoCurrency? from;
73
+ CryptoCurrency? to;
74
79
- CryptoCurrency? get to => CryptoCurrency.safeDeserialize(raw: toRaw);
80
-
81
- @HiveField(4, defaultValue: '')
82
- late String stateRaw;
75
+ String stateRaw = '';
76
77
TradeState get state => TradeState.deserialize(raw: stateRaw);
78
86
- @HiveField(5)
79
DateTime? createdAt;
88
-
89
- @HiveField(6)
80
DateTime? expiredAt;
91
-
92
- @HiveField(7, defaultValue: '')
81
String amount;
94
-
95
- @HiveField(8)
82
+ String? receiveAmount;
83
String? inputAddress;
97
-
98
- @HiveField(9)
84
String? extraId;
100
-
101
- @HiveField(10)
85
String? outputTransaction;
103
-
104
- @HiveField(11)
86
String? refundAddress;
106
-
107
- @HiveField(12)
87
String? walletId;
109
-
110
- @HiveField(13)
88
String? payoutAddress;
112
-
113
- @HiveField(14)
89
String? password;
115
-
116
- @HiveField(15)
90
String? providerId;
118
-
119
- @HiveField(16)
91
String? providerName;
121
-
122
- @HiveField(17)
92
String? fromWalletAddress;
124
-
125
- @HiveField(18)
93
String? memo;
127
-
128
- @HiveField(19)
94
String? txId;
130
-
131
- @HiveField(20)
95
bool? isRefund;
133
-
134
- @HiveField(21)
96
bool? isSendAll;
136
-
137
- /// Must be set on createTrade;
138
-
139
- @HiveField(22)
97
String? router;
98
142
- @HiveField(23, defaultValue: '')
143
- String? receiveAmount;
144
-
145
- @HiveField(24, defaultValue: '')
146
- String? userCurrencyFromRaw;
147
-
148
- @HiveField(25, defaultValue: '')
149
- String? userCurrencyToRaw;
150
-
99
// The following fields are used for SwapXyz trades only
152
- @HiveField(26)
100
bool? needToRegisterInSwapXyz;
154
-
155
- @HiveField(27)
101
String? sourceTokenAddress;
157
-
158
- @HiveField(28)
102
int? sourceTokenDecimals;
160
-
161
- @HiveField(29)
103
String? routerData;
163
-
164
- @HiveField(30)
104
String? routerValue;
166
-
167
- @HiveField(31)
105
int? routerChainId;
169
-
170
- @HiveField(32)
106
String? sourceTokenAmountRaw;
172
-
173
- @HiveField(33, defaultValue: false)
107
bool? requiresTokenApproval;
108
176
- @HiveField(34)
109
int? chainId;
178
-
179
- @HiveField(35)
110
double? fee;
111
182
- CryptoCurrency? get userCurrencyFrom {
183
- if (userCurrencyFromRaw == null || userCurrencyFromRaw!.isEmpty) {
184
- return null;
185
- }
186
- final underscoreIndex = userCurrencyFromRaw!.indexOf('_');
187
- final title = userCurrencyFromRaw!.substring(0, underscoreIndex);
188
- String tag = userCurrencyFromRaw!.substring(underscoreIndex + 1);
189
-
190
- if (tag.contains('ARB')) tag = 'ARB';
112
+ String get chainName {
113
+ if (chainId == null) return '';
114
192
- return CryptoCurrency(
193
- title: title,
194
- tag: tag.isNotEmpty ? tag : null,
195
- name: '',
196
- raw: -1,
197
- decimals: 1,
198
- );
115
+ return evm!.getChainNameByChainId(chainId!).capitalized();
116
}
117
201
- CryptoCurrency? get userCurrencyTo {
202
- if (userCurrencyToRaw == null || userCurrencyToRaw!.isEmpty) {
203
- return null;
204
- }
205
- final underscoreIndex = userCurrencyToRaw!.indexOf('_');
206
- final title = userCurrencyToRaw!.substring(0, underscoreIndex);
207
- final tag = userCurrencyToRaw!.substring(underscoreIndex + 1);
118
+ // ── SQLite CRUD ──────────────────────────────────────
119
209
- return CryptoCurrency(
210
- title: title,
211
- tag: tag.isNotEmpty ? tag : null,
212
- name: '',
213
- raw: -1,
214
- decimals: 1,
120
+ Future<int> save() async {
121
+ final json = toSqliteMap();
122
+ if (json[selfIdColumn] == 0) {
123
+ json[selfIdColumn] = null;
124
+ }
125
+ internalId = await db!.insert(
126
+ tableName,
127
+ json,
128
+ conflictAlgorithm: ConflictAlgorithm.replace,
129
);
130
+ onChanged.add(null);
131
+ return internalId;
132
}
133
218
- String get chainName {
219
- if (chainId == null) return '';
134
+ static Future<List<Trade>> getAll({String? orderBy}) async {
135
+ final list = await db!.query(
136
+ tableName,
137
+ orderBy: orderBy ?? 'createdAt DESC',
138
+ );
139
+ return List.generate(
140
+ list.length,
141
+ (i) => Trade.fromSqliteRow(list[i]),
142
+ );
143
+ }
144
221
- return evm!.getChainNameByChainId(chainId!).capitalized();
145
+ static Future<Trade?> getByTradeId(String id) async {
146
+ final list = await db!.query(
147
+ tableName,
148
+ where: 'id = ?',
149
+ whereArgs: [id],
150
+ limit: 1,
151
+ );
152
+ if (list.isEmpty) return null;
153
+ return Trade.fromSqliteRow(list.first);
154
}
155
224
- static Trade fromMap(Map<String, Object?> map) {
225
- return Trade(
226
- id: map['id'] as String,
227
- provider: ExchangeProviderDescription.deserialize(raw: map['provider'] as int),
228
- from: CryptoCurrency.deserialize(raw: map['input'] as int),
229
- to: CryptoCurrency.deserialize(raw: map['output'] as int),
230
- createdAt:
231
- map['date'] != null ? DateTime.fromMillisecondsSinceEpoch(map['date'] as int) : null,
232
- amount: map['amount'] as String,
233
- receiveAmount: map['receive_amount'] as String?,
234
- walletId: map['wallet_id'] as String,
235
- fromWalletAddress: map['from_wallet_address'] as String?,
236
- memo: map['memo'] as String?,
237
- txId: map['tx_id'] as String?,
238
- isRefund: map['isRefund'] as bool?,
239
- isSendAll: map['isSendAll'] as bool?,
240
- router: map['router'] as String?,
241
- extraId: map['extra_id'] as String?,
242
- chainId: map['chain_id'] as int?,
156
+ static Future<int> deleteTrade(Trade trade) async {
157
+ final rows = await db!.delete(
158
+ tableName,
159
+ where: '$selfIdColumn = ?',
160
+ whereArgs: [trade.internalId],
161
);
162
+ onChanged.add(null);
163
+ return rows;
164
+ }
165
+
166
+ // ── SQLite serialization ─────────────────────────────
167
+ void mergeFindTradeByIdResult(Trade updated) {
168
+ if (updated.stateRaw.isNotEmpty) stateRaw = updated.stateRaw;
169
+ if (createdAt == null && updated.createdAt != null) {
170
+ createdAt = updated.createdAt;
171
+ }
172
+ if (updated.expiredAt != null) expiredAt = updated.expiredAt;
173
+ if (updated.isRefund != null) isRefund = updated.isRefund;
174
+
175
+ if (updated.receiveAmount != null) receiveAmount = updated.receiveAmount;
176
+ if (updated.inputAddress != null) inputAddress = updated.inputAddress;
177
+ if (updated.extraId != null) extraId = updated.extraId;
178
+ if (updated.outputTransaction != null) {
179
+ outputTransaction = updated.outputTransaction;
180
+ }
181
+ if (updated.refundAddress != null) refundAddress = updated.refundAddress;
182
+ if (updated.payoutAddress != null) payoutAddress = updated.payoutAddress;
183
+ if (updated.password != null) password = updated.password;
184
+ if (updated.providerId != null) providerId = updated.providerId;
185
+ if (updated.providerName != null) providerName = updated.providerName;
186
+ if (updated.memo != null) memo = updated.memo;
187
+ if (updated.txId != null) txId = updated.txId;
188
}
189
246
- Map<String, dynamic> toMap() {
190
+ Map<String, dynamic> toSqliteMap() {
191
return <String, dynamic>{
192
+ selfIdColumn: internalId,
193
'id': id,
249
- 'provider': provider.serialize(),
250
- 'input': fromRaw,
251
- 'output': toRaw,
252
- 'date': createdAt != null ? createdAt!.millisecondsSinceEpoch : null,
194
+ 'providerRaw': providerRaw,
195
+ 'fromTitle': from?.title,
196
+ 'fromName': from?.name,
197
+ 'fromTag': from?.tag,
198
+ 'fromFullName': from?.fullName,
199
+ 'fromDecimals': from?.decimals,
200
+ 'fromRaw': from?.raw,
201
+ 'fromIconPath': from?.iconPath,
202
+ 'fromFlatIconPath': from?.flatIconPath,
203
+ 'fromChainIconPath': from?.chainIconPath,
204
+ 'toTitle': to?.title,
205
+ 'toName': to?.name,
206
+ 'toTag': to?.tag,
207
+ 'toFullName': to?.fullName,
208
+ 'toDecimals': to?.decimals,
209
+ 'toRaw': to?.raw,
210
+ 'toIconPath': to?.iconPath,
211
+ 'toFlatIconPath': to?.flatIconPath,
212
+ 'toChainIconPath': to?.chainIconPath,
213
+ 'stateRaw': stateRaw,
214
+ 'createdAt': createdAt?.millisecondsSinceEpoch,
215
+ 'expiredAt': expiredAt?.millisecondsSinceEpoch,
216
'amount': amount,
254
- 'receive_amount': receiveAmount,
255
- 'wallet_id': walletId,
256
- 'from_wallet_address': fromWalletAddress,
217
+ 'receiveAmount': receiveAmount,
218
+ 'inputAddress': inputAddress,
219
+ 'extraId': extraId,
220
+ 'outputTransaction': outputTransaction,
221
+ 'refundAddress': refundAddress,
222
+ 'walletId': walletId,
223
+ 'payoutAddress': payoutAddress,
224
+ 'password': password,
225
+ 'providerId': providerId,
226
+ 'providerName': providerName,
227
+ 'fromWalletAddress': fromWalletAddress,
228
'memo': memo,
258
- 'tx_id': txId,
259
- 'isRefund': isRefund,
260
- 'isSendAll': isSendAll,
229
+ 'txId': txId,
230
+ 'isRefund': isRefund == true ? 1 : 0,
231
+ 'isSendAll': isSendAll == true ? 1 : 0,
232
'router': router,
262
- 'extra_id': extraId,
263
- 'chain_id': chainId,
233
+ 'needToRegisterInSwapXyz': needToRegisterInSwapXyz == true ? 1 : 0,
234
+ 'sourceTokenAddress': sourceTokenAddress,
235
+ 'sourceTokenDecimals': sourceTokenDecimals,
236
+ 'routerData': routerData,
237
+ 'routerValue': routerValue,
238
+ 'routerChainId': routerChainId,
239
+ 'sourceTokenAmountRaw': sourceTokenAmountRaw,
240
+ 'requiresTokenApproval': requiresTokenApproval == true ? 1 : 0,
241
+ 'chainId': chainId,
242
'fee': fee,
243
};
244
}
245
268
- String amountFormatted() => formatAmount(amount);
269
- String receiveAmountFormatted() => formatAmount(receiveAmount ?? '');
270
-}
246
+ factory Trade.fromSqliteRow(Map<String, dynamic> row) {
247
+ final trade = Trade(
248
+ id: row['id'] as String? ?? '',
249
+ amount: row['amount'] as String? ?? '',
250
+ receiveAmount: row['receiveAmount'] as String?,
251
+ createdAt: row['createdAt'] != null
252
+ ? DateTime.fromMillisecondsSinceEpoch(
253
+ row['createdAt'] as int,
254
+ )
255
+ : null,
256
+ expiredAt: row['expiredAt'] != null
257
+ ? DateTime.fromMillisecondsSinceEpoch(
258
+ row['expiredAt'] as int,
259
+ )
260
+ : null,
261
+ inputAddress: row['inputAddress'] as String?,
262
+ extraId: row['extraId'] as String?,
263
+ outputTransaction: row['outputTransaction'] as String?,
264
+ refundAddress: row['refundAddress'] as String?,
265
+ walletId: row['walletId'] as String?,
266
+ payoutAddress: row['payoutAddress'] as String?,
267
+ password: row['password'] as String?,
268
+ providerId: row['providerId'] as String?,
269
+ providerName: row['providerName'] as String?,
270
+ fromWalletAddress: row['fromWalletAddress'] as String?,
271
+ memo: row['memo'] as String?,
272
+ fee: row['fee'] as double?,
273
+ txId: row['txId'] as String?,
274
+ isRefund: (row['isRefund'] as int?) == 1,
275
+ isSendAll: (row['isSendAll'] as int?) == 1,
276
+ router: row['router'] as String?,
277
+ from: _currencyFromRow(row, 'from'),
278
+ to: _currencyFromRow(row, 'to'),
279
+ needToRegisterInSwapXyz: (row['needToRegisterInSwapXyz'] as int?) == 1,
280
+ sourceTokenAddress: row['sourceTokenAddress'] as String?,
281
+ sourceTokenDecimals: row['sourceTokenDecimals'] as int?,
282
+ routerData: row['routerData'] as String?,
283
+ routerValue: row['routerValue'] as String?,
284
+ routerChainId: row['routerChainId'] as int?,
285
+ sourceTokenAmountRaw: row['sourceTokenAmountRaw'] as String?,
286
+ requiresTokenApproval: (row['requiresTokenApproval'] as int?) == 1,
287
+ chainId: row['chainId'] as int?,
288
+ );
289
+ trade.internalId = row[selfIdColumn] as int? ?? 0;
290
+ trade.providerRaw = row['providerRaw'] as int? ?? 0;
291
+ trade.stateRaw = row['stateRaw'] as String? ?? '';
292
+ return trade;
293
+ }
294
272
-class TradeAdapter extends TypeAdapter<Trade> {
273
- @override
274
- final int typeId = Trade.typeId;
295
+ static CryptoCurrency? _currencyFromRow(Map<String, dynamic> row, String prefix) {
296
+ final title = row['${prefix}Title'] as String?;
297
+ if (title == null || title.isEmpty) return null;
298
276
- @override
277
- Trade read(BinaryReader reader) {
278
- final numOfFields = reader.readByte();
279
- final fields = <int, dynamic>{};
280
- for (int i = 0; i < numOfFields; i++) {
281
- try {
282
- fields[reader.readByte()] = reader.read();
283
- } catch (_) {}
284
- }
299
+ final tag = row['${prefix}Tag'] as String?;
300
286
- return Trade(
287
- id: fields[0] == null ? '' : fields[0] as String,
288
- amount: fields[7] == null ? '' : fields[7] as String,
289
- receiveAmount: fields[23] as String?,
290
- createdAt: fields[5] as DateTime?,
291
- expiredAt: fields[6] as DateTime?,
292
- inputAddress: fields[8] as String?,
293
- extraId: fields[9] as String?,
294
- outputTransaction: fields[10] as String?,
295
- refundAddress: fields[11] as String?,
296
- walletId: fields[12] as String?,
297
- payoutAddress: fields[13] as String?,
298
- password: fields[14] as String?,
299
- providerId: fields[15] as String?,
300
- providerName: fields[16] as String?,
301
- fromWalletAddress: fields[17] as String?,
302
- memo: fields[18] as String?,
303
- txId: fields[19] as String?,
304
- isRefund: fields[20] as bool?,
305
- isSendAll: fields[21] as bool?,
306
- router: fields[22] as String?,
307
- userCurrencyFromRaw: fields[24] as String?,
308
- userCurrencyToRaw: fields[25] as String?,
309
- needToRegisterInSwapXyz: fields[26] as bool?,
310
- sourceTokenAddress: fields[27] as String?,
311
- sourceTokenDecimals: fields[28] as int?,
312
- routerData: fields[29] as String?,
313
- routerValue: fields[30] as String?,
314
- routerChainId: fields[31] as int?,
315
- sourceTokenAmountRaw: fields[32] as String?,
316
- requiresTokenApproval: fields[33] as bool?,
317
- chainId: fields[34] as int?,
318
- fee: fields[35] as double?,
319
- )
320
- ..providerRaw = fields[1] == null ? 0 : fields[1] as int
321
- ..fromRaw = (fields[2] as int?) ?? -1
322
- ..toRaw = (fields[3] as int?) ?? -1
323
- ..stateRaw = fields[4] == null ? '' : fields[4] as String;
324
- }
301
+ final live = CryptoCurrency.safeParseCurrencyFromString(title, tag: tag);
302
+ if (live != null) return live;
303
326
- @override
327
- void write(BinaryWriter writer, Trade obj) {
328
- writer
329
- ..writeByte(26)
330
- ..writeByte(0)
331
- ..write(obj.id)
332
- ..writeByte(1)
333
- ..write(obj.providerRaw)
334
- ..writeByte(2)
335
- ..write(obj.fromRaw)
336
- ..writeByte(3)
337
- ..write(obj.toRaw)
338
- ..writeByte(4)
339
- ..write(obj.stateRaw)
340
- ..writeByte(5)
341
- ..write(obj.createdAt)
342
- ..writeByte(6)
343
- ..write(obj.expiredAt)
344
- ..writeByte(7)
345
- ..write(obj.amount)
346
- ..writeByte(8)
347
- ..write(obj.inputAddress)
348
- ..writeByte(9)
349
- ..write(obj.extraId)
350
- ..writeByte(10)
351
- ..write(obj.outputTransaction)
352
- ..writeByte(11)
353
- ..write(obj.refundAddress)
354
- ..writeByte(12)
355
- ..write(obj.walletId)
356
- ..writeByte(13)
357
- ..write(obj.payoutAddress)
358
- ..writeByte(14)
359
- ..write(obj.password)
360
- ..writeByte(15)
361
- ..write(obj.providerId)
362
- ..writeByte(16)
363
- ..write(obj.providerName)
364
- ..writeByte(17)
365
- ..write(obj.fromWalletAddress)
366
- ..writeByte(18)
367
- ..write(obj.memo)
368
- ..writeByte(19)
369
- ..write(obj.txId)
370
- ..writeByte(20)
371
- ..write(obj.isRefund)
372
- ..writeByte(21)
373
- ..write(obj.isSendAll)
374
- ..writeByte(22)
375
- ..write(obj.router)
376
- ..writeByte(23)
377
- ..write(obj.receiveAmount)
378
- ..writeByte(24)
379
- ..write(obj.userCurrencyFromRaw)
380
- ..writeByte(25)
381
- ..write(obj.userCurrencyToRaw)
382
- ..writeByte(26)
383
- ..write(obj.needToRegisterInSwapXyz)
384
- ..writeByte(27)
385
- ..write(obj.sourceTokenAddress)
386
- ..writeByte(28)
387
- ..write(obj.sourceTokenDecimals)
388
- ..writeByte(29)
389
- ..write(obj.routerData)
390
- ..writeByte(30)
391
- ..write(obj.routerValue)
392
- ..writeByte(31)
393
- ..write(obj.routerChainId)
394
- ..writeByte(32)
395
- ..write(obj.sourceTokenAmountRaw)
396
- ..writeByte(33)
397
- ..write(obj.requiresTokenApproval)
398
- ..writeByte(34)
399
- ..write(obj.chainId)
400
- ..writeByte(35)
401
- ..write(obj.fee);
304
+ return CryptoCurrency(
305
+ title: title,
306
+ name: row['${prefix}Name'] as String? ?? '',
307
+ tag: tag,
308
+ fullName: row['${prefix}FullName'] as String?,
309
+ decimals: row['${prefix}Decimals'] as int? ?? 1,
310
+ raw: row['${prefix}Raw'] as int? ?? -1,
311
+ iconPath: row['${prefix}IconPath'] as String?,
312
+ flatIconPath: row['${prefix}FlatIconPath'] as String?,
313
+ chainIconPath: row['${prefix}ChainIconPath'] as String?,
314
+ );
315
}
316
404
- @override
405
- int get hashCode => typeId.hashCode;
406
-
407
- @override
408
- bool operator ==(Object other) =>
409
- identical(this, other) ||
410
- other is TradeAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
317
+ String amountFormatted() => formatAmount(amount);
318
+ String receiveAmountFormatted() => formatAmount(receiveAmount ?? '');
319
}
lib/exchange/trade_currency_snapshot.dart
new
+45
@@ -0,0 +1,45 @@
1
+import 'package:cw_core/crypto_currency.dart';
2
+
3
+class TradeCurrencySnapshot {
4
+ TradeCurrencySnapshot._();
5
+
6
+ static CryptoCurrency? fromLegacyHive({
7
+ required int raw,
8
+ String? displayTitleTag,
9
+ }) {
10
+ if (raw >= 0) {
11
+ final curr = CryptoCurrency.safeDeserialize(raw: raw);
12
+ if (curr != null) return curr;
13
+ }
14
+
15
+ return _parseLegacyTitleTag(displayTitleTag);
16
+ }
17
+
18
+ static CryptoCurrency? _parseLegacyTitleTag(String? titleTag) {
19
+ if (titleTag == null || titleTag.isEmpty) return null;
20
+
21
+ final idx = titleTag.indexOf('_');
22
+ if (idx < 0) {
23
+ return CryptoCurrency(
24
+ title: titleTag,
25
+ name: '',
26
+ raw: -1,
27
+ decimals: 1,
28
+ );
29
+ }
30
+
31
+ final title = titleTag.substring(0, idx);
32
+
33
+ var tag = titleTag.substring(idx + 1);
34
+
35
+ if (tag.contains('ARB')) tag = 'ARB';
36
+
37
+ return CryptoCurrency(
38
+ title: title,
39
+ tag: tag.isNotEmpty ? tag : null,
40
+ name: '',
41
+ raw: -1,
42
+ decimals: 1,
43
+ );
44
+ }
45
+}
lib/exchange/trade_legacy.dart
new
+168
@@ -0,0 +1,168 @@
1
+import 'package:cake_wallet/core/secure_storage.dart';
2
+import 'package:cake_wallet/entities/get_encryption_key.dart';
3
+import 'package:cake_wallet/exchange/exchange_provider_description.dart';
4
+import 'package:cake_wallet/exchange/trade.dart';
5
+import 'package:cake_wallet/exchange/trade_currency_snapshot.dart';
6
+import 'package:cake_wallet/exchange/trade_state.dart';
7
+import 'package:cw_core/cake_hive.dart';
8
+import 'package:cw_core/crypto_currency.dart';
9
+import 'package:cw_core/hive_type_ids.dart';
10
+import 'package:cw_core/utils/print_verbose.dart';
11
+import 'package:hive/hive.dart';
12
+
13
+part 'trade_legacy.part.dart';
14
+
15
+Future<void> performTradeHiveMigration(SecureStorage secureStorage) async {
16
+ try {
17
+ if (!CakeHive.isAdapterRegistered(TradeLegacy.typeId)) {
18
+ CakeHive.registerAdapter(TradeLegacyAdapter());
19
+ }
20
+ final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
21
+ final box = await CakeHive.openBox<TradeLegacy>(Trade.boxName, encryptionKey: tradesBoxKey);
22
+ await TradeLegacy.migrateAllToSqlite(box);
23
+ } catch (e) {
24
+ printV('Trade Hive migration error: $e');
25
+ }
26
+}
27
+
28
+class TradeLegacy extends HiveObject {
29
+ TradeLegacy({
30
+ required this.id,
31
+ required this.amount,
32
+ ExchangeProviderDescription? provider,
33
+ CryptoCurrency? from,
34
+ CryptoCurrency? to,
35
+ TradeState? state,
36
+ this.receiveAmount,
37
+ this.createdAt,
38
+ this.expiredAt,
39
+ this.inputAddress,
40
+ this.extraId,
41
+ this.outputTransaction,
42
+ this.refundAddress,
43
+ this.walletId,
44
+ this.payoutAddress,
45
+ this.password,
46
+ this.providerId,
47
+ this.providerName,
48
+ this.fromWalletAddress,
49
+ this.memo,
50
+ this.fee,
51
+ this.txId,
52
+ this.isRefund,
53
+ this.isSendAll,
54
+ this.router,
55
+ this.userCurrencyFromRaw,
56
+ this.userCurrencyToRaw,
57
+ this.needToRegisterInSwapXyz,
58
+ this.sourceTokenAddress,
59
+ this.sourceTokenDecimals,
60
+ this.routerData,
61
+ this.routerValue,
62
+ this.routerChainId,
63
+ this.sourceTokenAmountRaw,
64
+ this.requiresTokenApproval,
65
+ this.chainId,
66
+ }) {
67
+ if (provider != null) providerRaw = provider.raw;
68
+ fromRaw = from?.raw ?? -1;
69
+ toRaw = to?.raw ?? -1;
70
+ if (state != null) stateRaw = state.raw;
71
+ }
72
+
73
+ static const typeId = TRADE_TYPE_ID;
74
+
75
+ String id;
76
+ late int providerRaw;
77
+ int fromRaw = -1;
78
+ int toRaw = -1;
79
+ late String stateRaw;
80
+ DateTime? createdAt;
81
+ DateTime? expiredAt;
82
+ String amount;
83
+ String? receiveAmount;
84
+ String? inputAddress;
85
+ String? extraId;
86
+ String? outputTransaction;
87
+ String? refundAddress;
88
+ String? walletId;
89
+ String? payoutAddress;
90
+ String? password;
91
+ String? providerId;
92
+ String? providerName;
93
+ String? fromWalletAddress;
94
+ String? memo;
95
+ String? txId;
96
+ bool? isRefund;
97
+ bool? isSendAll;
98
+ String? router;
99
+ String? userCurrencyFromRaw;
100
+ String? userCurrencyToRaw;
101
+ bool? needToRegisterInSwapXyz;
102
+ String? sourceTokenAddress;
103
+ int? sourceTokenDecimals;
104
+ String? routerData;
105
+ String? routerValue;
106
+ int? routerChainId;
107
+ String? sourceTokenAmountRaw;
108
+ bool? requiresTokenApproval;
109
+ int? chainId;
110
+ double? fee;
111
+
112
+ Future<void> migrateToSqlite() async {
113
+ final trade = Trade(
114
+ id: id,
115
+ amount: amount,
116
+ receiveAmount: receiveAmount,
117
+ createdAt: createdAt,
118
+ expiredAt: expiredAt,
119
+ inputAddress: inputAddress,
120
+ extraId: extraId,
121
+ outputTransaction: outputTransaction,
122
+ refundAddress: refundAddress,
123
+ walletId: walletId,
124
+ payoutAddress: payoutAddress,
125
+ password: password,
126
+ providerId: providerId,
127
+ providerName: providerName,
128
+ fromWalletAddress: fromWalletAddress,
129
+ memo: memo,
130
+ fee: fee,
131
+ txId: txId,
132
+ isRefund: isRefund,
133
+ isSendAll: isSendAll,
134
+ router: router,
135
+ from:
136
+ TradeCurrencySnapshot.fromLegacyHive(raw: fromRaw, displayTitleTag: userCurrencyFromRaw),
137
+ to: TradeCurrencySnapshot.fromLegacyHive(raw: toRaw, displayTitleTag: userCurrencyToRaw),
138
+ needToRegisterInSwapXyz: needToRegisterInSwapXyz,
139
+ sourceTokenAddress: sourceTokenAddress,
140
+ sourceTokenDecimals: sourceTokenDecimals,
141
+ routerData: routerData,
142
+ routerValue: routerValue,
143
+ routerChainId: routerChainId,
144
+ sourceTokenAmountRaw: sourceTokenAmountRaw,
145
+ requiresTokenApproval: requiresTokenApproval,
146
+ chainId: chainId,
147
+ );
148
+ trade.providerRaw = providerRaw;
149
+ trade.stateRaw = stateRaw;
150
+ await trade.save();
151
+ }
152
+
153
+ static Future<void> migrateAllToSqlite(
154
+ Box<TradeLegacy> box,
155
+ ) async {
156
+ printV('Migrating Trades to SQLite: start');
157
+ final list = box.values.toList();
158
+ for (final trade in list) {
159
+ try {
160
+ await trade.migrateToSqlite();
161
+ await trade.delete();
162
+ } catch (e) {
163
+ printV('Error migrating trade ${trade.id}: $e');
164
+ }
165
+ }
166
+ printV('Migrating Trades to SQLite: end');
167
+ }
168
+}
lib/exchange/trade_legacy.part.dart
new
+146
@@ -0,0 +1,146 @@
1
+part of 'trade_legacy.dart';
2
+
3
+class TradeLegacyAdapter extends TypeAdapter<TradeLegacy> {
4
+ @override
5
+ final int typeId = TradeLegacy.typeId;
6
+
7
+ @override
8
+ TradeLegacy read(BinaryReader reader) {
9
+ final numOfFields = reader.readByte();
10
+ final fields = <int, dynamic>{};
11
+ for (int i = 0; i < numOfFields; i++) {
12
+ try {
13
+ fields[reader.readByte()] = reader.read();
14
+ } catch (_) {}
15
+ }
16
+
17
+ return TradeLegacy(
18
+ id: fields[0] == null ? '' : fields[0] as String,
19
+ amount: fields[7] == null ? '' : fields[7] as String,
20
+ receiveAmount: fields[23] as String?,
21
+ createdAt: fields[5] as DateTime?,
22
+ expiredAt: fields[6] as DateTime?,
23
+ inputAddress: fields[8] as String?,
24
+ extraId: fields[9] as String?,
25
+ outputTransaction: fields[10] as String?,
26
+ refundAddress: fields[11] as String?,
27
+ walletId: fields[12] as String?,
28
+ payoutAddress: fields[13] as String?,
29
+ password: fields[14] as String?,
30
+ providerId: fields[15] as String?,
31
+ providerName: fields[16] as String?,
32
+ fromWalletAddress: fields[17] as String?,
33
+ memo: fields[18] as String?,
34
+ txId: fields[19] as String?,
35
+ isRefund: fields[20] as bool?,
36
+ isSendAll: fields[21] as bool?,
37
+ router: fields[22] as String?,
38
+ userCurrencyFromRaw: fields[24] as String?,
39
+ userCurrencyToRaw: fields[25] as String?,
40
+ needToRegisterInSwapXyz: fields[26] as bool?,
41
+ sourceTokenAddress: fields[27] as String?,
42
+ sourceTokenDecimals: fields[28] as int?,
43
+ routerData: fields[29] as String?,
44
+ routerValue: fields[30] as String?,
45
+ routerChainId: fields[31] as int?,
46
+ sourceTokenAmountRaw: fields[32] as String?,
47
+ requiresTokenApproval: fields[33] as bool?,
48
+ chainId: fields[34] as int?,
49
+ fee: fields[35] as double?,
50
+ )
51
+ ..providerRaw =
52
+ fields[1] == null ? 0 : fields[1] as int
53
+ ..fromRaw = (fields[2] as int?) ?? -1
54
+ ..toRaw = (fields[3] as int?) ?? -1
55
+ ..stateRaw =
56
+ fields[4] == null ? '' : fields[4] as String;
57
+ }
58
+
59
+ @override
60
+ void write(BinaryWriter writer, TradeLegacy obj) {
61
+ writer
62
+ ..writeByte(36)
63
+ ..writeByte(0)
64
+ ..write(obj.id)
65
+ ..writeByte(1)
66
+ ..write(obj.providerRaw)
67
+ ..writeByte(2)
68
+ ..write(obj.fromRaw)
69
+ ..writeByte(3)
70
+ ..write(obj.toRaw)
71
+ ..writeByte(4)
72
+ ..write(obj.stateRaw)
73
+ ..writeByte(5)
74
+ ..write(obj.createdAt)
75
+ ..writeByte(6)
76
+ ..write(obj.expiredAt)
77
+ ..writeByte(7)
78
+ ..write(obj.amount)
79
+ ..writeByte(8)
80
+ ..write(obj.inputAddress)
81
+ ..writeByte(9)
82
+ ..write(obj.extraId)
83
+ ..writeByte(10)
84
+ ..write(obj.outputTransaction)
85
+ ..writeByte(11)
86
+ ..write(obj.refundAddress)
87
+ ..writeByte(12)
88
+ ..write(obj.walletId)
89
+ ..writeByte(13)
90
+ ..write(obj.payoutAddress)
91
+ ..writeByte(14)
92
+ ..write(obj.password)
93
+ ..writeByte(15)
94
+ ..write(obj.providerId)
95
+ ..writeByte(16)
96
+ ..write(obj.providerName)
97
+ ..writeByte(17)
98
+ ..write(obj.fromWalletAddress)
99
+ ..writeByte(18)
100
+ ..write(obj.memo)
101
+ ..writeByte(19)
102
+ ..write(obj.txId)
103
+ ..writeByte(20)
104
+ ..write(obj.isRefund)
105
+ ..writeByte(21)
106
+ ..write(obj.isSendAll)
107
+ ..writeByte(22)
108
+ ..write(obj.router)
109
+ ..writeByte(23)
110
+ ..write(obj.receiveAmount)
111
+ ..writeByte(24)
112
+ ..write(obj.userCurrencyFromRaw)
113
+ ..writeByte(25)
114
+ ..write(obj.userCurrencyToRaw)
115
+ ..writeByte(26)
116
+ ..write(obj.needToRegisterInSwapXyz)
117
+ ..writeByte(27)
118
+ ..write(obj.sourceTokenAddress)
119
+ ..writeByte(28)
120
+ ..write(obj.sourceTokenDecimals)
121
+ ..writeByte(29)
122
+ ..write(obj.routerData)
123
+ ..writeByte(30)
124
+ ..write(obj.routerValue)
125
+ ..writeByte(31)
126
+ ..write(obj.routerChainId)
127
+ ..writeByte(32)
128
+ ..write(obj.sourceTokenAmountRaw)
129
+ ..writeByte(33)
130
+ ..write(obj.requiresTokenApproval)
131
+ ..writeByte(34)
132
+ ..write(obj.chainId)
133
+ ..writeByte(35)
134
+ ..write(obj.fee);
135
+ }
136
+
137
+ @override
138
+ int get hashCode => typeId.hashCode;
139
+
140
+ @override
141
+ bool operator ==(Object other) =>
142
+ identical(this, other) ||
143
+ other is TradeLegacyAdapter &&
144
+ runtimeType == other.runtimeType &&
145
+ typeId == other.typeId;
146
+}
lib/main.dart
+11
-20
@@ -19,7 +19,7 @@ import 'package:cake_wallet/entities/language_service.dart';
19
import 'package:cake_wallet/entities/template.dart';
20
import 'package:cake_wallet/entities/transaction_description.dart';
21
import 'package:cake_wallet/exchange/exchange_template.dart';
22
-import 'package:cake_wallet/exchange/trade.dart';
22
+import 'package:cake_wallet/exchange/trade_legacy.dart';
23
import 'package:cake_wallet/generated/i18n.dart';
24
import 'package:cake_wallet/locales/locale.dart';
25
import 'package:cake_wallet/order/order.dart';
@@ -37,7 +37,6 @@ import 'package:cake_wallet/utils/exception_handler.dart';
37
import 'package:cake_wallet/utils/feature_flag.dart';
38
import 'package:cake_wallet/utils/responsive_layout_util.dart';
39
import 'package:cake_wallet/view_model/link_view_model.dart';
40
-import 'package:cake_wallet/utils/responsive_layout_util.dart';
40
import 'package:cake_wallet/zcash/zcash.dart';
41
import 'package:cw_core/address_info.dart';
42
import 'package:cw_core/cake_hive.dart';
@@ -65,7 +64,6 @@ import 'package:flutter/services.dart';
64
import 'package:flutter_daemon/flutter_daemon.dart';
65
import 'package:flutter_mobx/flutter_mobx.dart';
66
import 'package:hive/hive.dart';
68
-import 'package:cw_core/root_dir.dart';
67
import 'package:quick_actions/quick_actions.dart';
68
import 'package:logging/logging.dart';
69
import 'package:shared_preferences/shared_preferences.dart';
@@ -230,10 +228,6 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
228
CakeHive.registerAdapter(TransactionDescriptionAdapter());
229
}
230
233
- if (!CakeHive.isAdapterRegistered(Trade.typeId)) {
234
- CakeHive.registerAdapter(TradeAdapter());
235
- }
236
-
231
if (!CakeHive.isAdapterRegistered(AddressInfo.typeId)) {
232
CakeHive.registerAdapter(AddressInfoAdapter());
233
}
@@ -290,7 +284,6 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
284
final secureStorage = secureStorageShared;
285
final transactionDescriptionsBoxKey =
286
await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
293
- final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
287
final ordersBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Order.boxKey);
288
final contacts = await CakeHive.openBox<Contact>(Contact.boxName);
289
final nodes = await CakeHive.openBox<Node>(Node.boxName);
@@ -299,7 +292,8 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
292
final transactionDescriptions = await CakeHive.openBox<TransactionDescription>(
293
TransactionDescription.boxName,
294
encryptionKey: transactionDescriptionsBoxKey);
302
- final trades = await CakeHive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
295
+ await performTradeHiveMigration(secureStorage);
296
+
297
final orders = await CakeHive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
298
final templates = await CakeHive.openBox<Template>(Template.boxName);
299
final exchangeTemplates = await CakeHive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
@@ -318,7 +312,6 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
312
nodes: nodes,
313
powNodes: powNodes,
314
contactSource: contacts,
321
- tradesSource: trades,
315
ordersSource: orders,
316
unspentCoinsInfoSource: unspentCoinsInfoSource,
317
// fiatConvertationService: fiatConvertationService,
@@ -339,7 +332,6 @@ Future<void> initialSetup({
332
required Box<Node> nodes,
333
required Box<Node> powNodes,
334
required Box<Contact> contactSource,
342
- required Box<Trade> tradesSource,
335
required Box<Order> ordersSource,
336
// required FiatConvertationService fiatConvertationService,
337
required Box<Template> templates,
@@ -354,19 +346,18 @@ Future<void> initialSetup({
346
}) async {
347
LanguageService.loadLocaleList();
348
await defaultSettingsMigration(
357
- secureStorage: secureStorage,
358
- version: initialMigrationVersion,
359
- sharedPreferences: sharedPreferences,
360
- contactSource: contactSource,
361
- tradeSource: tradesSource,
362
- nodes: nodes,
363
- powNodes: powNodes,
364
- havenSeedStore: havenSeedStore);
349
+ secureStorage: secureStorage,
350
+ version: initialMigrationVersion,
351
+ sharedPreferences: sharedPreferences,
352
+ contactSource: contactSource,
353
+ nodes: nodes,
354
+ powNodes: powNodes,
355
+ havenSeedStore: havenSeedStore,
356
+ );
357
await setup(
358
nodeSource: nodes,
359
powNodeSource: powNodes,
360
contactSource: contactSource,
369
- tradesSource: tradesSource,
361
ordersSource: ordersSource,
362
templates: templates,
363
exchangeTemplates: exchangeTemplates,
lib/new-ui/widgets/coins_page/assets_history/history_section.dart
+137
-124
@@ -35,13 +35,15 @@ class HistorySection extends StatelessWidget {
35
? SliverPadding(
36
padding: EdgeInsets.only(top: 24),
37
sliver: SliverToBoxAdapter(
38
- child: (dashboardViewModel.status is SyncingSyncStatus) ? SizedBox.shrink() : Center(
39
- child: Text(S.of(context).transactions_will_appear_here,
40
- style: TextStyle(
41
- fontSize: 14,
42
- fontWeight: FontWeight.w400,
43
- color: Theme.of(context).colorScheme.onSurfaceVariant)),
44
- ),
38
+ child: (dashboardViewModel.status is SyncingSyncStatus)
39
+ ? SizedBox.shrink()
40
+ : Center(
41
+ child: Text(S.of(context).transactions_will_appear_here,
42
+ style: TextStyle(
43
+ fontSize: 14,
44
+ fontWeight: FontWeight.w400,
45
+ color: Theme.of(context).colorScheme.onSurfaceVariant)),
46
+ ),
47
),
48
)
49
: SliverList(
@@ -51,136 +53,147 @@ class HistorySection extends StatelessWidget {
53
final prevItem = index == 0 ? null : dashboardViewModel.items[index - 1];
54
final topPadding = index == 0 ? 0.0 : 18.0;
55
final item = dashboardViewModel.items[index];
54
- final nextItem = index == dashboardViewModel.items.length - 1
55
- ? null
56
- : dashboardViewModel.items[index + 1];
56
+ final nextItem = index == dashboardViewModel.items.length - 1
57
+ ? null
58
+ : dashboardViewModel.items[index + 1];
59
58
- final roundedBottom = (nextItem == null || nextItem is DateSectionItem);
59
- final roundedTop = (prevItem == null || prevItem is DateSectionItem);
60
+ final roundedBottom = (nextItem == null || nextItem is DateSectionItem);
61
+ final roundedTop = (prevItem == null || prevItem is DateSectionItem);
62
61
- if (item is TransactionListItem) {
62
- final transaction = item.transaction;
63
- final transactionType = dashboardViewModel.getTransactionType(transaction);
63
+ if (item is TransactionListItem) {
64
+ final transaction = item.transaction;
65
+ final transactionType = dashboardViewModel.getTransactionType(transaction);
66
65
- if (item.hasTokens && item.assetOfTransaction == null) {
66
- return Container();
67
- }
67
+ if (item.hasTokens && item.assetOfTransaction == null) {
68
+ return Container();
69
+ }
70
69
- CryptoCurrency? asset;
70
- if (transaction.additionalInfo["isLightning"] == true)
71
- asset = CryptoCurrency.btcln;
72
- else
73
- asset = item.assetOfTransaction;
71
+ CryptoCurrency? asset;
72
+ if (transaction.additionalInfo["isLightning"] == true)
73
+ asset = CryptoCurrency.btcln;
74
+ else
75
+ asset = item.assetOfTransaction;
76
75
- return GestureDetector(
76
- onTap: () {
77
- final page = getIt.get<TransactionDetailsModal>(param1: transaction);
78
- showModalBottomSheet(isScrollControlled:true,context: context, builder: (context) => page);
79
- },
80
- child: HistoryTile(
81
- title: item.formattedTitle + transactionType,
82
- date: DateFormat('HH:mm').format(transaction.date),
83
- amount: item.formattedCryptoAmount,
84
- amountFiat: item.formattedFiatAmount,
85
- hasTokens: item.hasTokens,
86
- chainIconPath: _getChainIconPath(),
87
- roundedBottom: roundedBottom,
88
- roundedTop: roundedTop,
89
- bottomSeparator: !roundedBottom,
90
- direction: item.transaction.direction,
91
- pending: item.transaction.isPending,
92
- asset: asset,
93
- ),
94
- );
95
- } else if (item is TradeListItem) {
96
- final trade = item.trade;
77
+ return GestureDetector(
78
+ onTap: () {
79
+ final page = getIt.get<TransactionDetailsModal>(param1: transaction);
80
+ showModalBottomSheet(
81
+ isScrollControlled: true,
82
+ context: context,
83
+ builder: (context) => page);
84
+ },
85
+ child: HistoryTile(
86
+ title: item.formattedTitle + transactionType,
87
+ date: DateFormat('HH:mm').format(transaction.date),
88
+ amount: item.formattedCryptoAmount,
89
+ amountFiat: item.formattedFiatAmount,
90
+ hasTokens: item.hasTokens,
91
+ chainIconPath: _getChainIconPath(),
92
+ roundedBottom: roundedBottom,
93
+ roundedTop: roundedTop,
94
+ bottomSeparator: !roundedBottom,
95
+ direction: item.transaction.direction,
96
+ pending: item.transaction.isPending,
97
+ asset: asset,
98
+ ),
99
+ );
100
+ } else if (item is TradeListItem) {
101
+ final trade = item.trade;
102
+ final tradeFrom = trade.from;
103
+ final tradeTo = trade.to;
104
+ if (tradeFrom == null || tradeTo == null) {
105
+ return const SizedBox.shrink();
106
+ }
107
98
- final tradeFrom = trade.fromRaw >= 0 ? trade.from : trade.userCurrencyFrom;
108
+ return GestureDetector(
109
+ onTap: () => Navigator.of(context)
110
+ .pushNamed(Routes.tradeDetails, arguments: trade),
111
+ child: HistoryTradeTile(
112
+ from: tradeFrom,
113
+ to: tradeTo,
114
+ provider: trade.provider,
115
+ date:
116
+ DateFormat('HH:mm').format(item.trade.createdAt ?? DateTime.now()),
117
+ amount: trade.amountFormatted(),
118
+ receiveAmount: trade.receiveAmountFormatted(),
119
+ roundedBottom: roundedBottom,
120
+ roundedTop: roundedTop,
121
+ bottomSeparator: !roundedBottom,
122
+ swapState: trade.state,
123
+ ),
124
+ );
125
+ } else if (item is DateSectionItem) {
126
+ return Padding(
127
+ padding: EdgeInsets.only(left: 8.0, bottom: 8.0, top: topPadding),
128
+ child: Text(DateFormatter.convertDateTimeToReadableString(item.date),
129
+ style: TextStyle(
130
+ color: Theme.of(context).colorScheme.onSurfaceVariant)));
131
+ } else if (item is OrderListItem) {
132
+ return GestureDetector(
133
+ onTap: () => Navigator.of(context)
134
+ .pushNamed(Routes.orderDetails, arguments: item.order),
135
+ child: HistoryOrderTile(
136
+ date: DateFormat('HH:mm').format(item.order.createdAt),
137
+ amount: item.orderFormattedAmount,
138
+ amountFiat: "USD 0.00",
139
+ roundedBottom: roundedBottom,
140
+ roundedTop: roundedTop,
141
+ bottomSeparator: !roundedBottom,
142
+ ),
143
+ );
144
+ } else if (item is PayjoinTransactionListItem) {
145
+ final session = item.session;
146
100
- final tradeTo = trade.toRaw >= 0 ? trade.to : trade.userCurrencyTo;
147
+ return GestureDetector(
148
+ onTap: () => Navigator.of(context).pushNamed(
149
+ Routes.payjoinDetails,
150
+ arguments: [item.sessionId, item.transaction],
151
+ ),
152
+ child: PayjoinHistoryTile(
153
+ createdAt: DateFormat('HH:mm').format(session.inProgressSince!),
154
+ amount: dashboardViewModel.appStore.amountParsingProxy
155
+ .getDisplayCryptoString(
156
+ session.amount.toInt(), CryptoCurrency.btc),
157
+ currency: item.transaction?.from ?? "BTC",
158
+ state: item.status,
159
+ isSending: session.isSenderSession,
160
+ roundedTop: roundedTop,
161
+ roundedBottom: roundedBottom,
162
+ bottomSeparator: !roundedBottom),
163
+ );
164
+ } else if (item is AnonpayTransactionListItem) {
165
+ final transactionInfo = item.transaction;
166
102
- return GestureDetector(
103
- onTap: () => Navigator.of(context)
104
- .pushNamed(Routes.tradeDetails, arguments: trade),
105
- child: HistoryTradeTile(
106
- from: tradeFrom!,
107
- to: tradeTo!,
108
- provider: trade.provider,
109
- date: DateFormat('HH:mm').format(item.trade.createdAt!),
110
- amount: trade.amountFormatted(),
111
- receiveAmount: trade.receiveAmountFormatted(),
112
- roundedBottom: roundedBottom,
113
- roundedTop: roundedTop,
114
- bottomSeparator: !roundedBottom,
115
- swapState: trade.state,
116
- ),
117
- );
118
- } else if (item is DateSectionItem) {
119
- return Padding(
120
- padding: EdgeInsets.only(left: 8.0, bottom: 8.0, top: topPadding),
121
- child: Text(DateFormatter.convertDateTimeToReadableString(item.date),
122
- style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)));
123
- }else if(item is OrderListItem){
124
- return GestureDetector(
125
- onTap: () => Navigator.of(context)
126
- .pushNamed(Routes.orderDetails, arguments: item.order),
127
- child: HistoryOrderTile(
128
- date: DateFormat('HH:mm').format(item.order.createdAt),
129
- amount: item.orderFormattedAmount,
130
- amountFiat: "USD 0.00",
131
- roundedBottom: roundedBottom,
132
- roundedTop: roundedTop,
133
- bottomSeparator: !roundedBottom,
134
- ),
135
- );
136
- } else if (item is PayjoinTransactionListItem) {
137
- final session = item.session;
138
-
139
- return GestureDetector(
140
- onTap: () => Navigator.of(context).pushNamed(
141
- Routes.payjoinDetails,
142
- arguments: [item.sessionId, item.transaction],
167
+ return GestureDetector(
168
+ onTap: () => Navigator.of(context)
169
+ .pushNamed(Routes.anonPayDetailsPage, arguments: transactionInfo),
170
+ child: AnonpayHistoryTile(
171
+ provider: transactionInfo.provider,
172
+ createdAt: DateFormat('HH:mm').format(transactionInfo.createdAt),
173
+ amount: transactionInfo.fiatAmount?.toString() ??
174
+ (transactionInfo.amountTo?.toString() ?? ''),
175
+ currency: transactionInfo.fiatAmount != null
176
+ ? transactionInfo.fiatEquiv ?? ''
177
+ : CryptoCurrency.fromFullName(transactionInfo.coinTo)
178
+ .name
179
+ .toUpperCase(),
180
+ roundedTop: roundedTop,
181
+ roundedBottom: roundedBottom,
182
+ bottomSeparator: !roundedBottom));
183
+ } else
184
+ return Text(item.runtimeType.toString());
185
+ }),
186
+ ),
187
),
144
- child: PayjoinHistoryTile(
145
- createdAt: DateFormat('HH:mm').format(session.inProgressSince!),
146
- amount: dashboardViewModel.appStore.amountParsingProxy
147
- .getDisplayCryptoString(session.amount.toInt(), CryptoCurrency.btc),
148
- currency: item.transaction?.from ?? "BTC",
149
- state: item.status,
150
- isSending: session.isSenderSession,
151
- roundedTop: roundedTop,
152
- roundedBottom: roundedBottom,
153
- bottomSeparator: !roundedBottom),
154
- );
155
- } else if (item is AnonpayTransactionListItem) {
156
- final transactionInfo = item.transaction;
157
-
158
- return GestureDetector(
159
- onTap: () => Navigator.of(context)
160
- .pushNamed(Routes.anonPayDetailsPage, arguments: transactionInfo),
161
- child: AnonpayHistoryTile(
162
- provider: transactionInfo.provider,
163
- createdAt: DateFormat('HH:mm').format(transactionInfo.createdAt),
164
- amount: transactionInfo.fiatAmount?.toString() ??
165
- (transactionInfo.amountTo?.toString() ?? ''),
166
- currency: transactionInfo.fiatAmount != null
167
- ? transactionInfo.fiatEquiv ?? ''
168
- : CryptoCurrency.fromFullName(transactionInfo.coinTo).name.toUpperCase(),
169
- roundedTop: roundedTop,
170
- roundedBottom: roundedBottom,
171
- bottomSeparator: !roundedBottom));
172
- } else
173
- return Text(item.runtimeType.toString());
174
- }),
175
- ),
176
- ),
177
- ));
188
+ ));
189
}
190
191
String _getChainIconPath() {
192
try {
182
- return CryptoCurrency.fromString(dashboardViewModel.wallet.currency.tag ??dashboardViewModel.wallet.currency.title).chainIconPath!;
183
- } catch(e) {
193
+ return CryptoCurrency.fromString(
194
+ dashboardViewModel.wallet.currency.tag ?? dashboardViewModel.wallet.currency.title)
195
+ .chainIconPath!;
196
+ } catch (e) {
197
return dashboardViewModel.wallet.currency.chainIconPath ?? "";
198
}
199
}
lib/new-ui/widgets/coins_page/assets_history/history_trade_tile.dart
+29
-31
@@ -39,28 +39,30 @@ class HistoryTradeTile extends StatelessWidget {
39
width: 50,
40
child: Stack(
41
children: [
42
- CakeImageWidget(imageUrl: _getIconPath(from),
43
- width: currencyIconSize, height: currencyIconSize),
42
+ CakeImageWidget(
43
+ imageUrl: _getIconPath(from), width: currencyIconSize, height: currencyIconSize),
44
Positioned(
45
- top: currencyIconSize / 2,
46
- left: currencyIconSize / 2,
47
- child: Container(
48
- decoration: BoxDecoration(
49
- border: Border.all(
50
- width: 2,
51
- color: Theme.of(context).colorScheme.surfaceContainer),
52
- shape: BoxShape.circle),
53
- child: CakeImageWidget(imageUrl: _getIconPath(to),
54
- width: currencyIconSize, height: currencyIconSize))),
45
+ top: currencyIconSize / 2,
46
+ left: currencyIconSize / 2,
47
+ child: Container(
48
+ decoration: BoxDecoration(
49
+ border:
50
+ Border.all(width: 2, color: Theme.of(context).colorScheme.surfaceContainer),
51
+ shape: BoxShape.circle),
52
+ child: CakeImageWidget(
53
+ imageUrl: _getIconPath(to),
54
+ width: currencyIconSize,
55
+ height: currencyIconSize,
56
+ ),
57
+ ),
58
+ ),
59
],
60
),
61
);
62
}
63
60
-
64
@override
65
Widget build(BuildContext context) {
63
-
66
final fromChainIcon = _getChainIcon(from);
67
final toChainIcon = _getChainIcon(to);
68
@@ -118,36 +120,32 @@ class HistoryTradeTile extends StatelessWidget {
120
}
121
122
String _getIconPath(CryptoCurrency currency) {
121
- try { // temporarily until we migrate from hive to sqlite and store the full currency object
122
- if (currency.iconPath != null) {
123
- return currency.iconPath!;
123
+ try {
124
+ if (currency.title.isNotEmpty) {
125
+ final live = CryptoCurrency.safeParseCurrencyFromString(currency.title, tag: currency.tag);
126
+ if (live?.iconPath != null) return live!.iconPath!;
127
}
128
126
- if (currency.name.isNotEmpty) {
127
- final currencyFromName = CryptoCurrency.fromString(currency.name);
128
- if (currencyFromName.iconPath != null) {
129
- return currencyFromName.iconPath!;
130
- }
131
- }
129
+ if (currency.iconPath != null) return currency.iconPath!;
130
133
- if (currency.title.isNotEmpty) {
134
- final currencyFromTitle = CryptoCurrency.fromString(currency.title);
135
- if (currencyFromTitle.iconPath != null) {
136
- return currencyFromTitle.iconPath!;
137
- }
131
+ if (currency.name.isNotEmpty) {
132
+ final byName = CryptoCurrency.safeParseCurrencyFromString(currency.name);
133
+ if (byName?.iconPath != null) return byName!.iconPath!;
134
}
135
} catch (_) {}
136
141
- //TODO approporiate fallback
137
return "";
138
}
139
140
String _getChainIcon(CryptoCurrency currency) {
141
try {
147
- if (currency.chainIconPath != null) {
148
- return currency.chainIconPath!;
142
+ if (currency.title.isNotEmpty) {
143
+ final parsedCurrency = CryptoCurrency.safeParseCurrencyFromString(currency.title, tag: currency.tag);
144
+ if (parsedCurrency?.chainIconPath != null) return parsedCurrency!.chainIconPath!;
145
}
146
147
+ if (currency.chainIconPath != null) return currency.chainIconPath!;
148
+
149
if ((currency.tag ?? "").isNotEmpty) {
150
final currencyFromTag = CryptoCurrency.fromString(currency.tag!);
151
if (currencyFromTag.chainIconPath != null) {
lib/src/screens/dashboard/pages/transactions_page.dart
+2
-2
@@ -166,9 +166,9 @@ class TransactionsPage extends StatelessWidget {
166
final trade = item.trade;
167
168
final tradeFrom =
169
- trade.fromRaw >= 0 ? trade.from : trade.userCurrencyFrom;
169
+ trade.from;
170
171
- final tradeTo = trade.toRaw >= 0 ? trade.to : trade.userCurrencyTo;
171
+ final tradeTo = trade.to;
172
173
return tradeFrom != null && tradeTo != null
174
? Observer(
lib/src/screens/exchange_trade/exchange_trade_page.dart
+1
-1
@@ -31,7 +31,7 @@ void showInformation(ExchangeTradeViewModel exchangeTradeViewModel, BuildContext
31
final trade = exchangeTradeViewModel.trade;
32
final walletName = exchangeTradeViewModel.wallet.name;
33
34
- final from = trade.from?.toString() ?? trade.userCurrencyFrom.toString();
34
+ final from = trade.from?.toString() ?? '';
35
36
final information = exchangeTradeViewModel.isSendable
37
? S.current.exchange_trade_result_confirm(trade.amount, from, walletName) +
lib/src/widgets/bottom_sheet/swap_details_bottom_sheet.dart
+2
-2
@@ -319,14 +319,14 @@ class _SwapDetailsContent extends StatelessWidget {
319
_SwapDetailsTile(
320
label: 'You Send',
321
value:
322
- '${trade.amount} ${trade.from?.title ?? trade.userCurrencyFrom?.title ?? ''}',
322
+ '${trade.amount} ${trade.from?.title ?? ''}',
323
valueFiatFormatted: exchangeTradeViewModel.sendAmountFiatFormatted,
324
),
325
const SizedBox(height: 8),
326
_SwapDetailsTile(
327
label: 'You Get',
328
value:
329
- '${trade.receiveAmount ?? '0'} ${trade.to?.title ?? trade.userCurrencyTo?.title ?? ''}',
329
+ '${trade.receiveAmount ?? '0'} ${trade.to?.title ?? ''}',
330
valueFiatFormatted: exchangeTradeViewModel
331
.getReceiveAmountFiatFormatted(trade.receiveAmount ?? '0.0'),
332
),
lib/store/dashboard/trades_store.dart
+16
-14
@@ -1,9 +1,7 @@
1
-import 'dart:async';
1
import 'package:cake_wallet/exchange/trade.dart';
2
import 'package:cake_wallet/store/app_store.dart';
3
import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
4
import 'package:flutter/foundation.dart';
6
-import 'package:hive/hive.dart';
5
import 'package:mobx/mobx.dart';
6
7
part 'trades_store.g.dart';
@@ -11,14 +9,11 @@ part 'trades_store.g.dart';
9
class TradesStore = TradesStoreBase with _$TradesStore;
10
11
abstract class TradesStoreBase with Store {
14
- TradesStoreBase({required this.tradesSource, required this.appStore})
15
- : trades = <TradeListItem>[] {
16
- _onTradesChanged = tradesSource.watch().listen((_) async => await updateTradeList());
12
+ TradesStoreBase({required this.appStore}) : trades = <TradeListItem>[] {
13
+ Trade.onChanged.stream.listen((_) => updateTradeList());
14
updateTradeList();
15
}
16
20
- Box<Trade> tradesSource;
21
- StreamSubscription<BoxEvent>? _onTradesChanged;
17
AppStore appStore;
18
19
@observable
@@ -31,11 +26,18 @@ abstract class TradesStoreBase with Store {
26
void setTrade(Trade trade) => this.trade = trade;
27
28
@action
34
- Future<void> updateTradeList() async => trades = tradesSource.values
35
- .map((trade) => TradeListItem(
36
- trade: trade,
37
- appStore: appStore,
38
- key: ValueKey('trade_list_item_${trade.id}_key'),
39
- ))
40
- .toList();
29
+ Future<void> updateTradeList() async {
30
+ try {
31
+ final allTrades = await Trade.getAll();
32
+ runInAction(() {
33
+ trades = allTrades
34
+ .map((trade) => TradeListItem(
35
+ trade: trade,
36
+ appStore: appStore,
37
+ key: ValueKey('trade_list_item_${trade.id}_key'),
38
+ ))
39
+ .toList();
40
+ });
41
+ } catch (_) {}
42
+ }
43
}
lib/view_model/dashboard/trade_list_item.dart
+17
-8
@@ -15,15 +15,24 @@ class TradeListItem extends ActionListItem {
15
16
BalanceDisplayMode get displayMode => appStore.settingsStore.balanceDisplayMode;
17
18
- String get tradeFormattedAmount => displayMode == BalanceDisplayMode.hiddenBalance
19
- ? "---"
20
- : appStore.amountParsingProxy.getDisplayCryptoAmount(trade.amountFormatted(), trade.from!);
18
+ String get tradeFormattedAmount {
19
+ if (displayMode == BalanceDisplayMode.hiddenBalance) {
20
+ return '---';
21
+ }
22
+ final from = trade.from;
23
+ if (from == null) return trade.amountFormatted();
24
+ return appStore.amountParsingProxy.getDisplayCryptoAmount(trade.amountFormatted(), from);
25
+ }
26
22
- String get tradeFormattedReceiveAmount => displayMode == BalanceDisplayMode.hiddenBalance
23
- ? "---"
24
- : appStore.amountParsingProxy
25
- .getDisplayCryptoAmount(trade.receiveAmountFormatted(), trade.to!);
27
+ String get tradeFormattedReceiveAmount {
28
+ if (displayMode == BalanceDisplayMode.hiddenBalance) {
29
+ return '---';
30
+ }
31
+ final to = trade.to;
32
+ if (to == null) return trade.receiveAmountFormatted();
33
+ return appStore.amountParsingProxy.getDisplayCryptoAmount(trade.receiveAmountFormatted(), to);
34
+ }
35
36
@override
28
- DateTime get date => trade.createdAt!;
37
+ DateTime get date => trade.createdAt ?? DateTime.fromMillisecondsSinceEpoch(0, isUtc: true);
38
}
lib/view_model/exchange/exchange_trade_view_model.dart
+23
-36
@@ -34,7 +34,6 @@ import 'package:cw_core/payment_uris.dart';
34
import 'package:cw_core/utils/print_verbose.dart';
35
import 'package:cw_core/wallet_base.dart';
36
import 'package:cw_core/wallet_type.dart';
37
-import 'package:hive/hive.dart';
37
import 'package:mobx/mobx.dart';
38
39
part 'exchange_trade_view_model.g.dart';
@@ -44,7 +43,6 @@ class ExchangeTradeViewModel = ExchangeTradeViewModelBase with _$ExchangeTradeVi
43
abstract class ExchangeTradeViewModelBase with Store {
44
ExchangeTradeViewModelBase({
45
required this.wallet,
47
- required this.trades,
46
required this.tradesStore,
47
required this.sendViewModel,
48
required this.feesViewModel,
@@ -78,10 +76,10 @@ abstract class ExchangeTradeViewModelBase with Store {
76
_provider = StealthExExchangeProvider();
77
break;
78
case ExchangeProviderDescription.thorChain:
81
- _provider = ThorChainExchangeProvider(tradesStore: trades);
79
+ _provider = ThorChainExchangeProvider();
80
break;
81
case ExchangeProviderDescription.chainflip:
84
- _provider = ChainflipExchangeProvider(tradesStore: trades);
82
+ _provider = ChainflipExchangeProvider();
83
break;
84
case ExchangeProviderDescription.xoSwap:
85
_provider = XOSwapExchangeProvider();
@@ -106,7 +104,6 @@ abstract class ExchangeTradeViewModelBase with Store {
104
}
105
106
final WalletBase wallet;
109
- final Box<Trade> trades;
107
final TradesStore tradesStore;
108
final SendViewModel sendViewModel;
109
final FeesViewModel feesViewModel;
@@ -217,7 +214,7 @@ abstract class ExchangeTradeViewModelBase with Store {
214
Future<void> confirmSending() async {
215
if (!isSendable) return;
216
220
- final selected = trade.from ?? trade.userCurrencyFrom;
217
+ final selected = trade.from;
218
if (selected == null) {
219
printV('No selectable currency for trade ${trade.id}');
220
return;
@@ -231,35 +228,23 @@ abstract class ExchangeTradeViewModelBase with Store {
228
if (_provider is SwapsXyzExchangeProvider) {
229
final hash = pendingTransaction?.evmTxHashFromRawHex ?? pendingTransaction?.id ?? '';
230
trade.txId = hash;
234
-
235
- if (trade.isInBox) {
236
- await trade.save();
237
- } else {
238
- await trades.add(trade);
239
- }
231
+ await trade.save();
232
}
233
234
if (_provider is ThorChainExchangeProvider) {
235
trade.id = pendingTransaction?.id ?? '';
244
- trades.add(trade);
236
+ await trade.save();
237
}
238
}
239
240
@action
241
Future<void> _updateTrade() async {
242
try {
251
- final agreedAmount = tradesStore.trade!.amount;
252
- final isSendAll = tradesStore.trade!.isSendAll;
243
final updatedTrade = await _provider!.findTradeById(id: trade.id);
244
255
- if (updatedTrade.createdAt == null && trade.createdAt != null)
256
- updatedTrade.createdAt = trade.createdAt;
257
-
258
- if (updatedTrade.amount.isEmpty) updatedTrade.amount = trade.amount;
259
-
260
- trade = updatedTrade;
261
- trade.amount = agreedAmount;
262
- trade.isSendAll = isSendAll;
245
+ trade.mergeFindTradeByIdResult(updatedTrade);
246
+ await trade.save();
247
+ tradesStore.setTrade(trade);
248
249
_updateItems();
250
} catch (e) {
@@ -268,10 +253,8 @@ abstract class ExchangeTradeViewModelBase with Store {
253
}
254
255
void _updateItems() {
271
- final trade = tradesStore.trade!;
272
-
273
- final tradeFrom = trade.fromRaw >= 0 ? trade.from : trade.userCurrencyFrom;
274
- final tradeTo = trade.toRaw >= 0 ? trade.to : trade.userCurrencyTo;
256
+ final tradeFrom = trade.from;
257
+ final tradeTo = trade.to;
258
259
final tagFrom = tradeFrom?.tag != null ? "${tradeFrom!.tag} " : "";
260
final tagTo = tradeTo?.tag != null ? "${tradeTo!.tag} " : "";
@@ -289,12 +272,12 @@ abstract class ExchangeTradeViewModelBase with Store {
272
),
273
);
274
292
- if (tradeFrom != null || tradeTo != null) {
275
+ if (tradeFrom != null && tradeTo != null) {
276
items.addAll([
277
ExchangeTradeItem(
278
title: S.current.amount,
279
data:
297
- "${_amountParsingProxy.getDisplayCryptoAmount(trade.amount, tradeFrom!)} ${_amountParsingProxy.getCryptoSymbol(tradeFrom)}",
280
+ "${_amountParsingProxy.getDisplayCryptoAmount(trade.amount, tradeFrom)} ${_amountParsingProxy.getCryptoSymbol(tradeFrom)}",
281
isCopied: false,
282
isReceiveDetail: false,
283
isExternalSendDetail: true,
@@ -302,14 +285,14 @@ abstract class ExchangeTradeViewModelBase with Store {
285
ExchangeTradeItem(
286
title: "${S.current.you_will_receive_estimated_amount}:",
287
data:
305
- "${_amountParsingProxy.getDisplayCryptoAmount(tradesStore.trade?.receiveAmount ?? "0", tradeTo!)} ${_amountParsingProxy.getCryptoSymbol(tradeTo)}",
288
+ "${_amountParsingProxy.getDisplayCryptoAmount(trade.receiveAmount ?? "0", tradeTo)} ${_amountParsingProxy.getCryptoSymbol(tradeTo)}",
289
isCopied: true,
290
isReceiveDetail: true,
291
isExternalSendDetail: false,
292
),
293
ExchangeTradeItem(
311
- title: "${S.current.send_to_this_address("${tradeFrom}", tagFrom)}:",
312
- data: trade.inputAddress ?? "",
294
+ title: "${S.current.send_to_this_address("$tradeFrom", tagFrom)}:",
295
+ data: trade.inputAddress ?? '',
296
isCopied: false,
297
isReceiveDetail: false,
298
isExternalSendDetail: true,
@@ -367,7 +350,10 @@ abstract class ExchangeTradeViewModelBase with Store {
350
351
static bool _checkIfCanSend(TradesStore tradesStore, WalletBase wallet) {
352
final trade = tradesStore.trade!;
370
- final tradeFrom = trade.fromRaw >= 0 ? trade.from : trade.userCurrencyFrom;
353
+ final tradeFrom = trade.from;
354
+
355
+ bool _sameCurrency(CryptoCurrency? a, CryptoCurrency? b) =>
356
+ a != null && b != null && a.titleAndTagEqual(b);
357
358
bool _isEthToken() =>
359
wallet.currency == CryptoCurrency.eth && tradeFrom?.tag == CryptoCurrency.eth.title;
@@ -393,8 +379,9 @@ abstract class ExchangeTradeViewModelBase with Store {
379
bool _isBscToken() =>
380
wallet.currency == CryptoCurrency.bnb && tradeFrom?.tag == CryptoCurrency.bnb.tag;
381
396
- return tradeFrom == wallet.currency ||
397
- tradeFrom == CryptoCurrency.btcln && wallet.currency == CryptoCurrency.btc ||
382
+ return _sameCurrency(tradeFrom, wallet.currency) ||
383
+ (_sameCurrency(tradeFrom, CryptoCurrency.btcln) &&
384
+ wallet.currency == CryptoCurrency.btc) ||
385
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto ||
386
_isEthToken() ||
387
_isPolygonToken() ||
@@ -472,7 +459,7 @@ abstract class ExchangeTradeViewModelBase with Store {
459
PaymentURI? get paymentUri {
460
final inputAddress = trade.inputAddress;
461
final amount = trade.amount;
475
- final fromCurrency = trade.from ?? trade.userCurrencyFrom;
462
+ final fromCurrency = trade.from;
463
464
if (inputAddress == null || inputAddress.isEmpty || fromCurrency == null) {
465
return null;
lib/view_model/exchange/exchange_view_model.dart
+3
-6
@@ -67,7 +67,6 @@ import 'package:cw_core/utils/print_verbose.dart';
67
import 'package:cw_core/utils/proxy_wrapper.dart';
68
import 'package:cw_core/wallet_type.dart';
69
import 'package:flutter/material.dart';
70
-import 'package:hive/hive.dart';
70
import 'package:mobx/mobx.dart';
71
import 'package:shared_preferences/shared_preferences.dart';
72
@@ -95,7 +94,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
94
95
ExchangeViewModelBase(
96
this._appStore,
98
- this.trades,
97
this._exchangeTemplateStore,
98
this.tradesStore,
99
this.sharedPreferences,
@@ -307,7 +305,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
305
[WalletType.monero, WalletType.wownero, WalletType.zcash].contains(wallet.type);
306
307
bool _useTorOnly;
310
- final Box<Trade> trades;
308
final ExchangeTemplateStore _exchangeTemplateStore;
309
final TradesStore tradesStore;
310
final SharedPreferences sharedPreferences;
@@ -315,7 +312,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
312
List<ExchangeProvider> get _allProviders => [
313
ChangeNowExchangeProvider(settingsStore: _settingsStore),
314
// SideShiftExchangeProvider(),
318
- ChainflipExchangeProvider(tradesStore: trades),
315
+ ChainflipExchangeProvider(),
316
if (FeatureFlag.isExolixEnabled) ExolixExchangeProvider(),
317
SwapTradeExchangeProvider(),
318
LetsExchangeExchangeProvider(),
@@ -1213,7 +1210,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
1210
}
1211
1212
tradesStore.setTrade(trade);
1216
- if (trade.provider != ExchangeProviderDescription.thorChain) await trades.add(trade);
1213
+ if (trade.provider != ExchangeProviderDescription.thorChain) await trade.save();
1214
tradeState = TradeIsCreatedSuccessfully(trade: trade);
1215
1216
/// return after the first successful trade
@@ -1626,7 +1623,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
1623
1624
if (trade.provider == ExchangeProviderDescription.swapsXyz) {
1625
1629
- final tradeFrom = trade.fromRaw >= 0 ? trade.from : trade.userCurrencyFrom;
1626
+ final tradeFrom = trade.from;
1627
1628
if (tradeFrom == null) {
1629
return CreateTradeResult(
lib/view_model/send/send_view_model.dart
+1
-3
@@ -1091,9 +1091,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
1091
1092
_currentTrade!.stateRaw = isSuccess ? TradeState.completed.raw : TradeState.failed.raw;
1093
1094
- if (_currentTrade!.isInBox) {
1095
- await _currentTrade!.save();
1096
- }
1094
+ await _currentTrade!.save();
1095
}
1096
1097
@action
lib/view_model/trade_details_view_model.dart
+7
-44
@@ -26,11 +26,8 @@ import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.d
26
import 'package:cake_wallet/store/app_store.dart';
27
import 'package:cake_wallet/utils/date_formatter.dart';
28
import 'package:cake_wallet/utils/show_bar.dart';
29
-import 'package:collection/collection.dart';
30
-import 'package:cw_core/crypto_currency.dart';
29
import 'package:cw_core/utils/print_verbose.dart';
30
import 'package:flutter/services.dart';
33
-import 'package:hive/hive.dart';
31
import 'package:mobx/mobx.dart';
32
import 'package:url_launcher/url_launcher.dart';
33
@@ -41,11 +38,9 @@ class TradeDetailsViewModel = TradeDetailsViewModelBase with _$TradeDetailsViewM
38
abstract class TradeDetailsViewModelBase with Store {
39
TradeDetailsViewModelBase({
40
required Trade tradeForDetails,
44
- required this.trades,
41
required this.appStore,
42
}) : items = ObservableList<StandartListItem>(),
47
- trade = trades.values.firstWhereOrNull((element) => element.id == tradeForDetails.id) ??
48
- tradeForDetails {
43
+ trade = tradeForDetails {
44
switch (trade.provider) {
45
case ExchangeProviderDescription.changeNow:
46
_provider = ChangeNowExchangeProvider(settingsStore: appStore.settingsStore);
@@ -63,7 +58,7 @@ abstract class TradeDetailsViewModelBase with Store {
58
_provider = ExolixExchangeProvider();
59
break;
60
case ExchangeProviderDescription.thorChain:
66
- _provider = ThorChainExchangeProvider(tradesStore: trades);
61
+ _provider = ThorChainExchangeProvider();
62
break;
63
case ExchangeProviderDescription.swapTrade:
64
_provider = SwapTradeExchangeProvider();
@@ -74,7 +69,7 @@ abstract class TradeDetailsViewModelBase with Store {
69
_provider = StealthExExchangeProvider();
70
break;
71
case ExchangeProviderDescription.chainflip:
77
- _provider = ChainflipExchangeProvider(tradesStore: trades);
72
+ _provider = ChainflipExchangeProvider();
73
break;
74
case ExchangeProviderDescription.xoSwap:
75
_provider = XOSwapExchangeProvider();
@@ -132,8 +127,6 @@ abstract class TradeDetailsViewModelBase with Store {
127
return null;
128
}
129
135
- final Box<Trade> trades;
136
-
130
@observable
131
Trade trade;
132
@@ -151,22 +144,8 @@ abstract class TradeDetailsViewModelBase with Store {
144
try {
145
final updatedTrade = await _provider!.findTradeById(id: trade.id);
146
154
- if (updatedTrade.createdAt == null && trade.createdAt != null) {
155
- updatedTrade.createdAt = trade.createdAt;
156
- }
157
-
158
- if (updatedTrade.toRaw == -1 && trade.toRaw != -1) {
159
- updatedTrade.toRaw = trade.toRaw;
160
- }
161
-
162
- Trade? foundElement = trades.values.firstWhereOrNull((element) => element.id == trade.id);
163
- if (foundElement != null) {
164
- final editedTrade = trades.get(foundElement.key);
165
- editedTrade?.stateRaw = updatedTrade.stateRaw;
166
- editedTrade?.save();
167
- }
168
-
169
- trade = updatedTrade;
147
+ trade.mergeFindTradeByIdResult(updatedTrade);
148
+ await trade.save();
149
150
_updateItems();
151
} catch (e) {
@@ -186,8 +165,8 @@ abstract class TradeDetailsViewModelBase with Store {
165
items.add(
166
DetailsListStatusItem(title: S.current.trade_details_state, value: trade.state.toString()));
167
189
- final tradeFrom = _safeFrom(trade);
190
- final tradeTo = _safeTo(trade);
168
+ final tradeFrom = trade.from;
169
+ final tradeTo = trade.to;
170
171
if (tradeFrom != null && tradeTo != null) {
172
items.add(TradeDetailsListCardItem.tradeDetails(
@@ -241,21 +220,5 @@ abstract class TradeDetailsViewModelBase with Store {
220
} catch (e) {}
221
}
222
244
- CryptoCurrency? _safeFrom(Trade trade) {
245
- try {
246
- final raw = trade.fromRaw;
247
- return raw >= 0 ? trade.from : trade.userCurrencyFrom;
248
- } catch (_) {
249
- return trade.userCurrencyFrom;
250
- }
251
- }
223
253
- CryptoCurrency? _safeTo(Trade trade) {
254
- try {
255
- final raw = trade.toRaw;
256
- return raw >= 0 ? trade.to : trade.userCurrencyTo;
257
- } catch (_) {
258
- return trade.userCurrencyTo;
259
- }
260
- }
224
}