Erc20 token transactions are displaying incorrectly (#1493)

* evm signature name

* hide depositWithExpiry and transfer transactions

* Update contact_list_view_model.dart

* remove erc20 token history when disabled
This commit is contained in:
Serhii 2024-06-20 23:13:12 +00:00 committed by GitHub
parent 40c2712f55
commit 1690f6af1e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 79 additions and 7 deletions

View file

@ -16,6 +16,7 @@ abstract class TransactionInfo extends Object with Keyable {
void changeFiatAmount(String amount); void changeFiatAmount(String amount);
String? to; String? to;
String? from; String? from;
String? evmSignatureName;
List<String>? inputAddresses; List<String>? inputAddresses;
List<String>? outputAddresses; List<String>? outputAddresses;

View file

@ -29,6 +29,11 @@ class EthereumClient extends EVMChainClient {
final jsonResponse = json.decode(response.body) as Map<String, dynamic>; final jsonResponse = json.decode(response.body) as Map<String, dynamic>;
if (jsonResponse['result'] is String) {
log(jsonResponse['result']);
return [];
}
if (response.statusCode >= 200 && response.statusCode < 300 && jsonResponse['status'] != 0) { if (response.statusCode >= 200 && response.statusCode < 300 && jsonResponse['status'] != 0) {
return (jsonResponse['result'] as List) return (jsonResponse['result'] as List)
.map((e) => EVMChainTransactionModel.fromJson(e as Map<String, dynamic>, 'ETH')) .map((e) => EVMChainTransactionModel.fromJson(e as Map<String, dynamic>, 'ETH'))

View file

@ -14,6 +14,7 @@ class EthereumTransactionInfo extends EVMChainTransactionInfo {
required super.confirmations, required super.confirmations,
required super.to, required super.to,
required super.from, required super.from,
super.evmSignatureName,
super.exponent, super.exponent,
}); });
@ -31,6 +32,7 @@ class EthereumTransactionInfo extends EVMChainTransactionInfo {
tokenSymbol: data['tokenSymbol'] as String, tokenSymbol: data['tokenSymbol'] as String,
to: data['to'], to: data['to'],
from: data['from'], from: data['from'],
evmSignatureName: data['evmSignatureName'],
); );
} }

View file

@ -94,6 +94,7 @@ class EthereumWallet extends EVMChainWallet {
tokenSymbol: transactionModel.tokenSymbol ?? "ETH", tokenSymbol: transactionModel.tokenSymbol ?? "ETH",
to: transactionModel.to, to: transactionModel.to,
from: transactionModel.from, from: transactionModel.from,
evmSignatureName: transactionModel.evmSignatureName,
); );
return model; return model;
} }

View file

@ -20,6 +20,7 @@ abstract class EVMChainTransactionInfo extends TransactionInfo {
required this.confirmations, required this.confirmations,
required this.to, required this.to,
required this.from, required this.from,
this.evmSignatureName,
}) : amount = ethAmount.toInt(), }) : amount = ethAmount.toInt(),
fee = ethFee.toInt(); fee = ethFee.toInt();
@ -38,6 +39,7 @@ abstract class EVMChainTransactionInfo extends TransactionInfo {
String? _fiatAmount; String? _fiatAmount;
final String? to; final String? to;
final String? from; final String? from;
final String? evmSignatureName;
//! Getter to be overridden in child classes //! Getter to be overridden in child classes
String get feeCurrency; String get feeCurrency;
@ -73,5 +75,6 @@ abstract class EVMChainTransactionInfo extends TransactionInfo {
'tokenSymbol': tokenSymbol, 'tokenSymbol': tokenSymbol,
'to': to, 'to': to,
'from': from, 'from': from,
'evmSignatureName': evmSignatureName,
}; };
} }

View file

@ -12,6 +12,8 @@ class EVMChainTransactionModel {
final String? tokenSymbol; final String? tokenSymbol;
final int? tokenDecimal; final int? tokenDecimal;
final bool isError; final bool isError;
final String input;
String? evmSignatureName;
EVMChainTransactionModel({ EVMChainTransactionModel({
required this.date, required this.date,
@ -27,6 +29,8 @@ class EVMChainTransactionModel {
required this.tokenSymbol, required this.tokenSymbol,
required this.tokenDecimal, required this.tokenDecimal,
required this.isError, required this.isError,
required this.input,
this.evmSignatureName,
}); });
factory EVMChainTransactionModel.fromJson(Map<String, dynamic> json, String defaultSymbol) => factory EVMChainTransactionModel.fromJson(Map<String, dynamic> json, String defaultSymbol) =>
@ -44,5 +48,7 @@ class EVMChainTransactionModel {
tokenSymbol: json["tokenSymbol"] ?? defaultSymbol, tokenSymbol: json["tokenSymbol"] ?? defaultSymbol,
tokenDecimal: int.tryParse(json["tokenDecimal"] ?? ""), tokenDecimal: int.tryParse(json["tokenDecimal"] ?? ""),
isError: json["isError"] == "1", isError: json["isError"] == "1",
input: json["input"] ?? "",
evmSignatureName: json["evmSignatureName"],
); );
} }

View file

@ -39,6 +39,20 @@ import 'evm_erc20_balance.dart';
part 'evm_chain_wallet.g.dart'; part 'evm_chain_wallet.g.dart';
const Map<String, String> methodSignatureToType = {
'0x095ea7b3': 'approval',
'0xa9059cbb': 'transfer',
'0x23b872dd': 'transferFrom',
'0x574da717': 'transferOut',
'0x2e1a7d4d': 'withdraw',
'0x7ff36ab5': 'swapExactETHForTokens',
'0x40c10f19': 'mint',
'0x44bc937b': 'depositWithExpiry',
'0xd0e30db0': 'deposit',
'0xe8e33700': 'addLiquidity',
'0xd505accf': 'permit',
};
abstract class EVMChainWallet = EVMChainWalletBase with _$EVMChainWallet; abstract class EVMChainWallet = EVMChainWalletBase with _$EVMChainWallet;
abstract class EVMChainWalletBase abstract class EVMChainWalletBase
@ -235,7 +249,8 @@ abstract class EVMChainWalletBase
String? hexOpReturnMemo; String? hexOpReturnMemo;
if (opReturnMemo != null) { if (opReturnMemo != null) {
hexOpReturnMemo = '0x${opReturnMemo.codeUnits.map((char) => char.toRadixString(16).padLeft(2, '0')).join()}'; hexOpReturnMemo =
'0x${opReturnMemo.codeUnits.map((char) => char.toRadixString(16).padLeft(2, '0')).join()}';
} }
final CryptoCurrency transactionCurrency = final CryptoCurrency transactionCurrency =
@ -337,11 +352,21 @@ abstract class EVMChainWalletBase
@override @override
Future<Map<String, EVMChainTransactionInfo>> fetchTransactions() async { Future<Map<String, EVMChainTransactionInfo>> fetchTransactions() async {
final List<EVMChainTransactionModel> transactions = [];
final List<Future<List<EVMChainTransactionModel>>> erc20TokensTransactions = [];
final address = _evmChainPrivateKey.address.hex; final address = _evmChainPrivateKey.address.hex;
final transactions = await _client.fetchTransactions(address); final externalTransactions = await _client.fetchTransactions(address);
final internalTransactions = await _client.fetchInternalTransactions(address); final internalTransactions = await _client.fetchInternalTransactions(address);
final List<Future<List<EVMChainTransactionModel>>> erc20TokensTransactions = []; for (var transaction in externalTransactions) {
final evmSignatureName = analyzeTransaction(transaction.input);
if (evmSignatureName != 'depositWithExpiry' && evmSignatureName != 'transfer') {
transaction.evmSignatureName = evmSignatureName;
transactions.add(transaction);
}
}
for (var token in balance.keys) { for (var token in balance.keys) {
if (token is Erc20Token) { if (token is Erc20Token) {
@ -369,6 +394,17 @@ abstract class EVMChainWalletBase
return result; return result;
} }
String? analyzeTransaction(String? transactionInput) {
if (transactionInput == '0x' || transactionInput == null || transactionInput.isEmpty) {
return 'simpleTransfer';
}
final methodSignature =
transactionInput.length >= 10 ? transactionInput.substring(0, 10) : null;
return methodSignatureToType[methodSignature];
}
@override @override
Object get keys => throw UnimplementedError("keys"); Object get keys => throw UnimplementedError("keys");
@ -482,11 +518,11 @@ abstract class EVMChainWalletBase
await token.delete(); await token.delete();
balance.remove(token); balance.remove(token);
await _removeTokenTransactionsInHistory(token); await removeTokenTransactionsInHistory(token);
_updateBalance(); _updateBalance();
} }
Future<void> _removeTokenTransactionsInHistory(Erc20Token token) async { Future<void> removeTokenTransactionsInHistory(Erc20Token token) async {
transactionHistory.transactions.removeWhere((key, value) => value.tokenSymbol == token.title); transactionHistory.transactions.removeWhere((key, value) => value.tokenSymbol == token.title);
await transactionHistory.save(); await transactionHistory.save();
} }

View file

@ -137,6 +137,10 @@ class CWEthereum extends Ethereum {
Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token) async => Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token) async =>
await (wallet as EthereumWallet).deleteErc20Token(token as Erc20Token); await (wallet as EthereumWallet).deleteErc20Token(token as Erc20Token);
@override
Future<void> removeTokenTransactionsInHistory(WalletBase wallet, CryptoCurrency token) async =>
await (wallet as EthereumWallet).removeTokenTransactionsInHistory(token as Erc20Token);
@override @override
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async { Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async {
final ethereumWallet = wallet as EthereumWallet; final ethereumWallet = wallet as EthereumWallet;

View file

@ -135,6 +135,10 @@ class CWPolygon extends Polygon {
Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token) async => Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token) async =>
await (wallet as PolygonWallet).deleteErc20Token(token as Erc20Token); await (wallet as PolygonWallet).deleteErc20Token(token as Erc20Token);
@override
Future<void> removeTokenTransactionsInHistory(WalletBase wallet, CryptoCurrency token) async =>
await (wallet as PolygonWallet).removeTokenTransactionsInHistory(token as Erc20Token);
@override @override
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async { Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async {
final polygonWallet = wallet as PolygonWallet; final polygonWallet = wallet as PolygonWallet;

View file

@ -8,6 +8,7 @@ import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.d
import 'package:cake_wallet/view_model/dashboard/order_list_item.dart'; import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
@ -87,6 +88,10 @@ class TransactionsPage extends StatelessWidget {
} }
final transaction = item.transaction; final transaction = item.transaction;
final transactionType = dashboardViewModel.type == WalletType.ethereum &&
transaction.evmSignatureName == 'approval'
? ' (${transaction.evmSignatureName})'
: '';
return Observer( return Observer(
builder: (_) => TransactionRow( builder: (_) => TransactionRow(
@ -100,7 +105,8 @@ class TransactionsPage extends StatelessWidget {
? '' ? ''
: item.formattedFiatAmount, : item.formattedFiatAmount,
isPending: transaction.isPending, isPending: transaction.isPending,
title: item.formattedTitle + item.formattedStatus, title: item.formattedTitle +
item.formattedStatus + ' $transactionType',
), ),
); );
} }

View file

@ -39,7 +39,7 @@ abstract class ContactListViewModelBase with Store {
)); ));
} }
}); });
} else if (info.addresses?.isNotEmpty == true) { } else if (info.addresses?.isNotEmpty == true && info.addresses!.length > 1) {
info.addresses!.forEach((address, label) { info.addresses!.forEach((address, label) {
if (label.isEmpty) { if (label.isEmpty) {
return; return;

View file

@ -144,10 +144,12 @@ abstract class HomeSettingsViewModelBase with Store {
if (_balanceViewModel.wallet.type == WalletType.ethereum) { if (_balanceViewModel.wallet.type == WalletType.ethereum) {
ethereum!.addErc20Token(_balanceViewModel.wallet, token as Erc20Token); ethereum!.addErc20Token(_balanceViewModel.wallet, token as Erc20Token);
if (!value) ethereum!.removeTokenTransactionsInHistory(_balanceViewModel.wallet, token);
} }
if (_balanceViewModel.wallet.type == WalletType.polygon) { if (_balanceViewModel.wallet.type == WalletType.polygon) {
polygon!.addErc20Token(_balanceViewModel.wallet, token as Erc20Token); polygon!.addErc20Token(_balanceViewModel.wallet, token as Erc20Token);
if (!value) polygon!.removeTokenTransactionsInHistory(_balanceViewModel.wallet, token);
} }
if (_balanceViewModel.wallet.type == WalletType.solana) { if (_balanceViewModel.wallet.type == WalletType.solana) {

View file

@ -667,6 +667,7 @@ abstract class Ethereum {
List<Erc20Token> getERC20Currencies(WalletBase wallet); List<Erc20Token> getERC20Currencies(WalletBase wallet);
Future<void> addErc20Token(WalletBase wallet, CryptoCurrency token); Future<void> addErc20Token(WalletBase wallet, CryptoCurrency token);
Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token); Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token);
Future<void> removeTokenTransactionsInHistory(WalletBase wallet, CryptoCurrency token);
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress); Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress);
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction); CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction);
@ -770,6 +771,7 @@ abstract class Polygon {
List<Erc20Token> getERC20Currencies(WalletBase wallet); List<Erc20Token> getERC20Currencies(WalletBase wallet);
Future<void> addErc20Token(WalletBase wallet, CryptoCurrency token); Future<void> addErc20Token(WalletBase wallet, CryptoCurrency token);
Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token); Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token);
Future<void> removeTokenTransactionsInHistory(WalletBase wallet, CryptoCurrency token);
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress); Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress);
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction); CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction);