mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
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>
This commit is contained in:
co-authored by
Omar Hatem
parent
813aa348bc
commit
9f6396f5d8
@@ -41,7 +41,7 @@ Future<void> initDb({String? pathOverride}) async {
|
||||
}
|
||||
}
|
||||
await db?.close();
|
||||
db = await openDatabase(dbFile.path, version: 5,
|
||||
db = await openDatabase(dbFile.path, version: 6,
|
||||
onUpgrade: (Database db, int oldVersion, int newVersion) async {
|
||||
printV("migrating: $oldVersion, $newVersion");
|
||||
if (oldVersion <= 1) {
|
||||
@@ -93,6 +93,9 @@ CREATE TABLE IF NOT EXISTS BalanceCardStyleSettings (
|
||||
if (oldVersion <= 4) {
|
||||
await _createBridgeTransferTable(db);
|
||||
}
|
||||
if (oldVersion <= 5) {
|
||||
await _createTradeTable(db);
|
||||
}
|
||||
},
|
||||
onCreate: (Database db, int version) async {
|
||||
await db.execute(
|
||||
@@ -191,10 +194,73 @@ CREATE TABLE BalanceCardStyleSettings (
|
||||
);
|
||||
''');
|
||||
await _createBridgeTransferTable(db);
|
||||
await _createTradeTable(db);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _createTradeTable(Database db) async {
|
||||
await db.execute('''
|
||||
CREATE TABLE IF NOT EXISTS Trade (
|
||||
tradeId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
id TEXT NOT NULL,
|
||||
providerRaw INTEGER NOT NULL DEFAULT 0,
|
||||
fromTitle TEXT,
|
||||
fromName TEXT,
|
||||
fromTag TEXT,
|
||||
fromFullName TEXT,
|
||||
fromDecimals INTEGER,
|
||||
fromRaw INTEGER,
|
||||
fromIconPath TEXT,
|
||||
fromFlatIconPath TEXT,
|
||||
fromChainIconPath TEXT,
|
||||
toTitle TEXT,
|
||||
toName TEXT,
|
||||
toTag TEXT,
|
||||
toFullName TEXT,
|
||||
toDecimals INTEGER,
|
||||
toRaw INTEGER,
|
||||
toIconPath TEXT,
|
||||
toFlatIconPath TEXT,
|
||||
toChainIconPath TEXT,
|
||||
stateRaw TEXT NOT NULL DEFAULT '',
|
||||
createdAt INTEGER,
|
||||
expiredAt INTEGER,
|
||||
amount TEXT NOT NULL DEFAULT '',
|
||||
receiveAmount TEXT,
|
||||
inputAddress TEXT,
|
||||
extraId TEXT,
|
||||
outputTransaction TEXT,
|
||||
refundAddress TEXT,
|
||||
walletId TEXT,
|
||||
payoutAddress TEXT,
|
||||
password TEXT,
|
||||
providerId TEXT,
|
||||
providerName TEXT,
|
||||
fromWalletAddress TEXT,
|
||||
memo TEXT,
|
||||
txId TEXT,
|
||||
isRefund INTEGER DEFAULT 0,
|
||||
isSendAll INTEGER DEFAULT 0,
|
||||
router TEXT,
|
||||
needToRegisterInSwapXyz INTEGER DEFAULT 0,
|
||||
sourceTokenAddress TEXT,
|
||||
sourceTokenDecimals INTEGER,
|
||||
routerData TEXT,
|
||||
routerValue TEXT,
|
||||
routerChainId INTEGER,
|
||||
sourceTokenAmountRaw TEXT,
|
||||
requiresTokenApproval INTEGER DEFAULT 0,
|
||||
chainId INTEGER,
|
||||
fee REAL
|
||||
);
|
||||
''');
|
||||
await db.execute('''
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_trade_id_unique
|
||||
ON Trade (id);
|
||||
''');
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> dumpDb() async {
|
||||
try {
|
||||
return await _dumpDb();
|
||||
|
||||
@@ -246,35 +246,35 @@ class WalletInfo extends HiveObject {
|
||||
Future<void> migrateToSqlite() async {
|
||||
final di = newWi.DerivationInfo(
|
||||
id: 0,
|
||||
derivationType: derivationInfo?.derivationType ?? derivationType ?? newWi.DerivationType.unknown,
|
||||
derivationType:
|
||||
derivationInfo?.derivationType ?? derivationType ?? newWi.DerivationType.unknown,
|
||||
derivationPath: derivationInfo?.derivationPath ?? derivationPath ?? '',
|
||||
);
|
||||
final derivationInfoId = await di.save();
|
||||
final walletInfo = newWi.WalletInfo(
|
||||
0,
|
||||
id,
|
||||
name,
|
||||
type,
|
||||
isRecovery,
|
||||
restoreHeight,
|
||||
timestamp,
|
||||
dirPath,
|
||||
path,
|
||||
address,
|
||||
yatEid,
|
||||
yatLastUsedAddressRaw,
|
||||
showIntroCakePayCard,
|
||||
derivationInfoId,
|
||||
hardwareWalletType,
|
||||
parentAddress,
|
||||
hashedWalletIdentifier,
|
||||
isNonSeedWallet,
|
||||
0,
|
||||
addressPageType,
|
||||
false,
|
||||
true,
|
||||
null
|
||||
);
|
||||
0,
|
||||
id,
|
||||
name,
|
||||
type,
|
||||
isRecovery,
|
||||
restoreHeight,
|
||||
timestamp,
|
||||
dirPath,
|
||||
path,
|
||||
address,
|
||||
yatEid,
|
||||
yatLastUsedAddressRaw,
|
||||
showIntroCakePayCard,
|
||||
derivationInfoId,
|
||||
hardwareWalletType,
|
||||
parentAddress,
|
||||
hashedWalletIdentifier,
|
||||
isNonSeedWallet,
|
||||
0,
|
||||
addressPageType,
|
||||
false,
|
||||
true,
|
||||
null);
|
||||
final wiId = await walletInfo.save();
|
||||
for (final address in usedAddresses ?? <String>[]) {
|
||||
await newWi.WalletInfoAddress.insert(wiId, newWi.WalletInfoAddressType.used, address);
|
||||
@@ -289,8 +289,8 @@ class WalletInfo extends HiveObject {
|
||||
for (final address in addressInfos![i] ?? <AddressInfo>[]) {
|
||||
await newWi.WalletInfoAddressInfo.insert(
|
||||
walletInfoId: wiId,
|
||||
mapKey: i,
|
||||
accountIndex: address.accountIndex??0,
|
||||
mapKey: i,
|
||||
accountIndex: address.accountIndex ?? 0,
|
||||
address: address.address,
|
||||
label: address.label,
|
||||
);
|
||||
@@ -304,8 +304,12 @@ class WalletInfo extends HiveObject {
|
||||
final sw = Stopwatch()..start();
|
||||
final list = box.values.toList();
|
||||
for (final wi in list) {
|
||||
await wi.migrateToSqlite();
|
||||
await wi.delete();
|
||||
try {
|
||||
await wi.migrateToSqlite();
|
||||
await wi.delete();
|
||||
} catch (e) {
|
||||
printV('Error migrating WalletInfo ${wi.id}: $e');
|
||||
}
|
||||
}
|
||||
printV('Migrating WalletInfo to SQLite: end (${sw.elapsedMilliseconds}ms)');
|
||||
}
|
||||
|
||||
@@ -385,8 +385,8 @@ class TransactionsPageRobot {
|
||||
|
||||
Future<void> _verifyTradeListItemDisplay(TradeListItem item) async {
|
||||
final keyId = 'trade_list_item_${item.trade.id}_key';
|
||||
final from = item.trade.from?.toString() ?? item.trade.userCurrencyFrom.toString();
|
||||
final to = item.trade.to?.toString() ?? item.trade.userCurrencyTo.toString();
|
||||
final from = item.trade.from?.toString() ?? '';
|
||||
final to = item.trade.to?.toString() ?? '';
|
||||
|
||||
//* ==============Confirm it has the right key for this item ========
|
||||
commonTestCases.hasValueKey(keyId);
|
||||
|
||||
@@ -19,6 +19,7 @@ import 'package:cake_wallet/entities/encrypt.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cake_wallet/exchange/trade_legacy.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/wallet_types.g.dart';
|
||||
import 'package:cake_backup/backup.dart' as cake_backup;
|
||||
@@ -110,6 +111,7 @@ class $BackupService {
|
||||
|
||||
Future<void> verifyWallets() async {
|
||||
await performHiveMigration(); // for backups made before sqlite migration
|
||||
await performTradeHiveMigration(_secureStorage);
|
||||
correctWallets = (await WalletInfo.getAll()).where((info) => availableWalletTypes.contains(info.type)).toList();
|
||||
|
||||
if (correctWallets.isEmpty) {
|
||||
|
||||
@@ -20,7 +20,6 @@ import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/provider/xoswap_exchange_provider.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
@@ -30,13 +29,11 @@ class TradeMonitor {
|
||||
|
||||
TradeMonitor({
|
||||
required this.tradesStore,
|
||||
required this.trades,
|
||||
required this.appStore,
|
||||
required this.preferences,
|
||||
});
|
||||
|
||||
final TradesStore tradesStore;
|
||||
final Box<Trade> trades;
|
||||
final AppStore appStore;
|
||||
final Map<String, Timer> _tradeTimers = {};
|
||||
final SharedPreferences preferences;
|
||||
@@ -54,7 +51,7 @@ class TradeMonitor {
|
||||
case ExchangeProviderDescription.exolix:
|
||||
return ExolixExchangeProvider();
|
||||
case ExchangeProviderDescription.thorChain:
|
||||
return ThorChainExchangeProvider(tradesStore: trades);
|
||||
return ThorChainExchangeProvider();
|
||||
case ExchangeProviderDescription.swapTrade:
|
||||
return SwapTradeExchangeProvider();
|
||||
case ExchangeProviderDescription.letsExchange:
|
||||
@@ -62,7 +59,7 @@ class TradeMonitor {
|
||||
case ExchangeProviderDescription.stealthEx:
|
||||
return StealthExExchangeProvider();
|
||||
case ExchangeProviderDescription.chainflip:
|
||||
return ChainflipExchangeProvider(tradesStore: trades);
|
||||
return ChainflipExchangeProvider();
|
||||
case ExchangeProviderDescription.xoSwap:
|
||||
return XOSwapExchangeProvider();
|
||||
case ExchangeProviderDescription.swapsXyz:
|
||||
@@ -187,12 +184,7 @@ class TradeMonitor {
|
||||
|
||||
try {
|
||||
final updated = await provider.findTradeById(id: trade.id);
|
||||
trade
|
||||
..stateRaw = updated.state.raw
|
||||
..receiveAmount = updated.receiveAmount ?? trade.receiveAmount
|
||||
..outputTransaction = updated.outputTransaction ?? trade.outputTransaction
|
||||
..userCurrencyToRaw = updated.userCurrencyToRaw
|
||||
..userCurrencyFromRaw = updated.userCurrencyFromRaw;
|
||||
trade.mergeFindTradeByIdResult(updated);
|
||||
printV('Trade ${trade.id} updated: ${trade.state}');
|
||||
await trade.save();
|
||||
|
||||
|
||||
+3
-12
@@ -329,7 +329,6 @@ var _isSetupFinished = false;
|
||||
late Box<Node> _nodeSource;
|
||||
late Box<Node> _powNodeSource;
|
||||
late Box<Contact> _contactSource;
|
||||
late Box<Trade> _tradesSource;
|
||||
late Box<Template> _templates;
|
||||
late Box<ExchangeTemplate> _exchangeTemplates;
|
||||
late Box<TransactionDescription> _transactionDescriptionBox;
|
||||
@@ -341,7 +340,6 @@ Future<void> setup({
|
||||
required Box<Node> nodeSource,
|
||||
required Box<Node> powNodeSource,
|
||||
required Box<Contact> contactSource,
|
||||
required Box<Trade> tradesSource,
|
||||
required Box<Template> templates,
|
||||
required Box<ExchangeTemplate> exchangeTemplates,
|
||||
required Box<TransactionDescription> transactionDescriptionBox,
|
||||
@@ -355,7 +353,6 @@ Future<void> setup({
|
||||
_nodeSource = nodeSource;
|
||||
_powNodeSource = powNodeSource;
|
||||
_contactSource = contactSource;
|
||||
_tradesSource = tradesSource;
|
||||
_templates = templates;
|
||||
_exchangeTemplates = exchangeTemplates;
|
||||
_transactionDescriptionBox = transactionDescriptionBox;
|
||||
@@ -402,7 +399,7 @@ Future<void> setup({
|
||||
nodeListStore: getIt.get<NodeListStore>(),
|
||||
themeStore: getIt.get<ThemeStore>()));
|
||||
getIt.registerSingleton<TradesStore>(
|
||||
TradesStore(tradesSource: _tradesSource, appStore: getIt.get<AppStore>()));
|
||||
TradesStore(appStore: getIt.get<AppStore>()));
|
||||
getIt.registerSingleton<OrdersStore>(
|
||||
OrdersStore(ordersSource: _ordersSource, settingsStore: getIt.get<SettingsStore>()));
|
||||
getIt.registerSingleton<BridgeTransfersStore>(BridgeTransfersStore());
|
||||
@@ -569,7 +566,6 @@ Future<void> setup({
|
||||
getIt.registerFactory(
|
||||
() => ExchangeViewModel(
|
||||
getIt.get<AppStore>(),
|
||||
_tradesSource,
|
||||
getIt.get<ExchangeTemplateStore>(),
|
||||
getIt.get<TradesStore>(),
|
||||
getIt.get<SharedPreferences>(),
|
||||
@@ -583,7 +579,6 @@ Future<void> setup({
|
||||
getIt.registerSingleton(
|
||||
TradeMonitor(
|
||||
tradesStore: getIt.get<TradesStore>(),
|
||||
trades: _tradesSource,
|
||||
appStore: getIt.get<AppStore>(),
|
||||
preferences: getIt.get<SharedPreferences>(),
|
||||
),
|
||||
@@ -1258,7 +1253,6 @@ Future<void> setup({
|
||||
getIt.registerFactory(
|
||||
() => ExchangeTradeViewModel(
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
trades: _tradesSource,
|
||||
tradesStore: getIt.get<TradesStore>(),
|
||||
sendViewModel: getIt.get<SendViewModel>(),
|
||||
feesViewModel: getIt.get<FeesViewModel>(),
|
||||
@@ -1471,11 +1465,8 @@ Future<void> setup({
|
||||
getIt.registerFactoryParam<TransactionSuccessPage, String, void>(
|
||||
(content, _) => TransactionSuccessPage(content: content));
|
||||
|
||||
getIt.registerFactoryParam<TradeDetailsViewModel, Trade, void>((trade, _) =>
|
||||
TradeDetailsViewModel(
|
||||
tradeForDetails: trade,
|
||||
trades: _tradesSource,
|
||||
appStore: getIt.get<AppStore>()));
|
||||
getIt.registerFactoryParam<TradeDetailsViewModel, Trade, void>(
|
||||
(trade, _) => TradeDetailsViewModel(tradeForDetails: trade, appStore: getIt.get<AppStore>()));
|
||||
|
||||
getIt.registerFactory(() => CakeFeaturesViewModel(getIt.get<CakePayService>()));
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import 'package:cake_wallet/entities/haven_seed_store.dart';
|
||||
import 'package:cake_wallet/entities/node_list.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
@@ -64,11 +63,10 @@ Future<void> defaultSettingsMigration(
|
||||
required SecureStorage secureStorage,
|
||||
required Box<Node> nodes,
|
||||
required Box<Node> powNodes,
|
||||
required Box<Trade> tradeSource,
|
||||
required Box<Contact> contactSource,
|
||||
required Box<HavenSeedStore> havenSeedStore}) async {
|
||||
if (Platform.isIOS) {
|
||||
await ios_migrate_v1(tradeSource, contactSource);
|
||||
await ios_migrate_v1(contactSource);
|
||||
}
|
||||
|
||||
// check current nodes for nullability regardless of the version
|
||||
|
||||
@@ -29,7 +29,7 @@ Future<void> migrate_android_v1() async {
|
||||
await android_migrate_wallets(appDocDir: appDocDir);
|
||||
}
|
||||
|
||||
Future<void> ios_migrate_v1(Box<Trade> tradeSource, Box<Contact> contactSource) async {
|
||||
Future<void> ios_migrate_v1(Box<Contact> contactSource) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
if (prefs.getBool('ios_migration_v1_completed') ?? false) {
|
||||
@@ -40,7 +40,7 @@ Future<void> ios_migrate_v1(Box<Trade> tradeSource, Box<Contact> contactSource)
|
||||
await ios_migrate_pin();
|
||||
await ios_migrate_wallet_passwords();
|
||||
await ios_migrate_wallet_info();
|
||||
await ios_migrate_trades_list(tradeSource);
|
||||
await ios_migrate_trades_list();
|
||||
await ios_migrate_address_book(contactSource);
|
||||
|
||||
await prefs.setBool('ios_migration_v1_completed', true);
|
||||
@@ -343,7 +343,7 @@ Future<void> ios_migrate_wallet_info() async {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> ios_migrate_trades_list(Box<Trade> tradeSource) async {
|
||||
Future<void> ios_migrate_trades_list() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
if (prefs.getBool('ios_migration_trade_list_completed') ?? false) {
|
||||
@@ -366,7 +366,8 @@ Future<void> ios_migrate_trades_list(Box<Trade> tradeSource) async {
|
||||
final key = masterPassword!.replaceAll('-', '');
|
||||
final decoded = await ios_legacy_helper.decrypt(content, key: key, salt: secrets.salt);
|
||||
final decodedJson = json.decode(decoded) as List<dynamic>;
|
||||
final trades = decodedJson.map((dynamic el) {
|
||||
|
||||
for (final dynamic el in decodedJson) {
|
||||
final elAsMap = el as Map<String, dynamic>;
|
||||
final providerAsString = elAsMap['provider'] as String;
|
||||
final fromAsString = elAsMap['from'] as String;
|
||||
@@ -393,17 +394,19 @@ Future<void> ios_migrate_trades_list(Box<Trade> tradeSource) async {
|
||||
break;
|
||||
}
|
||||
|
||||
return Trade(
|
||||
if (provider == null) continue;
|
||||
|
||||
await Trade(
|
||||
id: tradeId,
|
||||
provider: provider!,
|
||||
provider: provider,
|
||||
from: from,
|
||||
to: to,
|
||||
createdAt: date,
|
||||
amount: '',
|
||||
receiveAmount: '',
|
||||
);
|
||||
});
|
||||
await tradeSource.addAll(trades);
|
||||
).save();
|
||||
}
|
||||
|
||||
await prefs.setBool('ios_migration_trade_list_completed', true);
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
|
||||
@@ -8,15 +8,13 @@ import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cake_wallet/utils/exchange_provider_logger.dart';
|
||||
|
||||
class ChainflipExchangeProvider extends ExchangeProvider {
|
||||
ChainflipExchangeProvider({required this.tradesStore});
|
||||
ChainflipExchangeProvider();
|
||||
|
||||
static final List<CryptoCurrency> _supported = [
|
||||
CryptoCurrency.btc,
|
||||
@@ -41,8 +39,6 @@ class ChainflipExchangeProvider extends ExchangeProvider {
|
||||
static const _affiliateBps = secrets.chainflipAffiliateFee;
|
||||
static const _affiliateKey = secrets.chainflipApiKey;
|
||||
|
||||
final Box<Trade> tradesStore;
|
||||
|
||||
@override
|
||||
String get title => 'Chainflip';
|
||||
|
||||
@@ -229,19 +225,18 @@ class ChainflipExchangeProvider extends ExchangeProvider {
|
||||
);
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: request.fromCurrency,
|
||||
to: request.toCurrency,
|
||||
provider: description,
|
||||
inputAddress: swapResponse['address'].toString(),
|
||||
createdAt: DateTime.now(),
|
||||
amount: request.fromAmount,
|
||||
receiveAmount: request.toAmount,
|
||||
state: TradeState.waiting,
|
||||
payoutAddress: request.toAddress,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
isSendAll: isSendAll);
|
||||
id: id,
|
||||
from: request.fromCurrency,
|
||||
to: request.toCurrency,
|
||||
provider: description,
|
||||
inputAddress: swapResponse['address'].toString(),
|
||||
createdAt: DateTime.now(),
|
||||
amount: request.fromAmount,
|
||||
receiveAmount: request.toAmount,
|
||||
state: TradeState.waiting,
|
||||
payoutAddress: request.toAddress,
|
||||
isSendAll: isSendAll,
|
||||
);
|
||||
} catch (e, s) {
|
||||
ExchangeProviderLogger.logError(
|
||||
provider: description,
|
||||
@@ -296,29 +291,19 @@ class ChainflipExchangeProvider extends ExchangeProvider {
|
||||
final to = status['destinationAsset'].toString();
|
||||
|
||||
final newTrade = Trade(
|
||||
id: id,
|
||||
from: _toCurrency(status['sourceAsset'].toString()),
|
||||
to: _toCurrency(status['destinationAsset'].toString()),
|
||||
provider: description,
|
||||
amount: depositAmount,
|
||||
receiveAmount: amount,
|
||||
state: currentState,
|
||||
payoutAddress: status['destinationAddress'].toString(),
|
||||
outputTransaction: status['swapEgress']?['transactionReference']?.toString(),
|
||||
isRefund: isRefund,
|
||||
userCurrencyFromRaw: '${from.toUpperCase()}' + '_',
|
||||
userCurrencyToRaw: '${to.toUpperCase()}' + '_',
|
||||
id: id,
|
||||
from: _toCurrency(from),
|
||||
to: _toCurrency(to),
|
||||
provider: description,
|
||||
amount: depositAmount,
|
||||
receiveAmount: amount,
|
||||
state: currentState,
|
||||
payoutAddress: status['destinationAddress'].toString(),
|
||||
outputTransaction:
|
||||
status['swapEgress']?['transactionReference']?.toString(),
|
||||
isRefund: isRefund,
|
||||
);
|
||||
|
||||
// Find trade and update receiveAmount with the real value received
|
||||
final storedTrade = _getStoredTrade(id);
|
||||
|
||||
if (storedTrade != null) {
|
||||
storedTrade.$2.receiveAmount = newTrade.receiveAmount;
|
||||
storedTrade.$2.outputTransaction = newTrade.outputTransaction;
|
||||
tradesStore.put(storedTrade.$1, storedTrade.$2);
|
||||
}
|
||||
|
||||
return newTrade;
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
@@ -368,17 +353,6 @@ class ChainflipExchangeProvider extends ExchangeProvider {
|
||||
return currency;
|
||||
}
|
||||
|
||||
(dynamic, Trade)? _getStoredTrade(String id) {
|
||||
for (var i = tradesStore.length -1; i >= 0; i--) {
|
||||
Trade? t = tradesStore.getAt(i);
|
||||
|
||||
if (t != null && t.id == id)
|
||||
return (i, t);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
String _amountToNative(double amount, CryptoCurrency currency) =>
|
||||
(amount * pow(10, currency.decimals)).toInt().toString();
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/utils/distribution_info.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
@@ -248,8 +247,6 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
receiveAmount: toAmount ?? request.toAmount,
|
||||
state: TradeState.created,
|
||||
payoutAddress: payoutAddress,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
isSendAll: isSendAll,
|
||||
);
|
||||
}
|
||||
@@ -315,9 +312,6 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
expiredAt: expiredAt,
|
||||
outputTransaction: outputTransaction,
|
||||
payoutAddress: payoutAddress,
|
||||
userCurrencyFromRaw:
|
||||
'${fromCurrency.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
|
||||
userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:cake_wallet/exchange/exchange_pair.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
@@ -31,13 +30,12 @@ abstract class ExchangeProvider {
|
||||
|
||||
Future<Trade> findTradeById({required String id});
|
||||
|
||||
Future<double> fetchRate({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount
|
||||
});
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount});
|
||||
|
||||
Future<bool> checkIsAvailable();
|
||||
}
|
||||
|
||||
@@ -314,8 +314,6 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
||||
receiveAmount: receiveAmount ?? request.toAmount,
|
||||
state: TradeState.created,
|
||||
payoutAddress: payoutAddress,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
isSendAll: isSendAll,
|
||||
);
|
||||
}
|
||||
@@ -363,18 +361,16 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
||||
final payoutAddress = responseJSON['withdrawalAddress'] as String;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: from,
|
||||
to: to,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: amount,
|
||||
state: TradeState.deserialize(raw: _prepareStatus(status)),
|
||||
extraId: extraId,
|
||||
outputTransaction: outputTransaction,
|
||||
payoutAddress: payoutAddress,
|
||||
userCurrencyFromRaw: '${coinFrom.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
|
||||
userCurrencyToRaw: '${coinTo.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
|
||||
id: id,
|
||||
from: from,
|
||||
to: to,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: amount,
|
||||
state: TradeState.deserialize(raw: _prepareStatus(status)),
|
||||
extraId: extraId,
|
||||
outputTransaction: outputTransaction,
|
||||
payoutAddress: payoutAddress,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -367,8 +367,6 @@ class JupiterExchangeProvider extends ExchangeProvider {
|
||||
receiveAmount: receiveAmount,
|
||||
payoutAddress: request.toAddress,
|
||||
isSendAll: isSendAll,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? 'SOL'}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? 'SOL'}',
|
||||
routerData: transaction,
|
||||
routerValue: requestId,
|
||||
fee: totalFeeInSol,
|
||||
|
||||
@@ -9,7 +9,6 @@ import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
@@ -76,13 +75,12 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> fetchRate({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount
|
||||
}) async {
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
final networkFrom = _getNetworkType(from);
|
||||
final networkTo = _getNetworkType(to);
|
||||
try {
|
||||
@@ -191,14 +189,13 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
'Authorization': apiKey
|
||||
};
|
||||
|
||||
final uri = Uri.https(_baseUrl,
|
||||
isFixedRateMode ? _createTransactionRevertPath : _createTransactionPath);
|
||||
final uri = Uri.https(
|
||||
_baseUrl, isFixedRateMode ? _createTransactionRevertPath : _createTransactionPath);
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: headers,
|
||||
body: json.encode(tradeParams),
|
||||
);
|
||||
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
ExchangeProviderLogger.logError(
|
||||
@@ -304,8 +301,6 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
createdAt: createdAt,
|
||||
expiredAt: expiredAt,
|
||||
extraId: extraId,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
isSendAll: isSendAll,
|
||||
);
|
||||
} catch (e, s) {
|
||||
@@ -342,7 +337,6 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
|
||||
final url = Uri.https(_baseUrl, '$_getTransactionPath/$id');
|
||||
final response = await ProxyWrapper().get(clearnetUri: url, headers: headers);
|
||||
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('LetsExchange fetch trade failed: ${response.body}');
|
||||
@@ -363,7 +357,6 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
final toTag = toCurrency == normalizedToNetwork ? null : normalizedToNetwork;
|
||||
final to = CryptoCurrency.safeParseCurrencyFromString(toCurrency, tag: toTag);
|
||||
|
||||
|
||||
final payoutAddress = responseJSON['withdrawal'] as String;
|
||||
final depositAddress = responseJSON['deposit'] as String;
|
||||
final refundAddress = responseJSON['return'] as String;
|
||||
@@ -371,15 +364,8 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
final receiveAmount = responseJSON['withdrawal_amount'] as String;
|
||||
final status = responseJSON['status'] as String;
|
||||
|
||||
// We ignore the created_at from response and use DateTime.now() instead
|
||||
final createdAtString = responseJSON['created_at'] as String;
|
||||
final expiredAtTimestamp = responseJSON['expired_at'] as int;
|
||||
|
||||
final extraId = responseJSON['deposit_extra_id'] as String?;
|
||||
|
||||
final createdAt = DateTime.parse(createdAtString).toLocal();
|
||||
final expiredAt = DateTime.fromMillisecondsSinceEpoch(expiredAtTimestamp * 1000).toLocal();
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: from,
|
||||
@@ -393,8 +379,6 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
state: TradeState.deserialize(raw: status),
|
||||
isRefund: status == 'refund',
|
||||
extraId: extraId,
|
||||
userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
|
||||
userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -412,7 +396,7 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
headers: headers,
|
||||
body: json.encode(params),
|
||||
);
|
||||
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('LetsExchange fetch info failed: ${response.body}');
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cw_core/amount_converter.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
@@ -286,10 +285,6 @@ class NearIntentsExchangeProvider extends ExchangeProvider {
|
||||
receiveAmount: quoteObj['amountOutFormatted']?.toString(),
|
||||
memo: depositMemo,
|
||||
isSendAll: isSendAll,
|
||||
userCurrencyFromRaw:
|
||||
'${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw:
|
||||
'${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
|
||||
ExchangeProviderLogger.logSuccess(
|
||||
@@ -415,8 +410,6 @@ class NearIntentsExchangeProvider extends ExchangeProvider {
|
||||
txId: originTxHash,
|
||||
extraId: depositMemo,
|
||||
isRefund: statusRaw == 'REFUNDED',
|
||||
userCurrencyFromRaw: '${from?.$1.toUpperCase()}' + '_' + '${from?.$2?.toUpperCase() ?? ''}',
|
||||
userCurrencyToRaw: '${to?.$1.toUpperCase()}' + '_' + '${to?.$2?.toUpperCase() ?? ''}',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
@@ -337,8 +336,6 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
createdAt: DateTime.now(),
|
||||
isSendAll: isSendAll,
|
||||
extraId: depositMemo,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -377,19 +374,25 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
final expiredAt = isVariable ? null : DateTime.tryParse(expiredAtRaw)?.toLocal();
|
||||
final depositMemo = responseJSON['depositMemo'] as String?;
|
||||
|
||||
final fromParsed = CryptoCurrency.safeParseCurrencyFromString(
|
||||
fromCurrency,
|
||||
tag: fromNetwork,
|
||||
);
|
||||
final toParsed = CryptoCurrency.safeParseCurrencyFromString(
|
||||
toCurrency,
|
||||
tag: toNetwork,
|
||||
);
|
||||
return Trade(
|
||||
id: id,
|
||||
from: CryptoCurrency.safeParseCurrencyFromString(fromCurrency),
|
||||
to: CryptoCurrency.safeParseCurrencyFromString(toCurrency),
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: expectedSendAmount ?? '',
|
||||
state: TradeState.deserialize(raw: status ?? 'created'),
|
||||
expiredAt: expiredAt,
|
||||
payoutAddress: settleAddress,
|
||||
extraId: depositMemo,
|
||||
userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_' + _normalizeNetworkType(fromNetwork ?? ''),
|
||||
userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + _normalizeNetworkType(toNetwork ?? ''),
|
||||
id: id,
|
||||
from: fromParsed,
|
||||
to: toParsed,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: expectedSendAmount ?? '',
|
||||
state: TradeState.deserialize(raw: status ?? 'created'),
|
||||
expiredAt: expiredAt,
|
||||
payoutAddress: settleAddress,
|
||||
extraId: depositMemo,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
@@ -290,8 +289,6 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
||||
payoutAddress: payoutAddress,
|
||||
createdAt: DateTime.now(),
|
||||
isSendAll: isSendAll,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -326,18 +323,19 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
||||
final status = responseJSON['status'] as String;
|
||||
final payoutAddress = responseJSON['address_to'] as String;
|
||||
|
||||
final fromParsed =
|
||||
CryptoCurrency.safeParseCurrencyFromString(fromCurrency);
|
||||
final toParsed = CryptoCurrency.safeParseCurrencyFromString(toCurrency);
|
||||
return Trade(
|
||||
id: id,
|
||||
from: CryptoCurrency.safeParseCurrencyFromString(fromCurrency),
|
||||
to: CryptoCurrency.safeParseCurrencyFromString(toCurrency),
|
||||
from: fromParsed,
|
||||
to: toParsed,
|
||||
extraId: extraId,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: expectedSendAmount,
|
||||
state: TradeState.deserialize(raw: status),
|
||||
payoutAddress: payoutAddress,
|
||||
userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_',
|
||||
userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/utils/exchange_provider_logger.dart';
|
||||
@@ -299,8 +298,6 @@ class StealthExExchangeProvider extends ExchangeProvider {
|
||||
createdAt: createdAt,
|
||||
expiredAt: expiredAt,
|
||||
extraId: extraId,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
isSendAll: isSendAll,
|
||||
);
|
||||
} catch (e, s) {
|
||||
@@ -377,9 +374,6 @@ class StealthExExchangeProvider extends ExchangeProvider {
|
||||
createdAt: createdAt,
|
||||
isRefund: status == 'refunded',
|
||||
extraId: extraId,
|
||||
userCurrencyFromRaw:
|
||||
'${fromCurrency.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
|
||||
userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -407,10 +407,6 @@ class SwapsXyzExchangeProvider extends ExchangeProvider {
|
||||
requiresTokenApproval: requiresTokenApproval,
|
||||
routerData: routerData,
|
||||
routerValue: txValue,
|
||||
userCurrencyFromRaw:
|
||||
'${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw:
|
||||
'${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
|
||||
return trade;
|
||||
@@ -554,8 +550,6 @@ class SwapsXyzExchangeProvider extends ExchangeProvider {
|
||||
state: state,
|
||||
createdAt: createdAt,
|
||||
refundAddress: refundAddress,
|
||||
userCurrencyFromRaw: '${fromSymbol.toUpperCase()}' + '_',
|
||||
userCurrencyToRaw: '${toSymbol.toUpperCase()}' + '_',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -297,8 +297,6 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
|
||||
state: TradeState.created,
|
||||
payoutAddress: request.toAddress,
|
||||
isSendAll: isSendAll,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
} catch (e, s) {
|
||||
ExchangeProviderLogger.logError(
|
||||
@@ -374,8 +372,6 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
|
||||
receiveAmount: expectedReceiveAmount,
|
||||
memo: memo,
|
||||
createdAt: DateTime.tryParse(createdAt ?? ''),
|
||||
userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_',
|
||||
userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_',
|
||||
);
|
||||
} catch (e) {
|
||||
printV("error getting trade: ${e.toString()}");
|
||||
|
||||
@@ -6,15 +6,13 @@ import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cake_wallet/utils/exchange_provider_logger.dart';
|
||||
|
||||
class ThorChainExchangeProvider extends ExchangeProvider {
|
||||
ThorChainExchangeProvider({required this.tradesStore});
|
||||
ThorChainExchangeProvider();
|
||||
|
||||
static final isRefundAddressSupported = [CryptoCurrency.eth];
|
||||
|
||||
@@ -26,8 +24,6 @@ class ThorChainExchangeProvider extends ExchangeProvider {
|
||||
static const _affiliateBps = '175';
|
||||
static const _nameLookUpPath = 'v2/thorname/lookup/';
|
||||
|
||||
final Box<Trade> tradesStore;
|
||||
|
||||
@override
|
||||
String get title => 'THORChain';
|
||||
|
||||
@@ -195,8 +191,6 @@ class ThorChainExchangeProvider extends ExchangeProvider {
|
||||
payoutAddress: request.toAddress,
|
||||
memo: memo,
|
||||
isSendAll: isSendAll,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -254,8 +248,6 @@ class ThorChainExchangeProvider extends ExchangeProvider {
|
||||
state: currentState,
|
||||
memo: memo,
|
||||
isRefund: isRefund,
|
||||
userCurrencyFromRaw: '${tx['chain'] as String? ?? ''}' + '_',
|
||||
userCurrencyToRaw: '$toAsset' + '_',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -392,8 +392,6 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||
payoutAddress: payoutAddress,
|
||||
isSendAll: isSendAll,
|
||||
extraId: addressProviderMemo,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -456,9 +454,6 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||
providerId: providerId,
|
||||
providerName: providerName,
|
||||
extraId: addressProviderMemo,
|
||||
userCurrencyFromRaw:
|
||||
'${fromCurrency.toUpperCase()}' + '_' + '${fromTag?.toUpperCase() ?? ''}',
|
||||
userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_' + '${toTag?.toUpperCase() ?? ''}',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -423,8 +423,6 @@ class XOSwapExchangeProvider extends ExchangeProvider {
|
||||
receiveAmount: receiveAmount.toString(),
|
||||
payoutAddress: payoutAddress,
|
||||
extraId: extraId,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
isSendAll: isSendAll,
|
||||
);
|
||||
} catch (e, s) {
|
||||
@@ -529,14 +527,6 @@ class XOSwapExchangeProvider extends ExchangeProvider {
|
||||
final createdAt = DateTime.parse(createdAtString).toLocal();
|
||||
final extraId = responseJSON['payInAddressTag'] as String?;
|
||||
|
||||
final userCurrencyFromRaw = fromCurrency != null
|
||||
? '${fromCurrency.title}' + '_' + '${fromCurrency.tag ?? ''}'
|
||||
: '${fromAssetBase}' + '_' + '${fromAssetTag ?? ''}';
|
||||
|
||||
final userCurrencyToRaw = toCurrency != null
|
||||
? '${toCurrency.title}' + '_' + '${toCurrency.tag ?? ''}'
|
||||
: '${toAssetBase}' + '_' + '${toAssetTag ?? ''}';
|
||||
|
||||
return Trade(
|
||||
id: orderId,
|
||||
from: fromCurrency,
|
||||
@@ -550,8 +540,6 @@ class XOSwapExchangeProvider extends ExchangeProvider {
|
||||
receiveAmount: receiveAmount,
|
||||
payoutAddress: payoutAddress,
|
||||
extraId: extraId,
|
||||
userCurrencyFromRaw: userCurrencyFromRaw,
|
||||
userCurrencyToRaw: userCurrencyToRaw,
|
||||
);
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
|
||||
+207
-299
@@ -1,19 +1,22 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:cake_wallet/evm/evm.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/db/sqlite.dart';
|
||||
import 'package:cw_core/format_amount.dart';
|
||||
import 'package:cw_core/generate_name.dart';
|
||||
import 'package:cw_core/hive_type_ids.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
class Trade extends HiveObject {
|
||||
class Trade {
|
||||
Trade({
|
||||
this.internalId = 0,
|
||||
required this.id,
|
||||
required this.amount,
|
||||
ExchangeProviderDescription? provider,
|
||||
CryptoCurrency? from,
|
||||
CryptoCurrency? to,
|
||||
this.from,
|
||||
this.to,
|
||||
TradeState? state,
|
||||
this.receiveAmount,
|
||||
this.createdAt,
|
||||
@@ -34,8 +37,6 @@ class Trade extends HiveObject {
|
||||
this.isRefund,
|
||||
this.isSendAll,
|
||||
this.router,
|
||||
this.userCurrencyFromRaw,
|
||||
this.userCurrencyToRaw,
|
||||
// The following fields are used for SwapXyz trades only
|
||||
this.needToRegisterInSwapXyz,
|
||||
this.sourceTokenAddress,
|
||||
@@ -48,364 +49,271 @@ class Trade extends HiveObject {
|
||||
this.chainId,
|
||||
}) {
|
||||
if (provider != null) providerRaw = provider.raw;
|
||||
|
||||
fromRaw = from?.raw ?? -1;
|
||||
toRaw = to?.raw ?? -1;
|
||||
|
||||
if (state != null) stateRaw = state.raw;
|
||||
}
|
||||
|
||||
static const typeId = TRADE_TYPE_ID;
|
||||
static const tableName = 'Trade';
|
||||
static const selfIdColumn = 'tradeId';
|
||||
|
||||
static const boxName = 'Trades';
|
||||
static const boxKey = 'tradesBoxKey';
|
||||
|
||||
@HiveField(0, defaultValue: '')
|
||||
static final StreamController<void> onChanged = StreamController<void>.broadcast();
|
||||
|
||||
int internalId;
|
||||
|
||||
String id;
|
||||
|
||||
@HiveField(1, defaultValue: 0)
|
||||
late int providerRaw;
|
||||
int providerRaw = 0;
|
||||
|
||||
ExchangeProviderDescription get provider =>
|
||||
ExchangeProviderDescription.deserialize(raw: providerRaw);
|
||||
|
||||
@HiveField(2, defaultValue: -1)
|
||||
int fromRaw = -1;
|
||||
CryptoCurrency? from;
|
||||
CryptoCurrency? to;
|
||||
|
||||
CryptoCurrency? get from => CryptoCurrency.safeDeserialize(raw: fromRaw);
|
||||
|
||||
@HiveField(3, defaultValue: -1)
|
||||
int toRaw = -1;
|
||||
|
||||
CryptoCurrency? get to => CryptoCurrency.safeDeserialize(raw: toRaw);
|
||||
|
||||
@HiveField(4, defaultValue: '')
|
||||
late String stateRaw;
|
||||
String stateRaw = '';
|
||||
|
||||
TradeState get state => TradeState.deserialize(raw: stateRaw);
|
||||
|
||||
@HiveField(5)
|
||||
DateTime? createdAt;
|
||||
|
||||
@HiveField(6)
|
||||
DateTime? expiredAt;
|
||||
|
||||
@HiveField(7, defaultValue: '')
|
||||
String amount;
|
||||
|
||||
@HiveField(8)
|
||||
String? receiveAmount;
|
||||
String? inputAddress;
|
||||
|
||||
@HiveField(9)
|
||||
String? extraId;
|
||||
|
||||
@HiveField(10)
|
||||
String? outputTransaction;
|
||||
|
||||
@HiveField(11)
|
||||
String? refundAddress;
|
||||
|
||||
@HiveField(12)
|
||||
String? walletId;
|
||||
|
||||
@HiveField(13)
|
||||
String? payoutAddress;
|
||||
|
||||
@HiveField(14)
|
||||
String? password;
|
||||
|
||||
@HiveField(15)
|
||||
String? providerId;
|
||||
|
||||
@HiveField(16)
|
||||
String? providerName;
|
||||
|
||||
@HiveField(17)
|
||||
String? fromWalletAddress;
|
||||
|
||||
@HiveField(18)
|
||||
String? memo;
|
||||
|
||||
@HiveField(19)
|
||||
String? txId;
|
||||
|
||||
@HiveField(20)
|
||||
bool? isRefund;
|
||||
|
||||
@HiveField(21)
|
||||
bool? isSendAll;
|
||||
|
||||
/// Must be set on createTrade;
|
||||
|
||||
@HiveField(22)
|
||||
String? router;
|
||||
|
||||
@HiveField(23, defaultValue: '')
|
||||
String? receiveAmount;
|
||||
|
||||
@HiveField(24, defaultValue: '')
|
||||
String? userCurrencyFromRaw;
|
||||
|
||||
@HiveField(25, defaultValue: '')
|
||||
String? userCurrencyToRaw;
|
||||
|
||||
// The following fields are used for SwapXyz trades only
|
||||
@HiveField(26)
|
||||
bool? needToRegisterInSwapXyz;
|
||||
|
||||
@HiveField(27)
|
||||
String? sourceTokenAddress;
|
||||
|
||||
@HiveField(28)
|
||||
int? sourceTokenDecimals;
|
||||
|
||||
@HiveField(29)
|
||||
String? routerData;
|
||||
|
||||
@HiveField(30)
|
||||
String? routerValue;
|
||||
|
||||
@HiveField(31)
|
||||
int? routerChainId;
|
||||
|
||||
@HiveField(32)
|
||||
String? sourceTokenAmountRaw;
|
||||
|
||||
@HiveField(33, defaultValue: false)
|
||||
bool? requiresTokenApproval;
|
||||
|
||||
@HiveField(34)
|
||||
int? chainId;
|
||||
|
||||
@HiveField(35)
|
||||
double? fee;
|
||||
|
||||
CryptoCurrency? get userCurrencyFrom {
|
||||
if (userCurrencyFromRaw == null || userCurrencyFromRaw!.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final underscoreIndex = userCurrencyFromRaw!.indexOf('_');
|
||||
final title = userCurrencyFromRaw!.substring(0, underscoreIndex);
|
||||
String tag = userCurrencyFromRaw!.substring(underscoreIndex + 1);
|
||||
|
||||
if (tag.contains('ARB')) tag = 'ARB';
|
||||
|
||||
return CryptoCurrency(
|
||||
title: title,
|
||||
tag: tag.isNotEmpty ? tag : null,
|
||||
name: '',
|
||||
raw: -1,
|
||||
decimals: 1,
|
||||
);
|
||||
}
|
||||
|
||||
CryptoCurrency? get userCurrencyTo {
|
||||
if (userCurrencyToRaw == null || userCurrencyToRaw!.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final underscoreIndex = userCurrencyToRaw!.indexOf('_');
|
||||
final title = userCurrencyToRaw!.substring(0, underscoreIndex);
|
||||
final tag = userCurrencyToRaw!.substring(underscoreIndex + 1);
|
||||
|
||||
return CryptoCurrency(
|
||||
title: title,
|
||||
tag: tag.isNotEmpty ? tag : null,
|
||||
name: '',
|
||||
raw: -1,
|
||||
decimals: 1,
|
||||
);
|
||||
}
|
||||
|
||||
String get chainName {
|
||||
if (chainId == null) return '';
|
||||
|
||||
return evm!.getChainNameByChainId(chainId!).capitalized();
|
||||
}
|
||||
|
||||
static Trade fromMap(Map<String, Object?> map) {
|
||||
return Trade(
|
||||
id: map['id'] as String,
|
||||
provider: ExchangeProviderDescription.deserialize(raw: map['provider'] as int),
|
||||
from: CryptoCurrency.deserialize(raw: map['input'] as int),
|
||||
to: CryptoCurrency.deserialize(raw: map['output'] as int),
|
||||
createdAt:
|
||||
map['date'] != null ? DateTime.fromMillisecondsSinceEpoch(map['date'] as int) : null,
|
||||
amount: map['amount'] as String,
|
||||
receiveAmount: map['receive_amount'] as String?,
|
||||
walletId: map['wallet_id'] as String,
|
||||
fromWalletAddress: map['from_wallet_address'] as String?,
|
||||
memo: map['memo'] as String?,
|
||||
txId: map['tx_id'] as String?,
|
||||
isRefund: map['isRefund'] as bool?,
|
||||
isSendAll: map['isSendAll'] as bool?,
|
||||
router: map['router'] as String?,
|
||||
extraId: map['extra_id'] as String?,
|
||||
chainId: map['chain_id'] as int?,
|
||||
// ── SQLite CRUD ──────────────────────────────────────
|
||||
|
||||
Future<int> save() async {
|
||||
final json = toSqliteMap();
|
||||
if (json[selfIdColumn] == 0) {
|
||||
json[selfIdColumn] = null;
|
||||
}
|
||||
internalId = await db!.insert(
|
||||
tableName,
|
||||
json,
|
||||
conflictAlgorithm: ConflictAlgorithm.replace,
|
||||
);
|
||||
onChanged.add(null);
|
||||
return internalId;
|
||||
}
|
||||
|
||||
static Future<List<Trade>> getAll({String? orderBy}) async {
|
||||
final list = await db!.query(
|
||||
tableName,
|
||||
orderBy: orderBy ?? 'createdAt DESC',
|
||||
);
|
||||
return List.generate(
|
||||
list.length,
|
||||
(i) => Trade.fromSqliteRow(list[i]),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
static Future<Trade?> getByTradeId(String id) async {
|
||||
final list = await db!.query(
|
||||
tableName,
|
||||
where: 'id = ?',
|
||||
whereArgs: [id],
|
||||
limit: 1,
|
||||
);
|
||||
if (list.isEmpty) return null;
|
||||
return Trade.fromSqliteRow(list.first);
|
||||
}
|
||||
|
||||
static Future<int> deleteTrade(Trade trade) async {
|
||||
final rows = await db!.delete(
|
||||
tableName,
|
||||
where: '$selfIdColumn = ?',
|
||||
whereArgs: [trade.internalId],
|
||||
);
|
||||
onChanged.add(null);
|
||||
return rows;
|
||||
}
|
||||
|
||||
// ── SQLite serialization ─────────────────────────────
|
||||
void mergeFindTradeByIdResult(Trade updated) {
|
||||
if (updated.stateRaw.isNotEmpty) stateRaw = updated.stateRaw;
|
||||
if (createdAt == null && updated.createdAt != null) {
|
||||
createdAt = updated.createdAt;
|
||||
}
|
||||
if (updated.expiredAt != null) expiredAt = updated.expiredAt;
|
||||
if (updated.isRefund != null) isRefund = updated.isRefund;
|
||||
|
||||
if (updated.receiveAmount != null) receiveAmount = updated.receiveAmount;
|
||||
if (updated.inputAddress != null) inputAddress = updated.inputAddress;
|
||||
if (updated.extraId != null) extraId = updated.extraId;
|
||||
if (updated.outputTransaction != null) {
|
||||
outputTransaction = updated.outputTransaction;
|
||||
}
|
||||
if (updated.refundAddress != null) refundAddress = updated.refundAddress;
|
||||
if (updated.payoutAddress != null) payoutAddress = updated.payoutAddress;
|
||||
if (updated.password != null) password = updated.password;
|
||||
if (updated.providerId != null) providerId = updated.providerId;
|
||||
if (updated.providerName != null) providerName = updated.providerName;
|
||||
if (updated.memo != null) memo = updated.memo;
|
||||
if (updated.txId != null) txId = updated.txId;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toSqliteMap() {
|
||||
return <String, dynamic>{
|
||||
selfIdColumn: internalId,
|
||||
'id': id,
|
||||
'provider': provider.serialize(),
|
||||
'input': fromRaw,
|
||||
'output': toRaw,
|
||||
'date': createdAt != null ? createdAt!.millisecondsSinceEpoch : null,
|
||||
'providerRaw': providerRaw,
|
||||
'fromTitle': from?.title,
|
||||
'fromName': from?.name,
|
||||
'fromTag': from?.tag,
|
||||
'fromFullName': from?.fullName,
|
||||
'fromDecimals': from?.decimals,
|
||||
'fromRaw': from?.raw,
|
||||
'fromIconPath': from?.iconPath,
|
||||
'fromFlatIconPath': from?.flatIconPath,
|
||||
'fromChainIconPath': from?.chainIconPath,
|
||||
'toTitle': to?.title,
|
||||
'toName': to?.name,
|
||||
'toTag': to?.tag,
|
||||
'toFullName': to?.fullName,
|
||||
'toDecimals': to?.decimals,
|
||||
'toRaw': to?.raw,
|
||||
'toIconPath': to?.iconPath,
|
||||
'toFlatIconPath': to?.flatIconPath,
|
||||
'toChainIconPath': to?.chainIconPath,
|
||||
'stateRaw': stateRaw,
|
||||
'createdAt': createdAt?.millisecondsSinceEpoch,
|
||||
'expiredAt': expiredAt?.millisecondsSinceEpoch,
|
||||
'amount': amount,
|
||||
'receive_amount': receiveAmount,
|
||||
'wallet_id': walletId,
|
||||
'from_wallet_address': fromWalletAddress,
|
||||
'receiveAmount': receiveAmount,
|
||||
'inputAddress': inputAddress,
|
||||
'extraId': extraId,
|
||||
'outputTransaction': outputTransaction,
|
||||
'refundAddress': refundAddress,
|
||||
'walletId': walletId,
|
||||
'payoutAddress': payoutAddress,
|
||||
'password': password,
|
||||
'providerId': providerId,
|
||||
'providerName': providerName,
|
||||
'fromWalletAddress': fromWalletAddress,
|
||||
'memo': memo,
|
||||
'tx_id': txId,
|
||||
'isRefund': isRefund,
|
||||
'isSendAll': isSendAll,
|
||||
'txId': txId,
|
||||
'isRefund': isRefund == true ? 1 : 0,
|
||||
'isSendAll': isSendAll == true ? 1 : 0,
|
||||
'router': router,
|
||||
'extra_id': extraId,
|
||||
'chain_id': chainId,
|
||||
'needToRegisterInSwapXyz': needToRegisterInSwapXyz == true ? 1 : 0,
|
||||
'sourceTokenAddress': sourceTokenAddress,
|
||||
'sourceTokenDecimals': sourceTokenDecimals,
|
||||
'routerData': routerData,
|
||||
'routerValue': routerValue,
|
||||
'routerChainId': routerChainId,
|
||||
'sourceTokenAmountRaw': sourceTokenAmountRaw,
|
||||
'requiresTokenApproval': requiresTokenApproval == true ? 1 : 0,
|
||||
'chainId': chainId,
|
||||
'fee': fee,
|
||||
};
|
||||
}
|
||||
|
||||
factory Trade.fromSqliteRow(Map<String, dynamic> row) {
|
||||
final trade = Trade(
|
||||
id: row['id'] as String? ?? '',
|
||||
amount: row['amount'] as String? ?? '',
|
||||
receiveAmount: row['receiveAmount'] as String?,
|
||||
createdAt: row['createdAt'] != null
|
||||
? DateTime.fromMillisecondsSinceEpoch(
|
||||
row['createdAt'] as int,
|
||||
)
|
||||
: null,
|
||||
expiredAt: row['expiredAt'] != null
|
||||
? DateTime.fromMillisecondsSinceEpoch(
|
||||
row['expiredAt'] as int,
|
||||
)
|
||||
: null,
|
||||
inputAddress: row['inputAddress'] as String?,
|
||||
extraId: row['extraId'] as String?,
|
||||
outputTransaction: row['outputTransaction'] as String?,
|
||||
refundAddress: row['refundAddress'] as String?,
|
||||
walletId: row['walletId'] as String?,
|
||||
payoutAddress: row['payoutAddress'] as String?,
|
||||
password: row['password'] as String?,
|
||||
providerId: row['providerId'] as String?,
|
||||
providerName: row['providerName'] as String?,
|
||||
fromWalletAddress: row['fromWalletAddress'] as String?,
|
||||
memo: row['memo'] as String?,
|
||||
fee: row['fee'] as double?,
|
||||
txId: row['txId'] as String?,
|
||||
isRefund: (row['isRefund'] as int?) == 1,
|
||||
isSendAll: (row['isSendAll'] as int?) == 1,
|
||||
router: row['router'] as String?,
|
||||
from: _currencyFromRow(row, 'from'),
|
||||
to: _currencyFromRow(row, 'to'),
|
||||
needToRegisterInSwapXyz: (row['needToRegisterInSwapXyz'] as int?) == 1,
|
||||
sourceTokenAddress: row['sourceTokenAddress'] as String?,
|
||||
sourceTokenDecimals: row['sourceTokenDecimals'] as int?,
|
||||
routerData: row['routerData'] as String?,
|
||||
routerValue: row['routerValue'] as String?,
|
||||
routerChainId: row['routerChainId'] as int?,
|
||||
sourceTokenAmountRaw: row['sourceTokenAmountRaw'] as String?,
|
||||
requiresTokenApproval: (row['requiresTokenApproval'] as int?) == 1,
|
||||
chainId: row['chainId'] as int?,
|
||||
);
|
||||
trade.internalId = row[selfIdColumn] as int? ?? 0;
|
||||
trade.providerRaw = row['providerRaw'] as int? ?? 0;
|
||||
trade.stateRaw = row['stateRaw'] as String? ?? '';
|
||||
return trade;
|
||||
}
|
||||
|
||||
static CryptoCurrency? _currencyFromRow(Map<String, dynamic> row, String prefix) {
|
||||
final title = row['${prefix}Title'] as String?;
|
||||
if (title == null || title.isEmpty) return null;
|
||||
|
||||
final tag = row['${prefix}Tag'] as String?;
|
||||
|
||||
final live = CryptoCurrency.safeParseCurrencyFromString(title, tag: tag);
|
||||
if (live != null) return live;
|
||||
|
||||
return CryptoCurrency(
|
||||
title: title,
|
||||
name: row['${prefix}Name'] as String? ?? '',
|
||||
tag: tag,
|
||||
fullName: row['${prefix}FullName'] as String?,
|
||||
decimals: row['${prefix}Decimals'] as int? ?? 1,
|
||||
raw: row['${prefix}Raw'] as int? ?? -1,
|
||||
iconPath: row['${prefix}IconPath'] as String?,
|
||||
flatIconPath: row['${prefix}FlatIconPath'] as String?,
|
||||
chainIconPath: row['${prefix}ChainIconPath'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
String amountFormatted() => formatAmount(amount);
|
||||
String receiveAmountFormatted() => formatAmount(receiveAmount ?? '');
|
||||
}
|
||||
|
||||
class TradeAdapter extends TypeAdapter<Trade> {
|
||||
@override
|
||||
final int typeId = Trade.typeId;
|
||||
|
||||
@override
|
||||
Trade read(BinaryReader reader) {
|
||||
final numOfFields = reader.readByte();
|
||||
final fields = <int, dynamic>{};
|
||||
for (int i = 0; i < numOfFields; i++) {
|
||||
try {
|
||||
fields[reader.readByte()] = reader.read();
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
return Trade(
|
||||
id: fields[0] == null ? '' : fields[0] as String,
|
||||
amount: fields[7] == null ? '' : fields[7] as String,
|
||||
receiveAmount: fields[23] as String?,
|
||||
createdAt: fields[5] as DateTime?,
|
||||
expiredAt: fields[6] as DateTime?,
|
||||
inputAddress: fields[8] as String?,
|
||||
extraId: fields[9] as String?,
|
||||
outputTransaction: fields[10] as String?,
|
||||
refundAddress: fields[11] as String?,
|
||||
walletId: fields[12] as String?,
|
||||
payoutAddress: fields[13] as String?,
|
||||
password: fields[14] as String?,
|
||||
providerId: fields[15] as String?,
|
||||
providerName: fields[16] as String?,
|
||||
fromWalletAddress: fields[17] as String?,
|
||||
memo: fields[18] as String?,
|
||||
txId: fields[19] as String?,
|
||||
isRefund: fields[20] as bool?,
|
||||
isSendAll: fields[21] as bool?,
|
||||
router: fields[22] as String?,
|
||||
userCurrencyFromRaw: fields[24] as String?,
|
||||
userCurrencyToRaw: fields[25] as String?,
|
||||
needToRegisterInSwapXyz: fields[26] as bool?,
|
||||
sourceTokenAddress: fields[27] as String?,
|
||||
sourceTokenDecimals: fields[28] as int?,
|
||||
routerData: fields[29] as String?,
|
||||
routerValue: fields[30] as String?,
|
||||
routerChainId: fields[31] as int?,
|
||||
sourceTokenAmountRaw: fields[32] as String?,
|
||||
requiresTokenApproval: fields[33] as bool?,
|
||||
chainId: fields[34] as int?,
|
||||
fee: fields[35] as double?,
|
||||
)
|
||||
..providerRaw = fields[1] == null ? 0 : fields[1] as int
|
||||
..fromRaw = (fields[2] as int?) ?? -1
|
||||
..toRaw = (fields[3] as int?) ?? -1
|
||||
..stateRaw = fields[4] == null ? '' : fields[4] as String;
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, Trade obj) {
|
||||
writer
|
||||
..writeByte(26)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
..write(obj.providerRaw)
|
||||
..writeByte(2)
|
||||
..write(obj.fromRaw)
|
||||
..writeByte(3)
|
||||
..write(obj.toRaw)
|
||||
..writeByte(4)
|
||||
..write(obj.stateRaw)
|
||||
..writeByte(5)
|
||||
..write(obj.createdAt)
|
||||
..writeByte(6)
|
||||
..write(obj.expiredAt)
|
||||
..writeByte(7)
|
||||
..write(obj.amount)
|
||||
..writeByte(8)
|
||||
..write(obj.inputAddress)
|
||||
..writeByte(9)
|
||||
..write(obj.extraId)
|
||||
..writeByte(10)
|
||||
..write(obj.outputTransaction)
|
||||
..writeByte(11)
|
||||
..write(obj.refundAddress)
|
||||
..writeByte(12)
|
||||
..write(obj.walletId)
|
||||
..writeByte(13)
|
||||
..write(obj.payoutAddress)
|
||||
..writeByte(14)
|
||||
..write(obj.password)
|
||||
..writeByte(15)
|
||||
..write(obj.providerId)
|
||||
..writeByte(16)
|
||||
..write(obj.providerName)
|
||||
..writeByte(17)
|
||||
..write(obj.fromWalletAddress)
|
||||
..writeByte(18)
|
||||
..write(obj.memo)
|
||||
..writeByte(19)
|
||||
..write(obj.txId)
|
||||
..writeByte(20)
|
||||
..write(obj.isRefund)
|
||||
..writeByte(21)
|
||||
..write(obj.isSendAll)
|
||||
..writeByte(22)
|
||||
..write(obj.router)
|
||||
..writeByte(23)
|
||||
..write(obj.receiveAmount)
|
||||
..writeByte(24)
|
||||
..write(obj.userCurrencyFromRaw)
|
||||
..writeByte(25)
|
||||
..write(obj.userCurrencyToRaw)
|
||||
..writeByte(26)
|
||||
..write(obj.needToRegisterInSwapXyz)
|
||||
..writeByte(27)
|
||||
..write(obj.sourceTokenAddress)
|
||||
..writeByte(28)
|
||||
..write(obj.sourceTokenDecimals)
|
||||
..writeByte(29)
|
||||
..write(obj.routerData)
|
||||
..writeByte(30)
|
||||
..write(obj.routerValue)
|
||||
..writeByte(31)
|
||||
..write(obj.routerChainId)
|
||||
..writeByte(32)
|
||||
..write(obj.sourceTokenAmountRaw)
|
||||
..writeByte(33)
|
||||
..write(obj.requiresTokenApproval)
|
||||
..writeByte(34)
|
||||
..write(obj.chainId)
|
||||
..writeByte(35)
|
||||
..write(obj.fee);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is TradeAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class TradeCurrencySnapshot {
|
||||
TradeCurrencySnapshot._();
|
||||
|
||||
static CryptoCurrency? fromLegacyHive({
|
||||
required int raw,
|
||||
String? displayTitleTag,
|
||||
}) {
|
||||
if (raw >= 0) {
|
||||
final curr = CryptoCurrency.safeDeserialize(raw: raw);
|
||||
if (curr != null) return curr;
|
||||
}
|
||||
|
||||
return _parseLegacyTitleTag(displayTitleTag);
|
||||
}
|
||||
|
||||
static CryptoCurrency? _parseLegacyTitleTag(String? titleTag) {
|
||||
if (titleTag == null || titleTag.isEmpty) return null;
|
||||
|
||||
final idx = titleTag.indexOf('_');
|
||||
if (idx < 0) {
|
||||
return CryptoCurrency(
|
||||
title: titleTag,
|
||||
name: '',
|
||||
raw: -1,
|
||||
decimals: 1,
|
||||
);
|
||||
}
|
||||
|
||||
final title = titleTag.substring(0, idx);
|
||||
|
||||
var tag = titleTag.substring(idx + 1);
|
||||
|
||||
if (tag.contains('ARB')) tag = 'ARB';
|
||||
|
||||
return CryptoCurrency(
|
||||
title: title,
|
||||
tag: tag.isNotEmpty ? tag : null,
|
||||
name: '',
|
||||
raw: -1,
|
||||
decimals: 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
import 'package:cake_wallet/core/secure_storage.dart';
|
||||
import 'package:cake_wallet/entities/get_encryption_key.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_currency_snapshot.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cw_core/cake_hive.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/hive_type_ids.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
part 'trade_legacy.part.dart';
|
||||
|
||||
Future<void> performTradeHiveMigration(SecureStorage secureStorage) async {
|
||||
try {
|
||||
if (!CakeHive.isAdapterRegistered(TradeLegacy.typeId)) {
|
||||
CakeHive.registerAdapter(TradeLegacyAdapter());
|
||||
}
|
||||
final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
|
||||
final box = await CakeHive.openBox<TradeLegacy>(Trade.boxName, encryptionKey: tradesBoxKey);
|
||||
await TradeLegacy.migrateAllToSqlite(box);
|
||||
} catch (e) {
|
||||
printV('Trade Hive migration error: $e');
|
||||
}
|
||||
}
|
||||
|
||||
class TradeLegacy extends HiveObject {
|
||||
TradeLegacy({
|
||||
required this.id,
|
||||
required this.amount,
|
||||
ExchangeProviderDescription? provider,
|
||||
CryptoCurrency? from,
|
||||
CryptoCurrency? to,
|
||||
TradeState? state,
|
||||
this.receiveAmount,
|
||||
this.createdAt,
|
||||
this.expiredAt,
|
||||
this.inputAddress,
|
||||
this.extraId,
|
||||
this.outputTransaction,
|
||||
this.refundAddress,
|
||||
this.walletId,
|
||||
this.payoutAddress,
|
||||
this.password,
|
||||
this.providerId,
|
||||
this.providerName,
|
||||
this.fromWalletAddress,
|
||||
this.memo,
|
||||
this.fee,
|
||||
this.txId,
|
||||
this.isRefund,
|
||||
this.isSendAll,
|
||||
this.router,
|
||||
this.userCurrencyFromRaw,
|
||||
this.userCurrencyToRaw,
|
||||
this.needToRegisterInSwapXyz,
|
||||
this.sourceTokenAddress,
|
||||
this.sourceTokenDecimals,
|
||||
this.routerData,
|
||||
this.routerValue,
|
||||
this.routerChainId,
|
||||
this.sourceTokenAmountRaw,
|
||||
this.requiresTokenApproval,
|
||||
this.chainId,
|
||||
}) {
|
||||
if (provider != null) providerRaw = provider.raw;
|
||||
fromRaw = from?.raw ?? -1;
|
||||
toRaw = to?.raw ?? -1;
|
||||
if (state != null) stateRaw = state.raw;
|
||||
}
|
||||
|
||||
static const typeId = TRADE_TYPE_ID;
|
||||
|
||||
String id;
|
||||
late int providerRaw;
|
||||
int fromRaw = -1;
|
||||
int toRaw = -1;
|
||||
late String stateRaw;
|
||||
DateTime? createdAt;
|
||||
DateTime? expiredAt;
|
||||
String amount;
|
||||
String? receiveAmount;
|
||||
String? inputAddress;
|
||||
String? extraId;
|
||||
String? outputTransaction;
|
||||
String? refundAddress;
|
||||
String? walletId;
|
||||
String? payoutAddress;
|
||||
String? password;
|
||||
String? providerId;
|
||||
String? providerName;
|
||||
String? fromWalletAddress;
|
||||
String? memo;
|
||||
String? txId;
|
||||
bool? isRefund;
|
||||
bool? isSendAll;
|
||||
String? router;
|
||||
String? userCurrencyFromRaw;
|
||||
String? userCurrencyToRaw;
|
||||
bool? needToRegisterInSwapXyz;
|
||||
String? sourceTokenAddress;
|
||||
int? sourceTokenDecimals;
|
||||
String? routerData;
|
||||
String? routerValue;
|
||||
int? routerChainId;
|
||||
String? sourceTokenAmountRaw;
|
||||
bool? requiresTokenApproval;
|
||||
int? chainId;
|
||||
double? fee;
|
||||
|
||||
Future<void> migrateToSqlite() async {
|
||||
final trade = Trade(
|
||||
id: id,
|
||||
amount: amount,
|
||||
receiveAmount: receiveAmount,
|
||||
createdAt: createdAt,
|
||||
expiredAt: expiredAt,
|
||||
inputAddress: inputAddress,
|
||||
extraId: extraId,
|
||||
outputTransaction: outputTransaction,
|
||||
refundAddress: refundAddress,
|
||||
walletId: walletId,
|
||||
payoutAddress: payoutAddress,
|
||||
password: password,
|
||||
providerId: providerId,
|
||||
providerName: providerName,
|
||||
fromWalletAddress: fromWalletAddress,
|
||||
memo: memo,
|
||||
fee: fee,
|
||||
txId: txId,
|
||||
isRefund: isRefund,
|
||||
isSendAll: isSendAll,
|
||||
router: router,
|
||||
from:
|
||||
TradeCurrencySnapshot.fromLegacyHive(raw: fromRaw, displayTitleTag: userCurrencyFromRaw),
|
||||
to: TradeCurrencySnapshot.fromLegacyHive(raw: toRaw, displayTitleTag: userCurrencyToRaw),
|
||||
needToRegisterInSwapXyz: needToRegisterInSwapXyz,
|
||||
sourceTokenAddress: sourceTokenAddress,
|
||||
sourceTokenDecimals: sourceTokenDecimals,
|
||||
routerData: routerData,
|
||||
routerValue: routerValue,
|
||||
routerChainId: routerChainId,
|
||||
sourceTokenAmountRaw: sourceTokenAmountRaw,
|
||||
requiresTokenApproval: requiresTokenApproval,
|
||||
chainId: chainId,
|
||||
);
|
||||
trade.providerRaw = providerRaw;
|
||||
trade.stateRaw = stateRaw;
|
||||
await trade.save();
|
||||
}
|
||||
|
||||
static Future<void> migrateAllToSqlite(
|
||||
Box<TradeLegacy> box,
|
||||
) async {
|
||||
printV('Migrating Trades to SQLite: start');
|
||||
final list = box.values.toList();
|
||||
for (final trade in list) {
|
||||
try {
|
||||
await trade.migrateToSqlite();
|
||||
await trade.delete();
|
||||
} catch (e) {
|
||||
printV('Error migrating trade ${trade.id}: $e');
|
||||
}
|
||||
}
|
||||
printV('Migrating Trades to SQLite: end');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
part of 'trade_legacy.dart';
|
||||
|
||||
class TradeLegacyAdapter extends TypeAdapter<TradeLegacy> {
|
||||
@override
|
||||
final int typeId = TradeLegacy.typeId;
|
||||
|
||||
@override
|
||||
TradeLegacy read(BinaryReader reader) {
|
||||
final numOfFields = reader.readByte();
|
||||
final fields = <int, dynamic>{};
|
||||
for (int i = 0; i < numOfFields; i++) {
|
||||
try {
|
||||
fields[reader.readByte()] = reader.read();
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
return TradeLegacy(
|
||||
id: fields[0] == null ? '' : fields[0] as String,
|
||||
amount: fields[7] == null ? '' : fields[7] as String,
|
||||
receiveAmount: fields[23] as String?,
|
||||
createdAt: fields[5] as DateTime?,
|
||||
expiredAt: fields[6] as DateTime?,
|
||||
inputAddress: fields[8] as String?,
|
||||
extraId: fields[9] as String?,
|
||||
outputTransaction: fields[10] as String?,
|
||||
refundAddress: fields[11] as String?,
|
||||
walletId: fields[12] as String?,
|
||||
payoutAddress: fields[13] as String?,
|
||||
password: fields[14] as String?,
|
||||
providerId: fields[15] as String?,
|
||||
providerName: fields[16] as String?,
|
||||
fromWalletAddress: fields[17] as String?,
|
||||
memo: fields[18] as String?,
|
||||
txId: fields[19] as String?,
|
||||
isRefund: fields[20] as bool?,
|
||||
isSendAll: fields[21] as bool?,
|
||||
router: fields[22] as String?,
|
||||
userCurrencyFromRaw: fields[24] as String?,
|
||||
userCurrencyToRaw: fields[25] as String?,
|
||||
needToRegisterInSwapXyz: fields[26] as bool?,
|
||||
sourceTokenAddress: fields[27] as String?,
|
||||
sourceTokenDecimals: fields[28] as int?,
|
||||
routerData: fields[29] as String?,
|
||||
routerValue: fields[30] as String?,
|
||||
routerChainId: fields[31] as int?,
|
||||
sourceTokenAmountRaw: fields[32] as String?,
|
||||
requiresTokenApproval: fields[33] as bool?,
|
||||
chainId: fields[34] as int?,
|
||||
fee: fields[35] as double?,
|
||||
)
|
||||
..providerRaw =
|
||||
fields[1] == null ? 0 : fields[1] as int
|
||||
..fromRaw = (fields[2] as int?) ?? -1
|
||||
..toRaw = (fields[3] as int?) ?? -1
|
||||
..stateRaw =
|
||||
fields[4] == null ? '' : fields[4] as String;
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, TradeLegacy obj) {
|
||||
writer
|
||||
..writeByte(36)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
..write(obj.providerRaw)
|
||||
..writeByte(2)
|
||||
..write(obj.fromRaw)
|
||||
..writeByte(3)
|
||||
..write(obj.toRaw)
|
||||
..writeByte(4)
|
||||
..write(obj.stateRaw)
|
||||
..writeByte(5)
|
||||
..write(obj.createdAt)
|
||||
..writeByte(6)
|
||||
..write(obj.expiredAt)
|
||||
..writeByte(7)
|
||||
..write(obj.amount)
|
||||
..writeByte(8)
|
||||
..write(obj.inputAddress)
|
||||
..writeByte(9)
|
||||
..write(obj.extraId)
|
||||
..writeByte(10)
|
||||
..write(obj.outputTransaction)
|
||||
..writeByte(11)
|
||||
..write(obj.refundAddress)
|
||||
..writeByte(12)
|
||||
..write(obj.walletId)
|
||||
..writeByte(13)
|
||||
..write(obj.payoutAddress)
|
||||
..writeByte(14)
|
||||
..write(obj.password)
|
||||
..writeByte(15)
|
||||
..write(obj.providerId)
|
||||
..writeByte(16)
|
||||
..write(obj.providerName)
|
||||
..writeByte(17)
|
||||
..write(obj.fromWalletAddress)
|
||||
..writeByte(18)
|
||||
..write(obj.memo)
|
||||
..writeByte(19)
|
||||
..write(obj.txId)
|
||||
..writeByte(20)
|
||||
..write(obj.isRefund)
|
||||
..writeByte(21)
|
||||
..write(obj.isSendAll)
|
||||
..writeByte(22)
|
||||
..write(obj.router)
|
||||
..writeByte(23)
|
||||
..write(obj.receiveAmount)
|
||||
..writeByte(24)
|
||||
..write(obj.userCurrencyFromRaw)
|
||||
..writeByte(25)
|
||||
..write(obj.userCurrencyToRaw)
|
||||
..writeByte(26)
|
||||
..write(obj.needToRegisterInSwapXyz)
|
||||
..writeByte(27)
|
||||
..write(obj.sourceTokenAddress)
|
||||
..writeByte(28)
|
||||
..write(obj.sourceTokenDecimals)
|
||||
..writeByte(29)
|
||||
..write(obj.routerData)
|
||||
..writeByte(30)
|
||||
..write(obj.routerValue)
|
||||
..writeByte(31)
|
||||
..write(obj.routerChainId)
|
||||
..writeByte(32)
|
||||
..write(obj.sourceTokenAmountRaw)
|
||||
..writeByte(33)
|
||||
..write(obj.requiresTokenApproval)
|
||||
..writeByte(34)
|
||||
..write(obj.chainId)
|
||||
..writeByte(35)
|
||||
..write(obj.fee);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is TradeLegacyAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
||||
+11
-20
@@ -19,7 +19,7 @@ import 'package:cake_wallet/entities/language_service.dart';
|
||||
import 'package:cake_wallet/entities/template.dart';
|
||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_template.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_legacy.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/locales/locale.dart';
|
||||
import 'package:cake_wallet/order/order.dart';
|
||||
@@ -37,7 +37,6 @@ import 'package:cake_wallet/utils/exception_handler.dart';
|
||||
import 'package:cake_wallet/utils/feature_flag.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/zcash/zcash.dart';
|
||||
import 'package:cw_core/address_info.dart';
|
||||
import 'package:cw_core/cake_hive.dart';
|
||||
@@ -65,7 +64,6 @@ import 'package:flutter/services.dart';
|
||||
import 'package:flutter_daemon/flutter_daemon.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cw_core/root_dir.dart';
|
||||
import 'package:quick_actions/quick_actions.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
@@ -230,10 +228,6 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
|
||||
CakeHive.registerAdapter(TransactionDescriptionAdapter());
|
||||
}
|
||||
|
||||
if (!CakeHive.isAdapterRegistered(Trade.typeId)) {
|
||||
CakeHive.registerAdapter(TradeAdapter());
|
||||
}
|
||||
|
||||
if (!CakeHive.isAdapterRegistered(AddressInfo.typeId)) {
|
||||
CakeHive.registerAdapter(AddressInfoAdapter());
|
||||
}
|
||||
@@ -290,7 +284,6 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
|
||||
final secureStorage = secureStorageShared;
|
||||
final transactionDescriptionsBoxKey =
|
||||
await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
|
||||
final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
|
||||
final ordersBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Order.boxKey);
|
||||
final contacts = await CakeHive.openBox<Contact>(Contact.boxName);
|
||||
final nodes = await CakeHive.openBox<Node>(Node.boxName);
|
||||
@@ -299,7 +292,8 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
|
||||
final transactionDescriptions = await CakeHive.openBox<TransactionDescription>(
|
||||
TransactionDescription.boxName,
|
||||
encryptionKey: transactionDescriptionsBoxKey);
|
||||
final trades = await CakeHive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
|
||||
await performTradeHiveMigration(secureStorage);
|
||||
|
||||
final orders = await CakeHive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
|
||||
final templates = await CakeHive.openBox<Template>(Template.boxName);
|
||||
final exchangeTemplates = await CakeHive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
|
||||
@@ -318,7 +312,6 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
|
||||
nodes: nodes,
|
||||
powNodes: powNodes,
|
||||
contactSource: contacts,
|
||||
tradesSource: trades,
|
||||
ordersSource: orders,
|
||||
unspentCoinsInfoSource: unspentCoinsInfoSource,
|
||||
// fiatConvertationService: fiatConvertationService,
|
||||
@@ -339,7 +332,6 @@ Future<void> initialSetup({
|
||||
required Box<Node> nodes,
|
||||
required Box<Node> powNodes,
|
||||
required Box<Contact> contactSource,
|
||||
required Box<Trade> tradesSource,
|
||||
required Box<Order> ordersSource,
|
||||
// required FiatConvertationService fiatConvertationService,
|
||||
required Box<Template> templates,
|
||||
@@ -354,19 +346,18 @@ Future<void> initialSetup({
|
||||
}) async {
|
||||
LanguageService.loadLocaleList();
|
||||
await defaultSettingsMigration(
|
||||
secureStorage: secureStorage,
|
||||
version: initialMigrationVersion,
|
||||
sharedPreferences: sharedPreferences,
|
||||
contactSource: contactSource,
|
||||
tradeSource: tradesSource,
|
||||
nodes: nodes,
|
||||
powNodes: powNodes,
|
||||
havenSeedStore: havenSeedStore);
|
||||
secureStorage: secureStorage,
|
||||
version: initialMigrationVersion,
|
||||
sharedPreferences: sharedPreferences,
|
||||
contactSource: contactSource,
|
||||
nodes: nodes,
|
||||
powNodes: powNodes,
|
||||
havenSeedStore: havenSeedStore,
|
||||
);
|
||||
await setup(
|
||||
nodeSource: nodes,
|
||||
powNodeSource: powNodes,
|
||||
contactSource: contactSource,
|
||||
tradesSource: tradesSource,
|
||||
ordersSource: ordersSource,
|
||||
templates: templates,
|
||||
exchangeTemplates: exchangeTemplates,
|
||||
|
||||
@@ -35,13 +35,15 @@ class HistorySection extends StatelessWidget {
|
||||
? SliverPadding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: (dashboardViewModel.status is SyncingSyncStatus) ? SizedBox.shrink() : Center(
|
||||
child: Text(S.of(context).transactions_will_appear_here,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant)),
|
||||
),
|
||||
child: (dashboardViewModel.status is SyncingSyncStatus)
|
||||
? SizedBox.shrink()
|
||||
: Center(
|
||||
child: Text(S.of(context).transactions_will_appear_here,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant)),
|
||||
),
|
||||
),
|
||||
)
|
||||
: SliverList(
|
||||
@@ -51,136 +53,147 @@ class HistorySection extends StatelessWidget {
|
||||
final prevItem = index == 0 ? null : dashboardViewModel.items[index - 1];
|
||||
final topPadding = index == 0 ? 0.0 : 18.0;
|
||||
final item = dashboardViewModel.items[index];
|
||||
final nextItem = index == dashboardViewModel.items.length - 1
|
||||
? null
|
||||
: dashboardViewModel.items[index + 1];
|
||||
final nextItem = index == dashboardViewModel.items.length - 1
|
||||
? null
|
||||
: dashboardViewModel.items[index + 1];
|
||||
|
||||
final roundedBottom = (nextItem == null || nextItem is DateSectionItem);
|
||||
final roundedTop = (prevItem == null || prevItem is DateSectionItem);
|
||||
final roundedBottom = (nextItem == null || nextItem is DateSectionItem);
|
||||
final roundedTop = (prevItem == null || prevItem is DateSectionItem);
|
||||
|
||||
if (item is TransactionListItem) {
|
||||
final transaction = item.transaction;
|
||||
final transactionType = dashboardViewModel.getTransactionType(transaction);
|
||||
if (item is TransactionListItem) {
|
||||
final transaction = item.transaction;
|
||||
final transactionType = dashboardViewModel.getTransactionType(transaction);
|
||||
|
||||
if (item.hasTokens && item.assetOfTransaction == null) {
|
||||
return Container();
|
||||
}
|
||||
if (item.hasTokens && item.assetOfTransaction == null) {
|
||||
return Container();
|
||||
}
|
||||
|
||||
CryptoCurrency? asset;
|
||||
if (transaction.additionalInfo["isLightning"] == true)
|
||||
asset = CryptoCurrency.btcln;
|
||||
else
|
||||
asset = item.assetOfTransaction;
|
||||
CryptoCurrency? asset;
|
||||
if (transaction.additionalInfo["isLightning"] == true)
|
||||
asset = CryptoCurrency.btcln;
|
||||
else
|
||||
asset = item.assetOfTransaction;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
final page = getIt.get<TransactionDetailsModal>(param1: transaction);
|
||||
showModalBottomSheet(isScrollControlled:true,context: context, builder: (context) => page);
|
||||
},
|
||||
child: HistoryTile(
|
||||
title: item.formattedTitle + transactionType,
|
||||
date: DateFormat('HH:mm').format(transaction.date),
|
||||
amount: item.formattedCryptoAmount,
|
||||
amountFiat: item.formattedFiatAmount,
|
||||
hasTokens: item.hasTokens,
|
||||
chainIconPath: _getChainIconPath(),
|
||||
roundedBottom: roundedBottom,
|
||||
roundedTop: roundedTop,
|
||||
bottomSeparator: !roundedBottom,
|
||||
direction: item.transaction.direction,
|
||||
pending: item.transaction.isPending,
|
||||
asset: asset,
|
||||
),
|
||||
);
|
||||
} else if (item is TradeListItem) {
|
||||
final trade = item.trade;
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
final page = getIt.get<TransactionDetailsModal>(param1: transaction);
|
||||
showModalBottomSheet(
|
||||
isScrollControlled: true,
|
||||
context: context,
|
||||
builder: (context) => page);
|
||||
},
|
||||
child: HistoryTile(
|
||||
title: item.formattedTitle + transactionType,
|
||||
date: DateFormat('HH:mm').format(transaction.date),
|
||||
amount: item.formattedCryptoAmount,
|
||||
amountFiat: item.formattedFiatAmount,
|
||||
hasTokens: item.hasTokens,
|
||||
chainIconPath: _getChainIconPath(),
|
||||
roundedBottom: roundedBottom,
|
||||
roundedTop: roundedTop,
|
||||
bottomSeparator: !roundedBottom,
|
||||
direction: item.transaction.direction,
|
||||
pending: item.transaction.isPending,
|
||||
asset: asset,
|
||||
),
|
||||
);
|
||||
} else if (item is TradeListItem) {
|
||||
final trade = item.trade;
|
||||
final tradeFrom = trade.from;
|
||||
final tradeTo = trade.to;
|
||||
if (tradeFrom == null || tradeTo == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
final tradeFrom = trade.fromRaw >= 0 ? trade.from : trade.userCurrencyFrom;
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.tradeDetails, arguments: trade),
|
||||
child: HistoryTradeTile(
|
||||
from: tradeFrom,
|
||||
to: tradeTo,
|
||||
provider: trade.provider,
|
||||
date:
|
||||
DateFormat('HH:mm').format(item.trade.createdAt ?? DateTime.now()),
|
||||
amount: trade.amountFormatted(),
|
||||
receiveAmount: trade.receiveAmountFormatted(),
|
||||
roundedBottom: roundedBottom,
|
||||
roundedTop: roundedTop,
|
||||
bottomSeparator: !roundedBottom,
|
||||
swapState: trade.state,
|
||||
),
|
||||
);
|
||||
} else if (item is DateSectionItem) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(left: 8.0, bottom: 8.0, top: topPadding),
|
||||
child: Text(DateFormatter.convertDateTimeToReadableString(item.date),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant)));
|
||||
} else if (item is OrderListItem) {
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.orderDetails, arguments: item.order),
|
||||
child: HistoryOrderTile(
|
||||
date: DateFormat('HH:mm').format(item.order.createdAt),
|
||||
amount: item.orderFormattedAmount,
|
||||
amountFiat: "USD 0.00",
|
||||
roundedBottom: roundedBottom,
|
||||
roundedTop: roundedTop,
|
||||
bottomSeparator: !roundedBottom,
|
||||
),
|
||||
);
|
||||
} else if (item is PayjoinTransactionListItem) {
|
||||
final session = item.session;
|
||||
|
||||
final tradeTo = trade.toRaw >= 0 ? trade.to : trade.userCurrencyTo;
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.payjoinDetails,
|
||||
arguments: [item.sessionId, item.transaction],
|
||||
),
|
||||
child: PayjoinHistoryTile(
|
||||
createdAt: DateFormat('HH:mm').format(session.inProgressSince!),
|
||||
amount: dashboardViewModel.appStore.amountParsingProxy
|
||||
.getDisplayCryptoString(
|
||||
session.amount.toInt(), CryptoCurrency.btc),
|
||||
currency: item.transaction?.from ?? "BTC",
|
||||
state: item.status,
|
||||
isSending: session.isSenderSession,
|
||||
roundedTop: roundedTop,
|
||||
roundedBottom: roundedBottom,
|
||||
bottomSeparator: !roundedBottom),
|
||||
);
|
||||
} else if (item is AnonpayTransactionListItem) {
|
||||
final transactionInfo = item.transaction;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.tradeDetails, arguments: trade),
|
||||
child: HistoryTradeTile(
|
||||
from: tradeFrom!,
|
||||
to: tradeTo!,
|
||||
provider: trade.provider,
|
||||
date: DateFormat('HH:mm').format(item.trade.createdAt!),
|
||||
amount: trade.amountFormatted(),
|
||||
receiveAmount: trade.receiveAmountFormatted(),
|
||||
roundedBottom: roundedBottom,
|
||||
roundedTop: roundedTop,
|
||||
bottomSeparator: !roundedBottom,
|
||||
swapState: trade.state,
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.anonPayDetailsPage, arguments: transactionInfo),
|
||||
child: AnonpayHistoryTile(
|
||||
provider: transactionInfo.provider,
|
||||
createdAt: DateFormat('HH:mm').format(transactionInfo.createdAt),
|
||||
amount: transactionInfo.fiatAmount?.toString() ??
|
||||
(transactionInfo.amountTo?.toString() ?? ''),
|
||||
currency: transactionInfo.fiatAmount != null
|
||||
? transactionInfo.fiatEquiv ?? ''
|
||||
: CryptoCurrency.fromFullName(transactionInfo.coinTo)
|
||||
.name
|
||||
.toUpperCase(),
|
||||
roundedTop: roundedTop,
|
||||
roundedBottom: roundedBottom,
|
||||
bottomSeparator: !roundedBottom));
|
||||
} else
|
||||
return Text(item.runtimeType.toString());
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (item is DateSectionItem) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(left: 8.0, bottom: 8.0, top: topPadding),
|
||||
child: Text(DateFormatter.convertDateTimeToReadableString(item.date),
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)));
|
||||
}else if(item is OrderListItem){
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.orderDetails, arguments: item.order),
|
||||
child: HistoryOrderTile(
|
||||
date: DateFormat('HH:mm').format(item.order.createdAt),
|
||||
amount: item.orderFormattedAmount,
|
||||
amountFiat: "USD 0.00",
|
||||
roundedBottom: roundedBottom,
|
||||
roundedTop: roundedTop,
|
||||
bottomSeparator: !roundedBottom,
|
||||
),
|
||||
);
|
||||
} else if (item is PayjoinTransactionListItem) {
|
||||
final session = item.session;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.payjoinDetails,
|
||||
arguments: [item.sessionId, item.transaction],
|
||||
),
|
||||
child: PayjoinHistoryTile(
|
||||
createdAt: DateFormat('HH:mm').format(session.inProgressSince!),
|
||||
amount: dashboardViewModel.appStore.amountParsingProxy
|
||||
.getDisplayCryptoString(session.amount.toInt(), CryptoCurrency.btc),
|
||||
currency: item.transaction?.from ?? "BTC",
|
||||
state: item.status,
|
||||
isSending: session.isSenderSession,
|
||||
roundedTop: roundedTop,
|
||||
roundedBottom: roundedBottom,
|
||||
bottomSeparator: !roundedBottom),
|
||||
);
|
||||
} else if (item is AnonpayTransactionListItem) {
|
||||
final transactionInfo = item.transaction;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.anonPayDetailsPage, arguments: transactionInfo),
|
||||
child: AnonpayHistoryTile(
|
||||
provider: transactionInfo.provider,
|
||||
createdAt: DateFormat('HH:mm').format(transactionInfo.createdAt),
|
||||
amount: transactionInfo.fiatAmount?.toString() ??
|
||||
(transactionInfo.amountTo?.toString() ?? ''),
|
||||
currency: transactionInfo.fiatAmount != null
|
||||
? transactionInfo.fiatEquiv ?? ''
|
||||
: CryptoCurrency.fromFullName(transactionInfo.coinTo).name.toUpperCase(),
|
||||
roundedTop: roundedTop,
|
||||
roundedBottom: roundedBottom,
|
||||
bottomSeparator: !roundedBottom));
|
||||
} else
|
||||
return Text(item.runtimeType.toString());
|
||||
}),
|
||||
),
|
||||
),
|
||||
));
|
||||
));
|
||||
}
|
||||
|
||||
String _getChainIconPath() {
|
||||
try {
|
||||
return CryptoCurrency.fromString(dashboardViewModel.wallet.currency.tag ??dashboardViewModel.wallet.currency.title).chainIconPath!;
|
||||
} catch(e) {
|
||||
return CryptoCurrency.fromString(
|
||||
dashboardViewModel.wallet.currency.tag ?? dashboardViewModel.wallet.currency.title)
|
||||
.chainIconPath!;
|
||||
} catch (e) {
|
||||
return dashboardViewModel.wallet.currency.chainIconPath ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,28 +39,30 @@ class HistoryTradeTile extends StatelessWidget {
|
||||
width: 50,
|
||||
child: Stack(
|
||||
children: [
|
||||
CakeImageWidget(imageUrl: _getIconPath(from),
|
||||
width: currencyIconSize, height: currencyIconSize),
|
||||
CakeImageWidget(
|
||||
imageUrl: _getIconPath(from), width: currencyIconSize, height: currencyIconSize),
|
||||
Positioned(
|
||||
top: currencyIconSize / 2,
|
||||
left: currencyIconSize / 2,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 2,
|
||||
color: Theme.of(context).colorScheme.surfaceContainer),
|
||||
shape: BoxShape.circle),
|
||||
child: CakeImageWidget(imageUrl: _getIconPath(to),
|
||||
width: currencyIconSize, height: currencyIconSize))),
|
||||
top: currencyIconSize / 2,
|
||||
left: currencyIconSize / 2,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border:
|
||||
Border.all(width: 2, color: Theme.of(context).colorScheme.surfaceContainer),
|
||||
shape: BoxShape.circle),
|
||||
child: CakeImageWidget(
|
||||
imageUrl: _getIconPath(to),
|
||||
width: currencyIconSize,
|
||||
height: currencyIconSize,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
final fromChainIcon = _getChainIcon(from);
|
||||
final toChainIcon = _getChainIcon(to);
|
||||
|
||||
@@ -118,36 +120,32 @@ class HistoryTradeTile extends StatelessWidget {
|
||||
}
|
||||
|
||||
String _getIconPath(CryptoCurrency currency) {
|
||||
try { // temporarily until we migrate from hive to sqlite and store the full currency object
|
||||
if (currency.iconPath != null) {
|
||||
return currency.iconPath!;
|
||||
try {
|
||||
if (currency.title.isNotEmpty) {
|
||||
final live = CryptoCurrency.safeParseCurrencyFromString(currency.title, tag: currency.tag);
|
||||
if (live?.iconPath != null) return live!.iconPath!;
|
||||
}
|
||||
|
||||
if (currency.iconPath != null) return currency.iconPath!;
|
||||
|
||||
if (currency.name.isNotEmpty) {
|
||||
final currencyFromName = CryptoCurrency.fromString(currency.name);
|
||||
if (currencyFromName.iconPath != null) {
|
||||
return currencyFromName.iconPath!;
|
||||
}
|
||||
}
|
||||
|
||||
if (currency.title.isNotEmpty) {
|
||||
final currencyFromTitle = CryptoCurrency.fromString(currency.title);
|
||||
if (currencyFromTitle.iconPath != null) {
|
||||
return currencyFromTitle.iconPath!;
|
||||
}
|
||||
final byName = CryptoCurrency.safeParseCurrencyFromString(currency.name);
|
||||
if (byName?.iconPath != null) return byName!.iconPath!;
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
//TODO approporiate fallback
|
||||
return "";
|
||||
}
|
||||
|
||||
String _getChainIcon(CryptoCurrency currency) {
|
||||
try {
|
||||
if (currency.chainIconPath != null) {
|
||||
return currency.chainIconPath!;
|
||||
if (currency.title.isNotEmpty) {
|
||||
final parsedCurrency = CryptoCurrency.safeParseCurrencyFromString(currency.title, tag: currency.tag);
|
||||
if (parsedCurrency?.chainIconPath != null) return parsedCurrency!.chainIconPath!;
|
||||
}
|
||||
|
||||
if (currency.chainIconPath != null) return currency.chainIconPath!;
|
||||
|
||||
if ((currency.tag ?? "").isNotEmpty) {
|
||||
final currencyFromTag = CryptoCurrency.fromString(currency.tag!);
|
||||
if (currencyFromTag.chainIconPath != null) {
|
||||
|
||||
@@ -166,9 +166,9 @@ class TransactionsPage extends StatelessWidget {
|
||||
final trade = item.trade;
|
||||
|
||||
final tradeFrom =
|
||||
trade.fromRaw >= 0 ? trade.from : trade.userCurrencyFrom;
|
||||
trade.from;
|
||||
|
||||
final tradeTo = trade.toRaw >= 0 ? trade.to : trade.userCurrencyTo;
|
||||
final tradeTo = trade.to;
|
||||
|
||||
return tradeFrom != null && tradeTo != null
|
||||
? Observer(
|
||||
|
||||
@@ -31,7 +31,7 @@ void showInformation(ExchangeTradeViewModel exchangeTradeViewModel, BuildContext
|
||||
final trade = exchangeTradeViewModel.trade;
|
||||
final walletName = exchangeTradeViewModel.wallet.name;
|
||||
|
||||
final from = trade.from?.toString() ?? trade.userCurrencyFrom.toString();
|
||||
final from = trade.from?.toString() ?? '';
|
||||
|
||||
final information = exchangeTradeViewModel.isSendable
|
||||
? S.current.exchange_trade_result_confirm(trade.amount, from, walletName) +
|
||||
|
||||
@@ -319,14 +319,14 @@ class _SwapDetailsContent extends StatelessWidget {
|
||||
_SwapDetailsTile(
|
||||
label: 'You Send',
|
||||
value:
|
||||
'${trade.amount} ${trade.from?.title ?? trade.userCurrencyFrom?.title ?? ''}',
|
||||
'${trade.amount} ${trade.from?.title ?? ''}',
|
||||
valueFiatFormatted: exchangeTradeViewModel.sendAmountFiatFormatted,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_SwapDetailsTile(
|
||||
label: 'You Get',
|
||||
value:
|
||||
'${trade.receiveAmount ?? '0'} ${trade.to?.title ?? trade.userCurrencyTo?.title ?? ''}',
|
||||
'${trade.receiveAmount ?? '0'} ${trade.to?.title ?? ''}',
|
||||
valueFiatFormatted: exchangeTradeViewModel
|
||||
.getReceiveAmountFiatFormatted(trade.receiveAmount ?? '0.0'),
|
||||
),
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'trades_store.g.dart';
|
||||
@@ -11,14 +9,11 @@ part 'trades_store.g.dart';
|
||||
class TradesStore = TradesStoreBase with _$TradesStore;
|
||||
|
||||
abstract class TradesStoreBase with Store {
|
||||
TradesStoreBase({required this.tradesSource, required this.appStore})
|
||||
: trades = <TradeListItem>[] {
|
||||
_onTradesChanged = tradesSource.watch().listen((_) async => await updateTradeList());
|
||||
TradesStoreBase({required this.appStore}) : trades = <TradeListItem>[] {
|
||||
Trade.onChanged.stream.listen((_) => updateTradeList());
|
||||
updateTradeList();
|
||||
}
|
||||
|
||||
Box<Trade> tradesSource;
|
||||
StreamSubscription<BoxEvent>? _onTradesChanged;
|
||||
AppStore appStore;
|
||||
|
||||
@observable
|
||||
@@ -31,11 +26,18 @@ abstract class TradesStoreBase with Store {
|
||||
void setTrade(Trade trade) => this.trade = trade;
|
||||
|
||||
@action
|
||||
Future<void> updateTradeList() async => trades = tradesSource.values
|
||||
.map((trade) => TradeListItem(
|
||||
trade: trade,
|
||||
appStore: appStore,
|
||||
key: ValueKey('trade_list_item_${trade.id}_key'),
|
||||
))
|
||||
.toList();
|
||||
Future<void> updateTradeList() async {
|
||||
try {
|
||||
final allTrades = await Trade.getAll();
|
||||
runInAction(() {
|
||||
trades = allTrades
|
||||
.map((trade) => TradeListItem(
|
||||
trade: trade,
|
||||
appStore: appStore,
|
||||
key: ValueKey('trade_list_item_${trade.id}_key'),
|
||||
))
|
||||
.toList();
|
||||
});
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,15 +15,24 @@ class TradeListItem extends ActionListItem {
|
||||
|
||||
BalanceDisplayMode get displayMode => appStore.settingsStore.balanceDisplayMode;
|
||||
|
||||
String get tradeFormattedAmount => displayMode == BalanceDisplayMode.hiddenBalance
|
||||
? "---"
|
||||
: appStore.amountParsingProxy.getDisplayCryptoAmount(trade.amountFormatted(), trade.from!);
|
||||
String get tradeFormattedAmount {
|
||||
if (displayMode == BalanceDisplayMode.hiddenBalance) {
|
||||
return '---';
|
||||
}
|
||||
final from = trade.from;
|
||||
if (from == null) return trade.amountFormatted();
|
||||
return appStore.amountParsingProxy.getDisplayCryptoAmount(trade.amountFormatted(), from);
|
||||
}
|
||||
|
||||
String get tradeFormattedReceiveAmount => displayMode == BalanceDisplayMode.hiddenBalance
|
||||
? "---"
|
||||
: appStore.amountParsingProxy
|
||||
.getDisplayCryptoAmount(trade.receiveAmountFormatted(), trade.to!);
|
||||
String get tradeFormattedReceiveAmount {
|
||||
if (displayMode == BalanceDisplayMode.hiddenBalance) {
|
||||
return '---';
|
||||
}
|
||||
final to = trade.to;
|
||||
if (to == null) return trade.receiveAmountFormatted();
|
||||
return appStore.amountParsingProxy.getDisplayCryptoAmount(trade.receiveAmountFormatted(), to);
|
||||
}
|
||||
|
||||
@override
|
||||
DateTime get date => trade.createdAt!;
|
||||
DateTime get date => trade.createdAt ?? DateTime.fromMillisecondsSinceEpoch(0, isUtc: true);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ import 'package:cw_core/payment_uris.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'exchange_trade_view_model.g.dart';
|
||||
@@ -44,7 +43,6 @@ class ExchangeTradeViewModel = ExchangeTradeViewModelBase with _$ExchangeTradeVi
|
||||
abstract class ExchangeTradeViewModelBase with Store {
|
||||
ExchangeTradeViewModelBase({
|
||||
required this.wallet,
|
||||
required this.trades,
|
||||
required this.tradesStore,
|
||||
required this.sendViewModel,
|
||||
required this.feesViewModel,
|
||||
@@ -78,10 +76,10 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
_provider = StealthExExchangeProvider();
|
||||
break;
|
||||
case ExchangeProviderDescription.thorChain:
|
||||
_provider = ThorChainExchangeProvider(tradesStore: trades);
|
||||
_provider = ThorChainExchangeProvider();
|
||||
break;
|
||||
case ExchangeProviderDescription.chainflip:
|
||||
_provider = ChainflipExchangeProvider(tradesStore: trades);
|
||||
_provider = ChainflipExchangeProvider();
|
||||
break;
|
||||
case ExchangeProviderDescription.xoSwap:
|
||||
_provider = XOSwapExchangeProvider();
|
||||
@@ -106,7 +104,6 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
}
|
||||
|
||||
final WalletBase wallet;
|
||||
final Box<Trade> trades;
|
||||
final TradesStore tradesStore;
|
||||
final SendViewModel sendViewModel;
|
||||
final FeesViewModel feesViewModel;
|
||||
@@ -217,7 +214,7 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
Future<void> confirmSending() async {
|
||||
if (!isSendable) return;
|
||||
|
||||
final selected = trade.from ?? trade.userCurrencyFrom;
|
||||
final selected = trade.from;
|
||||
if (selected == null) {
|
||||
printV('No selectable currency for trade ${trade.id}');
|
||||
return;
|
||||
@@ -231,35 +228,23 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
if (_provider is SwapsXyzExchangeProvider) {
|
||||
final hash = pendingTransaction?.evmTxHashFromRawHex ?? pendingTransaction?.id ?? '';
|
||||
trade.txId = hash;
|
||||
|
||||
if (trade.isInBox) {
|
||||
await trade.save();
|
||||
} else {
|
||||
await trades.add(trade);
|
||||
}
|
||||
await trade.save();
|
||||
}
|
||||
|
||||
if (_provider is ThorChainExchangeProvider) {
|
||||
trade.id = pendingTransaction?.id ?? '';
|
||||
trades.add(trade);
|
||||
await trade.save();
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> _updateTrade() async {
|
||||
try {
|
||||
final agreedAmount = tradesStore.trade!.amount;
|
||||
final isSendAll = tradesStore.trade!.isSendAll;
|
||||
final updatedTrade = await _provider!.findTradeById(id: trade.id);
|
||||
|
||||
if (updatedTrade.createdAt == null && trade.createdAt != null)
|
||||
updatedTrade.createdAt = trade.createdAt;
|
||||
|
||||
if (updatedTrade.amount.isEmpty) updatedTrade.amount = trade.amount;
|
||||
|
||||
trade = updatedTrade;
|
||||
trade.amount = agreedAmount;
|
||||
trade.isSendAll = isSendAll;
|
||||
trade.mergeFindTradeByIdResult(updatedTrade);
|
||||
await trade.save();
|
||||
tradesStore.setTrade(trade);
|
||||
|
||||
_updateItems();
|
||||
} catch (e) {
|
||||
@@ -268,10 +253,8 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
}
|
||||
|
||||
void _updateItems() {
|
||||
final trade = tradesStore.trade!;
|
||||
|
||||
final tradeFrom = trade.fromRaw >= 0 ? trade.from : trade.userCurrencyFrom;
|
||||
final tradeTo = trade.toRaw >= 0 ? trade.to : trade.userCurrencyTo;
|
||||
final tradeFrom = trade.from;
|
||||
final tradeTo = trade.to;
|
||||
|
||||
final tagFrom = tradeFrom?.tag != null ? "${tradeFrom!.tag} " : "";
|
||||
final tagTo = tradeTo?.tag != null ? "${tradeTo!.tag} " : "";
|
||||
@@ -289,12 +272,12 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
),
|
||||
);
|
||||
|
||||
if (tradeFrom != null || tradeTo != null) {
|
||||
if (tradeFrom != null && tradeTo != null) {
|
||||
items.addAll([
|
||||
ExchangeTradeItem(
|
||||
title: S.current.amount,
|
||||
data:
|
||||
"${_amountParsingProxy.getDisplayCryptoAmount(trade.amount, tradeFrom!)} ${_amountParsingProxy.getCryptoSymbol(tradeFrom)}",
|
||||
"${_amountParsingProxy.getDisplayCryptoAmount(trade.amount, tradeFrom)} ${_amountParsingProxy.getCryptoSymbol(tradeFrom)}",
|
||||
isCopied: false,
|
||||
isReceiveDetail: false,
|
||||
isExternalSendDetail: true,
|
||||
@@ -302,14 +285,14 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
ExchangeTradeItem(
|
||||
title: "${S.current.you_will_receive_estimated_amount}:",
|
||||
data:
|
||||
"${_amountParsingProxy.getDisplayCryptoAmount(tradesStore.trade?.receiveAmount ?? "0", tradeTo!)} ${_amountParsingProxy.getCryptoSymbol(tradeTo)}",
|
||||
"${_amountParsingProxy.getDisplayCryptoAmount(trade.receiveAmount ?? "0", tradeTo)} ${_amountParsingProxy.getCryptoSymbol(tradeTo)}",
|
||||
isCopied: true,
|
||||
isReceiveDetail: true,
|
||||
isExternalSendDetail: false,
|
||||
),
|
||||
ExchangeTradeItem(
|
||||
title: "${S.current.send_to_this_address("${tradeFrom}", tagFrom)}:",
|
||||
data: trade.inputAddress ?? "",
|
||||
title: "${S.current.send_to_this_address("$tradeFrom", tagFrom)}:",
|
||||
data: trade.inputAddress ?? '',
|
||||
isCopied: false,
|
||||
isReceiveDetail: false,
|
||||
isExternalSendDetail: true,
|
||||
@@ -367,7 +350,10 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
|
||||
static bool _checkIfCanSend(TradesStore tradesStore, WalletBase wallet) {
|
||||
final trade = tradesStore.trade!;
|
||||
final tradeFrom = trade.fromRaw >= 0 ? trade.from : trade.userCurrencyFrom;
|
||||
final tradeFrom = trade.from;
|
||||
|
||||
bool _sameCurrency(CryptoCurrency? a, CryptoCurrency? b) =>
|
||||
a != null && b != null && a.titleAndTagEqual(b);
|
||||
|
||||
bool _isEthToken() =>
|
||||
wallet.currency == CryptoCurrency.eth && tradeFrom?.tag == CryptoCurrency.eth.title;
|
||||
@@ -393,8 +379,9 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
bool _isBscToken() =>
|
||||
wallet.currency == CryptoCurrency.bnb && tradeFrom?.tag == CryptoCurrency.bnb.tag;
|
||||
|
||||
return tradeFrom == wallet.currency ||
|
||||
tradeFrom == CryptoCurrency.btcln && wallet.currency == CryptoCurrency.btc ||
|
||||
return _sameCurrency(tradeFrom, wallet.currency) ||
|
||||
(_sameCurrency(tradeFrom, CryptoCurrency.btcln) &&
|
||||
wallet.currency == CryptoCurrency.btc) ||
|
||||
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto ||
|
||||
_isEthToken() ||
|
||||
_isPolygonToken() ||
|
||||
@@ -472,7 +459,7 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
PaymentURI? get paymentUri {
|
||||
final inputAddress = trade.inputAddress;
|
||||
final amount = trade.amount;
|
||||
final fromCurrency = trade.from ?? trade.userCurrencyFrom;
|
||||
final fromCurrency = trade.from;
|
||||
|
||||
if (inputAddress == null || inputAddress.isEmpty || fromCurrency == null) {
|
||||
return null;
|
||||
|
||||
@@ -67,7 +67,6 @@ import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
@@ -95,7 +94,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
ExchangeViewModelBase(
|
||||
this._appStore,
|
||||
this.trades,
|
||||
this._exchangeTemplateStore,
|
||||
this.tradesStore,
|
||||
this.sharedPreferences,
|
||||
@@ -307,7 +305,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
[WalletType.monero, WalletType.wownero, WalletType.zcash].contains(wallet.type);
|
||||
|
||||
bool _useTorOnly;
|
||||
final Box<Trade> trades;
|
||||
final ExchangeTemplateStore _exchangeTemplateStore;
|
||||
final TradesStore tradesStore;
|
||||
final SharedPreferences sharedPreferences;
|
||||
@@ -315,7 +312,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
List<ExchangeProvider> get _allProviders => [
|
||||
ChangeNowExchangeProvider(settingsStore: _settingsStore),
|
||||
// SideShiftExchangeProvider(),
|
||||
ChainflipExchangeProvider(tradesStore: trades),
|
||||
ChainflipExchangeProvider(),
|
||||
if (FeatureFlag.isExolixEnabled) ExolixExchangeProvider(),
|
||||
SwapTradeExchangeProvider(),
|
||||
LetsExchangeExchangeProvider(),
|
||||
@@ -1213,7 +1210,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
}
|
||||
|
||||
tradesStore.setTrade(trade);
|
||||
if (trade.provider != ExchangeProviderDescription.thorChain) await trades.add(trade);
|
||||
if (trade.provider != ExchangeProviderDescription.thorChain) await trade.save();
|
||||
tradeState = TradeIsCreatedSuccessfully(trade: trade);
|
||||
|
||||
/// return after the first successful trade
|
||||
@@ -1626,7 +1623,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
if (trade.provider == ExchangeProviderDescription.swapsXyz) {
|
||||
|
||||
final tradeFrom = trade.fromRaw >= 0 ? trade.from : trade.userCurrencyFrom;
|
||||
final tradeFrom = trade.from;
|
||||
|
||||
if (tradeFrom == null) {
|
||||
return CreateTradeResult(
|
||||
|
||||
@@ -1091,9 +1091,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||
|
||||
_currentTrade!.stateRaw = isSuccess ? TradeState.completed.raw : TradeState.failed.raw;
|
||||
|
||||
if (_currentTrade!.isInBox) {
|
||||
await _currentTrade!.save();
|
||||
}
|
||||
await _currentTrade!.save();
|
||||
}
|
||||
|
||||
@action
|
||||
|
||||
@@ -26,11 +26,8 @@ import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.d
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/utils/date_formatter.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
@@ -41,11 +38,9 @@ class TradeDetailsViewModel = TradeDetailsViewModelBase with _$TradeDetailsViewM
|
||||
abstract class TradeDetailsViewModelBase with Store {
|
||||
TradeDetailsViewModelBase({
|
||||
required Trade tradeForDetails,
|
||||
required this.trades,
|
||||
required this.appStore,
|
||||
}) : items = ObservableList<StandartListItem>(),
|
||||
trade = trades.values.firstWhereOrNull((element) => element.id == tradeForDetails.id) ??
|
||||
tradeForDetails {
|
||||
trade = tradeForDetails {
|
||||
switch (trade.provider) {
|
||||
case ExchangeProviderDescription.changeNow:
|
||||
_provider = ChangeNowExchangeProvider(settingsStore: appStore.settingsStore);
|
||||
@@ -63,7 +58,7 @@ abstract class TradeDetailsViewModelBase with Store {
|
||||
_provider = ExolixExchangeProvider();
|
||||
break;
|
||||
case ExchangeProviderDescription.thorChain:
|
||||
_provider = ThorChainExchangeProvider(tradesStore: trades);
|
||||
_provider = ThorChainExchangeProvider();
|
||||
break;
|
||||
case ExchangeProviderDescription.swapTrade:
|
||||
_provider = SwapTradeExchangeProvider();
|
||||
@@ -74,7 +69,7 @@ abstract class TradeDetailsViewModelBase with Store {
|
||||
_provider = StealthExExchangeProvider();
|
||||
break;
|
||||
case ExchangeProviderDescription.chainflip:
|
||||
_provider = ChainflipExchangeProvider(tradesStore: trades);
|
||||
_provider = ChainflipExchangeProvider();
|
||||
break;
|
||||
case ExchangeProviderDescription.xoSwap:
|
||||
_provider = XOSwapExchangeProvider();
|
||||
@@ -132,8 +127,6 @@ abstract class TradeDetailsViewModelBase with Store {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Box<Trade> trades;
|
||||
|
||||
@observable
|
||||
Trade trade;
|
||||
|
||||
@@ -151,22 +144,8 @@ abstract class TradeDetailsViewModelBase with Store {
|
||||
try {
|
||||
final updatedTrade = await _provider!.findTradeById(id: trade.id);
|
||||
|
||||
if (updatedTrade.createdAt == null && trade.createdAt != null) {
|
||||
updatedTrade.createdAt = trade.createdAt;
|
||||
}
|
||||
|
||||
if (updatedTrade.toRaw == -1 && trade.toRaw != -1) {
|
||||
updatedTrade.toRaw = trade.toRaw;
|
||||
}
|
||||
|
||||
Trade? foundElement = trades.values.firstWhereOrNull((element) => element.id == trade.id);
|
||||
if (foundElement != null) {
|
||||
final editedTrade = trades.get(foundElement.key);
|
||||
editedTrade?.stateRaw = updatedTrade.stateRaw;
|
||||
editedTrade?.save();
|
||||
}
|
||||
|
||||
trade = updatedTrade;
|
||||
trade.mergeFindTradeByIdResult(updatedTrade);
|
||||
await trade.save();
|
||||
|
||||
_updateItems();
|
||||
} catch (e) {
|
||||
@@ -186,8 +165,8 @@ abstract class TradeDetailsViewModelBase with Store {
|
||||
items.add(
|
||||
DetailsListStatusItem(title: S.current.trade_details_state, value: trade.state.toString()));
|
||||
|
||||
final tradeFrom = _safeFrom(trade);
|
||||
final tradeTo = _safeTo(trade);
|
||||
final tradeFrom = trade.from;
|
||||
final tradeTo = trade.to;
|
||||
|
||||
if (tradeFrom != null && tradeTo != null) {
|
||||
items.add(TradeDetailsListCardItem.tradeDetails(
|
||||
@@ -241,21 +220,5 @@ abstract class TradeDetailsViewModelBase with Store {
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
CryptoCurrency? _safeFrom(Trade trade) {
|
||||
try {
|
||||
final raw = trade.fromRaw;
|
||||
return raw >= 0 ? trade.from : trade.userCurrencyFrom;
|
||||
} catch (_) {
|
||||
return trade.userCurrencyFrom;
|
||||
}
|
||||
}
|
||||
|
||||
CryptoCurrency? _safeTo(Trade trade) {
|
||||
try {
|
||||
final raw = trade.toRaw;
|
||||
return raw >= 0 ? trade.to : trade.userCurrencyTo;
|
||||
} catch (_) {
|
||||
return trade.userCurrencyTo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user