From 1fdb9b8763ffb422796b7d2ddf385fb92b964130 Mon Sep 17 00:00:00 2001 From: reasje Date: Thu, 2 Nov 2023 11:40:11 +0330 Subject: [PATCH 1/4] imprv: Renamed tx history use case file --- ...t => transactions_history_repository.dart} | 23 ++++++++----------- ...art => transactions_history_use_case.dart} | 3 +++ 2 files changed, 12 insertions(+), 14 deletions(-) rename lib/common/components/recent_transactions/domain/{transactions_repository.dart => transactions_history_repository.dart} (62%) rename lib/common/components/recent_transactions/domain/{transactions_use_case.dart => transactions_history_use_case.dart} (94%) diff --git a/lib/common/components/recent_transactions/domain/transactions_repository.dart b/lib/common/components/recent_transactions/domain/transactions_history_repository.dart similarity index 62% rename from lib/common/components/recent_transactions/domain/transactions_repository.dart rename to lib/common/components/recent_transactions/domain/transactions_history_repository.dart index 2d497e4c..ff39cda5 100644 --- a/lib/common/components/recent_transactions/domain/transactions_repository.dart +++ b/lib/common/components/recent_transactions/domain/transactions_history_repository.dart @@ -7,25 +7,22 @@ class TransactionsHistoryRepository extends ControlledCacheRepository { late final Field> transactionsHistory = fieldWithDefault>('items', [], - serializer: (b) => b - .map((e) => e.toMap()) - .toList(), - deserializer: (b) => (b as List) - .map((e) => TransactionModel.fromMap(e) - ) - .toList()); + serializer: (b) => b.map((e) => e.toMap()).toList(), + deserializer: (b) => + (b as List).map((e) => TransactionModel.fromMap(e)).toList()); List get items => transactionsHistory.value; - - void addItem(TransactionModel item, int index) { final newList = transactionsHistory.value; newList.insert(0, item); transactionsHistory.value = newList; } - void updateItem(TransactionModel item, int index,) { + void updateItem( + TransactionModel item, + int index, + ) { final newList = transactionsHistory.value; newList[index] = item; @@ -33,10 +30,8 @@ class TransactionsHistoryRepository extends ControlledCacheRepository { transactionsHistory.value = newList; } - void removeItem(TransactionModel item) => - transactionsHistory.value = transactionsHistory.value - .where((e) => e.hash != item.hash) - .toList(); + void removeItem(TransactionModel item) => transactionsHistory.value = + transactionsHistory.value.where((e) => e.hash != item.hash).toList(); void removeAll() => transactionsHistory.value = []; } diff --git a/lib/common/components/recent_transactions/domain/transactions_use_case.dart b/lib/common/components/recent_transactions/domain/transactions_history_use_case.dart similarity index 94% rename from lib/common/components/recent_transactions/domain/transactions_use_case.dart rename to lib/common/components/recent_transactions/domain/transactions_history_use_case.dart index 8155a553..88cb6a1e 100644 --- a/lib/common/components/recent_transactions/domain/transactions_use_case.dart +++ b/lib/common/components/recent_transactions/domain/transactions_history_use_case.dart @@ -48,6 +48,7 @@ class TransactionsHistoryUseCase extends ReactiveUseCase { update(transactionsHistory, _repository.items); } + /// This function will spy on the given transaction void spyOnTransaction( TransactionModel item, ) { @@ -69,6 +70,8 @@ class TransactionsHistoryUseCase extends ReactiveUseCase { } } + /// This function will run through all the transactions and will start spying on + /// pending transactions void checkForPendingTransactions(int chainId) { if (!Config.isMxcChains(chainId)) { final txList = transactionsHistory.value; From 96cef857538e1056a8ffbe113ffa8994724bbd50 Mon Sep 17 00:00:00 2001 From: reasje Date: Thu, 2 Nov 2023 16:24:20 +0330 Subject: [PATCH 2/4] feat: Added mxc transactions use case --- assets/flutter_i18n/en.json | 2 + .../domain/mxc_transaction_use_case.dart | 80 +++++++++++++++++++ .../recent_transactions.dart | 4 +- lib/common/config.dart | 3 + .../src/providers/providers_use_cases.dart | 8 ++ 5 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 lib/common/components/recent_transactions/domain/mxc_transaction_use_case.dart diff --git a/assets/flutter_i18n/en.json b/assets/flutter_i18n/en.json index a3e6c7fe..a5a4fc16 100644 --- a/assets/flutter_i18n/en.json +++ b/assets/flutter_i18n/en.json @@ -42,6 +42,7 @@ "send": "Send", "received": "Received", "sent": "Sent", + "contractCall": "Contract call", "email_secured_body": "For the security and privacy of your AXS wallet it's essential that you keep all information contained in this email strictly confidential. \nPlease follow these next steps carefully: \n1. Ensure you're the sole recipient of this email by replacing the recipient's address with your own. \n2. After confirming the correct email address, proceed to click the 'Send' button to forward this vital information to yourself securely. By adhering to these measures, you'll ensure the utmost safety for your AXS wallet. Thank you for your diligence in this matter.", "email_secured_subject": "Secure Your AXS Wallet Key - Important Instructions", "face_id": "Face ID", @@ -172,6 +173,7 @@ "all_transactions": "All transactions", "send_transactions": "Send transactions", "receive_transactions": "Receive transactions", + "contract_call_transactions": "Contract call transactions", "sort": "Sort", "new_to_old": "New to Old", "old_to_new": "Old to New", diff --git a/lib/common/components/recent_transactions/domain/mxc_transaction_use_case.dart b/lib/common/components/recent_transactions/domain/mxc_transaction_use_case.dart new file mode 100644 index 00000000..44bb44eb --- /dev/null +++ b/lib/common/components/recent_transactions/domain/mxc_transaction_use_case.dart @@ -0,0 +1,80 @@ +import 'package:datadashwallet/common/common.dart'; +import 'package:datadashwallet/core/core.dart'; +import 'package:mxc_logic/mxc_logic.dart'; +import 'package:web3dart/web3dart.dart'; + +class MXCTransactionsUseCase extends ReactiveUseCase { + MXCTransactionsUseCase(this._web3Repository); + + final Web3Repository _web3Repository; + + /// Will remove token transfer (tx that are in general transaction) from general transaction + List removeTokenTransfersFromTxList( + List txList, + List tokenTransferList) { + return txList.where((element) { + if (element.hash != null) { + // 1. Delete if txHash is null + // 2. Delete if tx is token transfer + return tokenTransferList.indexWhere( + (e) => e.txHash == null ? true : e.txHash == element.hash) == + -1; + } else { + return false; + } + }).toList(); + } + + void addTokenTransfersToTxList(List txList, + List tokenTransferList) { + for (int i = 0; i < tokenTransferList.length; i++) { + final item = tokenTransferList[i]; + txList.add(WannseeTransactionModel(tokenTransfers: [item])); + } + } + + List keepOnlySixTransactions( + List txList, + ) { + if (txList.length > 6) { + return txList.sublist(0, 6); + } + return txList; + } + + void sortByDate(List txList) { + if (txList.isNotEmpty) { + txList.sort((a, b) { + final item1 = a.timestamp ?? a.tokenTransfers![0].timestamp; + final item2 = b.timestamp ?? b.tokenTransfers![0].timestamp; + + return item2!.compareTo(item1!); + }); + } + } + + List axsTxListFromMxcTxList( + List mxcTxList, String walletAddress) { + return mxcTxList + .map((e) => TransactionModel.fromMXCTransaction(e, walletAddress)) + .toList(); + } + + void removeInvalidTx(List txList) { + txList.removeWhere( + (element) => element.hash == "Unknown", + ); + } + + List applyTxDateLimit( + List txList) { + final sevenDays = DateTime.now() + .subtract(Duration(days: Config.transactionsHistoryLimit)); + return txList.where((element) { + if (element.timestamp != null) { + return element.timestamp!.isAfter(sevenDays); + } + return element.tokenTransfers![0].timestamp!.isAfter(sevenDays); + }).toList(); + } +} diff --git a/lib/common/components/recent_transactions/recent_transactions.dart b/lib/common/components/recent_transactions/recent_transactions.dart index b0980d56..8a1e89f3 100644 --- a/lib/common/components/recent_transactions/recent_transactions.dart +++ b/lib/common/components/recent_transactions/recent_transactions.dart @@ -9,8 +9,8 @@ import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:mxc_ui/mxc_ui.dart'; -export 'domain/transactions_use_case.dart'; -export 'domain/transactions_repository.dart'; +export 'domain/transactions_history_use_case.dart'; +export 'domain/transactions_history_repository.dart'; class RecentTransactions extends HookConsumerWidget { const RecentTransactions({ diff --git a/lib/common/config.dart b/lib/common/config.dart index f5cc0d97..a85359c2 100644 --- a/lib/common/config.dart +++ b/lib/common/config.dart @@ -22,6 +22,9 @@ class Config { static int decimalShowFixed = 3; static int decimalWriteFixed = 8; + /// It's in days + static int transactionsHistoryLimit = 7; + static bool isMxcChains(int chainId) { return chainId == mxcMainnetChainId || chainId == mxcTestnetChainId; } diff --git a/lib/core/src/providers/providers_use_cases.dart b/lib/core/src/providers/providers_use_cases.dart index 58f11a30..a109c45e 100644 --- a/lib/core/src/providers/providers_use_cases.dart +++ b/lib/core/src/providers/providers_use_cases.dart @@ -1,4 +1,5 @@ import 'package:datadashwallet/common/common.dart'; +import 'package:datadashwallet/common/components/recent_transactions/domain/mxc_transaction_use_case.dart'; import 'package:datadashwallet/features/common/account/log_out_use_case.dart'; import 'package:datadashwallet/features/common/common.dart'; import 'package:datadashwallet/features/common/contract/chains_use_case.dart'; @@ -114,6 +115,13 @@ final Provider chainConfigurationUseCaseProvider = ), ); +final Provider mxcTransactionsUseCaseProvider = + Provider( + (ref) => MXCTransactionsUseCase( + ref.watch(web3RepositoryProvider), + ), +); + final Provider transactionHistoryUseCaseProvider = Provider( (ref) => TransactionsHistoryUseCase( From c1d9a97619e41cd01b9c2dd3fa6ef46a8d5910a9 Mon Sep 17 00:00:00 2001 From: reasje Date: Thu, 2 Nov 2023 16:24:31 +0330 Subject: [PATCH 3/4] feat: Added contract call to wallet page --- .../components/recent_transactions/utils.dart | 12 +++- .../widgets/recent_transaction_item.dart | 66 ++++++++++--------- .../presentation/wallet_page_presenter.dart | 59 +++++------------ 3 files changed, 60 insertions(+), 77 deletions(-) diff --git a/lib/common/components/recent_transactions/utils.dart b/lib/common/components/recent_transactions/utils.dart index 18d54aa2..9b2a09a5 100644 --- a/lib/common/components/recent_transactions/utils.dart +++ b/lib/common/components/recent_transactions/utils.dart @@ -37,6 +37,9 @@ class RecentTransactionsUtils { case TransactionType.received: txColor = ColorsTheme.of(context).greenMain; break; + case TransactionType.contractCall: + txColor = ColorsTheme.of(context).textGrey1; + break; default: txColor = ColorsTheme.of(context).mainRed; } @@ -52,6 +55,9 @@ class RecentTransactionsUtils { case TransactionType.received: txIcon = MxcIcons.receive; break; + case TransactionType.contractCall: + txIcon = Icons.article_rounded; + break; default: txIcon = Icons.question_mark; } @@ -85,11 +91,13 @@ class RecentTransactionsUtils { 'assets/svg/networks/unknown.svg'; final decimal = foundToken.decimals ?? e.token.decimals ?? Config.ethDecimals; - final symbol = foundToken.symbol ?? e.token.symbol ?? 'Unknown'; + final symbol = foundToken.symbol ?? e.token.symbol; return RecentTrxListItem( logoUrl: logoUrl, - amount: Formatter.convertWeiToEth(e.value, decimal), + amount: e.value == null + ? null + : Formatter.convertWeiToEth(e.value!, decimal), symbol: symbol, timestamp: e.timeStamp == null ? "Unknown" : Formatter.localTime(e.timeStamp!), diff --git a/lib/common/components/recent_transactions/widgets/recent_transaction_item.dart b/lib/common/components/recent_transactions/widgets/recent_transaction_item.dart index f5116b86..ac016c0b 100644 --- a/lib/common/components/recent_transactions/widgets/recent_transaction_item.dart +++ b/lib/common/components/recent_transactions/widgets/recent_transaction_item.dart @@ -11,8 +11,8 @@ import '../../../common.dart'; import '../utils.dart'; class RecentTrxListItem extends HookConsumerWidget { - final String amount; - final String symbol; + final String? amount; + final String? symbol; final String txHash; final String timestamp; final TransactionType transactionType; @@ -86,40 +86,42 @@ class RecentTrxListItem extends HookConsumerWidget { ), Row( children: [ - Text( - amount, - style: FontTheme.of(context) - .body1 - .primary() - .copyWith( - fontWeight: FontWeight.w500, - foreground: state.hideBalance == true - ? (Paint() - ..style = PaintingStyle.fill - ..color = Colors.white - ..maskFilter = const MaskFilter.blur( - BlurStyle.normal, 6)) - : null, - ), - softWrap: true, - ), + if (amount != null) + Text( + amount!, + style: FontTheme.of(context) + .body1 + .primary() + .copyWith( + fontWeight: FontWeight.w500, + foreground: state.hideBalance == true + ? (Paint() + ..style = PaintingStyle.fill + ..color = Colors.white + ..maskFilter = const MaskFilter.blur( + BlurStyle.normal, 6)) + : null, + ), + softWrap: true, + ), const SizedBox( width: 4, ), - Expanded( - child: Text( - symbol, - style: FontTheme.of(context).h7().copyWith( - fontSize: 16, - fontWeight: FontWeight.w400, - color: - ColorsTheme.of(context).textSecondary, - ), - textAlign: TextAlign.start, - overflow: TextOverflow.ellipsis, - softWrap: false, + if (symbol != null) + Expanded( + child: Text( + symbol!, + style: FontTheme.of(context).h7().copyWith( + fontSize: 16, + fontWeight: FontWeight.w400, + color: + ColorsTheme.of(context).textSecondary, + ), + textAlign: TextAlign.start, + overflow: TextOverflow.ellipsis, + softWrap: false, + ), ), - ), ], ), ], diff --git a/lib/features/wallet/presentation/wallet_page_presenter.dart b/lib/features/wallet/presentation/wallet_page_presenter.dart index b082b8f7..cb3bcb62 100644 --- a/lib/features/wallet/presentation/wallet_page_presenter.dart +++ b/lib/features/wallet/presentation/wallet_page_presenter.dart @@ -24,6 +24,7 @@ class WalletPresenter extends CompletePresenter { late final _balanceUseCase = ref.read(balanceHistoryUseCaseProvider); late final _transactionHistoryUseCase = ref.read(transactionHistoryUseCaseProvider); + late final _mxcTransactionsUseCase = ref.read(mxcTransactionsUseCaseProvider); @override void initState() { @@ -249,56 +250,28 @@ class WalletPresenter extends CompletePresenter { // loading over and we have the data state.isTxListLoading = false; // merge - if (newTransactionsList.items != null) { + if (newTransactionsList.items != null && + newTokenTransfersList.items != null) { + // Separating token transfer from all transaction since they have different structure newTransactionsList = newTransactionsList.copyWith( - items: newTransactionsList.items!.where((element) { - if (element.txTypes != null) { - return element.txTypes! - .any((element) => element == 'coin_transfer'); - } else { - return false; - } - }).toList()); + items: _mxcTransactionsUseCase.removeTokenTransfersFromTxList( + newTransactionsList.items!, newTokenTransfersList.items!)); } if (newTokenTransfersList.items != null) { - for (int i = 0; i < newTokenTransfersList.items!.length; i++) { - final item = newTokenTransfersList.items![i]; - newTransactionsList.items! - .add(WannseeTransactionModel(tokenTransfers: [item])); - } - if (newTransactionsList.items!.isNotEmpty) { - newTransactionsList.items!.sort((a, b) { - if (b.timestamp == null && a.timestamp == null) { - // both token transfer - return b.tokenTransfers![0].timestamp! - .compareTo(a.tokenTransfers![0].timestamp!); - } else if (b.timestamp != null && a.timestamp != null) { - // both coin transfer - return b.timestamp!.compareTo(a.timestamp!); - } else if (b.timestamp == null) { - // b is token transfer - return b.tokenTransfers![0].timestamp!.compareTo(a.timestamp!); - } else { - // a is token transfer - return b.timestamp!.compareTo(a.tokenTransfers![0].timestamp!); - } - }); - } + _mxcTransactionsUseCase.addTokenTransfersToTxList( + newTransactionsList.items!, newTokenTransfersList.items!); - if (newTransactionsList.items!.length > 6) { - newTransactionsList = newTransactionsList.copyWith( - items: newTransactionsList.items!.sublist(0, 6)); - } + _mxcTransactionsUseCase.sortByDate(newTransactionsList.items!); + + newTransactionsList = newTransactionsList.copyWith( + items: _mxcTransactionsUseCase + .keepOnlySixTransactions(newTransactionsList.items!)); - final finalTxList = newTransactionsList.items! - .map((e) => TransactionModel.fromMXCTransaction( - e, state.account!.address)) - .toList(); + final finalTxList = _mxcTransactionsUseCase.axsTxListFromMxcTxList( + newTransactionsList.items!, state.account!.address); - finalTxList.removeWhere( - (element) => element.hash == "Unknown", - ); + _mxcTransactionsUseCase.removeInvalidTx(finalTxList); notify(() => state.txList = finalTxList); } From e2c1b2d17bcc6bf2b51bdba12c9ef1f023a6b093 Mon Sep 17 00:00:00 2001 From: reasje Date: Thu, 2 Nov 2023 16:25:09 +0330 Subject: [PATCH 4/4] feat: Added contract call to tx history page --- .../transaction_history_presenter.dart | 72 +++++++------------ .../widgets/filter_and_sort_items.dart | 3 +- packages/shared | 2 +- 3 files changed, 27 insertions(+), 50 deletions(-) diff --git a/lib/features/portfolio/subfeatures/transaction_history/transaction_history_presenter.dart b/lib/features/portfolio/subfeatures/transaction_history/transaction_history_presenter.dart index 5e0e0601..3a318192 100644 --- a/lib/features/portfolio/subfeatures/transaction_history/transaction_history_presenter.dart +++ b/lib/features/portfolio/subfeatures/transaction_history/transaction_history_presenter.dart @@ -20,6 +20,7 @@ class TransactionHistoryPresenter late final _accountUserCase = ref.read(accountUseCaseProvider); late final _transactionHistoryUseCase = ref.read(transactionHistoryUseCaseProvider); + late final _mxcTransactionsUseCase = ref.read(mxcTransactionsUseCaseProvider); @override void initState() { @@ -92,61 +93,30 @@ class TransactionHistoryPresenter if (newTokenTransfersList != null && newTransactionsList != null) { // loading over and we have the data // merge - if (newTransactionsList.items != null) { - newTransactionsList = newTransactionsList.copyWith( - items: newTransactionsList.items!.where((element) { - if (element.txTypes != null) { - return element.txTypes! - .any((element) => element == 'coin_transfer'); - } else { - return false; - } - }).toList()); - } + newTransactionsList = newTransactionsList.copyWith( + items: _mxcTransactionsUseCase.removeTokenTransfersFromTxList( + newTransactionsList.items!, newTokenTransfersList.items!)); if (newTokenTransfersList.items != null) { - for (int i = 0; i < newTokenTransfersList.items!.length; i++) { - final item = newTokenTransfersList.items![i]; - newTransactionsList.items! - .add(WannseeTransactionModel(tokenTransfers: [item])); - } - if (newTransactionsList.items!.isNotEmpty) { - newTransactionsList.items!.sort((a, b) { - final item1 = a.timestamp ?? a.tokenTransfers![0].timestamp; - final item2 = b.timestamp ?? b.tokenTransfers![0].timestamp; + _mxcTransactionsUseCase.addTokenTransfersToTxList( + newTransactionsList.items!, newTokenTransfersList.items!); - return item2!.compareTo(item1!); - }); - } + _mxcTransactionsUseCase.sortByDate(newTransactionsList.items!); - final sevenDays = DateTime.now().subtract(const Duration(days: 7)); + final sevenDays = DateTime.now() + .subtract(Duration(days: Config.transactionsHistoryLimit)); newTransactionsList = newTransactionsList.copyWith( - items: newTransactionsList.items!.where((element) { - if (element.timestamp != null) { - return element.timestamp!.isAfter(sevenDays); - } - return element.tokenTransfers![0].timestamp!.isAfter(sevenDays); - }).toList()); + items: _mxcTransactionsUseCase + .applyTxDateLimit(newTransactionsList.items!)); - newTransactionsList = newTransactionsList.copyWith( - items: newTransactionsList.items!.where((element) { - if (element.timestamp != null) { - return element.timestamp!.isAfter(sevenDays); - } - return element.tokenTransfers![0].timestamp!.isAfter(sevenDays); - }).toList()); + final finalTxList = _mxcTransactionsUseCase.axsTxListFromMxcTxList( + newTransactionsList.items!, state.account!.address); - final newTxList = newTransactionsList.items! - .map((e) => TransactionModel.fromMXCTransaction( - e, state.account!.address)) - .toList(); - newTxList.removeWhere( - (element) => element.hash == "Unknown", - ); + _mxcTransactionsUseCase.removeInvalidTx(finalTxList); notify(() { - state.transactions = newTxList; - state.filterTransactions = newTxList; + state.transactions = finalTxList; + state.filterTransactions = finalTxList; }); } } @@ -181,6 +151,12 @@ class TransactionHistoryPresenter return transactionType == item.type; }).toList(); + if (SortOption.amount == sortOption) { + result = state.transactions!.where((item) { + return TransactionType.contractCall != item.type; + }).toList(); + } + result.sort((a, b) { if (SortOption.date == sortOption) { final item1 = a.timeStamp; @@ -194,8 +170,8 @@ class TransactionHistoryPresenter return item2.compareTo(item1); } } else { - final item1 = double.parse(a.value); - final item2 = double.parse(b.value); + final item1 = double.parse(a.value!); + final item2 = double.parse(b.value!); if (SortType.increase == amountSort) { return item1.compareTo(item2); diff --git a/lib/features/portfolio/subfeatures/transaction_history/widgets/filter_and_sort_items.dart b/lib/features/portfolio/subfeatures/transaction_history/widgets/filter_and_sort_items.dart index db2ed3c4..8bb524d7 100644 --- a/lib/features/portfolio/subfeatures/transaction_history/widgets/filter_and_sort_items.dart +++ b/lib/features/portfolio/subfeatures/transaction_history/widgets/filter_and_sort_items.dart @@ -53,7 +53,8 @@ class _FilterAndSortItemsState extends State { ...{ 'all_transactions': TransactionType.all, 'send_transactions': TransactionType.sent, - 'receive_transactions': TransactionType.received + 'receive_transactions': TransactionType.received, + 'contract_call_transactions': TransactionType.contractCall } .entries .map( diff --git a/packages/shared b/packages/shared index 7a04fbb9..378f9c44 160000 --- a/packages/shared +++ b/packages/shared @@ -1 +1 @@ -Subproject commit 7a04fbb9b4157b79470eb7368d3f12e56efe962a +Subproject commit 378f9c4407e9f6494fa34d528c457076adee0a2c