From 659c702d48c0a9a2f8a04cccffacff585157af96 Mon Sep 17 00:00:00 2001 From: OmarHatem <omarh.ismail1@gmail.com> Date: Fri, 21 Jul 2023 18:37:33 +0300 Subject: [PATCH] Save transaction history --- .../lib/electrum_transaction_history.dart | 3 +- .../lib/ethereum_transaction_history.dart | 56 +++++++++++++++++-- .../lib/ethereum_transaction_info.dart | 43 +++++++------- cw_ethereum/lib/ethereum_wallet.dart | 16 +++--- 4 files changed, 82 insertions(+), 36 deletions(-) diff --git a/cw_bitcoin/lib/electrum_transaction_history.dart b/cw_bitcoin/lib/electrum_transaction_history.dart index 553795470..be039fa36 100644 --- a/cw_bitcoin/lib/electrum_transaction_history.dart +++ b/cw_bitcoin/lib/electrum_transaction_history.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/wallet_info.dart'; -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/transaction_history.dart'; import 'package:cw_bitcoin/file.dart'; @@ -67,7 +66,7 @@ abstract class ElectrumTransactionHistoryBase Future<void> _load() async { try { final content = await _read(); - final txs = content['transactions'] as Map<String, dynamic> ?? {}; + final txs = content['transactions'] as Map<String, dynamic>? ?? {}; txs.entries.forEach((entry) { final val = entry.value; diff --git a/cw_ethereum/lib/ethereum_transaction_history.dart b/cw_ethereum/lib/ethereum_transaction_history.dart index 8a5825c73..8904fb347 100644 --- a/cw_ethereum/lib/ethereum_transaction_history.dart +++ b/cw_ethereum/lib/ethereum_transaction_history.dart @@ -1,29 +1,73 @@ +import 'dart:convert'; import 'dart:core'; +import 'package:cw_core/pathForWallet.dart'; +import 'package:cw_core/wallet_info.dart'; +import 'package:cw_ethereum/file.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/transaction_history.dart'; import 'package:cw_ethereum/ethereum_transaction_info.dart'; part 'ethereum_transaction_history.g.dart'; -class EthereumTransactionHistory = EthereumTransactionHistoryBase - with _$EthereumTransactionHistory; +const transactionsHistoryFileName = 'transactions.json'; + +class EthereumTransactionHistory = EthereumTransactionHistoryBase with _$EthereumTransactionHistory; abstract class EthereumTransactionHistoryBase extends TransactionHistoryBase<EthereumTransactionInfo> with Store { - EthereumTransactionHistoryBase() { + EthereumTransactionHistoryBase({required this.walletInfo, required String password}) + : _password = password { transactions = ObservableMap<String, EthereumTransactionInfo>(); } + final WalletInfo walletInfo; + String _password; + + Future<void> init() async => await _load(); + @override Future<void> save() async { - // TODO: implement + try { + final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type); + final path = '$dirPath/$transactionsHistoryFileName'; + final data = json.encode({'transactions': transactions}); + await writeData(path: path, password: _password, data: data); + } catch (e) { + print('Error while save bitcoin transaction history: ${e.toString()}'); + } } @override - void addOne(EthereumTransactionInfo transaction) => - transactions[transaction.id] = transaction; + void addOne(EthereumTransactionInfo transaction) => transactions[transaction.id] = transaction; @override void addMany(Map<String, EthereumTransactionInfo> transactions) => this.transactions.addAll(transactions); + + Future<Map<String, dynamic>> _read() async { + final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type); + final path = '$dirPath/$transactionsHistoryFileName'; + final content = await read(path: path, password: _password); + return json.decode(content) as Map<String, dynamic>; + } + + Future<void> _load() async { + try { + final content = await _read(); + final txs = content['transactions'] as Map<String, dynamic>? ?? {}; + + txs.entries.forEach((entry) { + final val = entry.value; + + if (val is Map<String, dynamic>) { + final tx = EthereumTransactionInfo.fromJson(val); + _update(tx); + } + }); + } catch (e) { + print(e); + } + } + + void _update(EthereumTransactionInfo transaction) => transactions[transaction.id] = transaction; } diff --git a/cw_ethereum/lib/ethereum_transaction_info.dart b/cw_ethereum/lib/ethereum_transaction_info.dart index 0c642b947..fcf79961f 100644 --- a/cw_ethereum/lib/ethereum_transaction_info.dart +++ b/cw_ethereum/lib/ethereum_transaction_info.dart @@ -43,26 +43,29 @@ class EthereumTransactionInfo extends TransactionInfo { factory EthereumTransactionInfo.fromJson(Map<String, dynamic> data) { return EthereumTransactionInfo( - id: data['id'] as String, - height: data['height'] as int, - amount: data['amount'] as int, - fee: data['fee'] as int, - direction: parseTransactionDirectionFromInt(data['direction'] as int), - date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int), - isPending: data['isPending'] as bool, - confirmations: data['confirmations'] as int); + id: data['id'] as String, + height: data['height'] as int, + amount: data['amount'] as int, + exponent: data['exponent'] as int, + fee: data['fee'] as int, + direction: parseTransactionDirectionFromInt(data['direction'] as int), + date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int), + isPending: data['isPending'] as bool, + confirmations: data['confirmations'] as int, + tokenSymbol: data['tokenSymbol'] as String, + ); } - Map<String, dynamic> toJson() { - final m = <String, dynamic>{}; - m['id'] = id; - m['height'] = height; - m['amount'] = amount; - m['direction'] = direction.index; - m['date'] = date.millisecondsSinceEpoch; - m['isPending'] = isPending; - m['confirmations'] = confirmations; - m['fee'] = fee; - return m; - } + Map<String, dynamic> toJson() => { + 'id': id, + 'height': height, + 'amount': amount, + 'exponent': exponent, + 'fee': fee, + 'direction': direction.index, + 'date': date.millisecondsSinceEpoch, + 'isPending': isPending, + 'confirmations': confirmations, + 'tokenSymbol': tokenSymbol, + }; } diff --git a/cw_ethereum/lib/ethereum_wallet.dart b/cw_ethereum/lib/ethereum_wallet.dart index 94f69b253..cf644784e 100644 --- a/cw_ethereum/lib/ethereum_wallet.dart +++ b/cw_ethereum/lib/ethereum_wallet.dart @@ -53,6 +53,7 @@ abstract class EthereumWalletBase {CryptoCurrency.eth: initialBalance ?? ERC20Balance(BigInt.zero)}), super(walletInfo) { this.walletInfo = walletInfo; + transactionHistory = EthereumTransactionHistory(walletInfo: walletInfo, password: password); if (!Hive.isAdapterRegistered(Erc20Token.typeId)) { Hive.registerAdapter(Erc20TokenAdapter()); @@ -86,9 +87,10 @@ abstract class EthereumWalletBase Future<void> init() async { erc20TokensBox = await Hive.openBox<Erc20Token>(Erc20Token.boxName); await walletAddresses.init(); + await transactionHistory.init(); _privateKey = await getPrivateKey(_mnemonic, _password); - transactionHistory = EthereumTransactionHistory(); walletAddresses.address = _privateKey.address.toString(); + await save(); } @override @@ -410,19 +412,17 @@ abstract class EthereumWalletBase final currentWalletFile = File(currentWalletPath); final currentDirPath = await pathForWalletDir(name: walletInfo.name, type: type); - // TODO: un-hash when transactions flow is implemented - // final currentTransactionsFile = File('$currentDirPath/$transactionsHistoryFileName'); + final currentTransactionsFile = File('$currentDirPath/$transactionsHistoryFileName'); // Copies current wallet files into new wallet name's dir and files if (currentWalletFile.existsSync()) { final newWalletPath = await pathForWallet(name: newWalletName, type: type); await currentWalletFile.copy(newWalletPath); } - // TODO: un-hash when transactions flow is implemented - // if (currentTransactionsFile.existsSync()) { - // final newDirPath = await pathForWalletDir(name: newWalletName, type: type); - // await currentTransactionsFile.copy('$newDirPath/$transactionsHistoryFileName'); - // } + if (currentTransactionsFile.existsSync()) { + final newDirPath = await pathForWalletDir(name: newWalletName, type: type); + await currentTransactionsFile.copy('$newDirPath/$transactionsHistoryFileName'); + } // Delete old name's dir and files await Directory(currentDirPath).delete(recursive: true);