mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 11:39:22 +00:00
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:
parent
40c2712f55
commit
1690f6af1e
13 changed files with 79 additions and 7 deletions
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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'))
|
||||||
|
|
|
@ -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'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue