mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
Generic Token Fixes (#2873)
* feat: Automatically detect wallet tokens for EVM chains * feat: Disable potential tg scam tokens by default * feat: Add homoglyph normalization to detect spoofing attacks in token symbols * refactor: Improve scam token detection and apply to automatically fetched EVM tokens * refactor: Enhance scam detection for automatically detected tokens in evm wallets * feat: Add fiat check to scam checks on automatically imported token and disable tokens that fail the check * feat: Add fiat check to scam checks on automatically imported token and disable tokens that fail the check * feat: Add fiat check to scam checks on automatically imported token and disable tokens that fail the check * feat: Enable whitelisted tokens with balance when importing wallet tokens * feat: Disable imported tokens with balance less than 0.1 usd * feat: Disable imported tokens with balance less than 0.1 usd - Update configure file * fixes: - default tokens marked as potential scam - ui overflow for token name on balance page - add more filters for spam tokens
This commit is contained in:
@@ -442,8 +442,6 @@ abstract class EVMChainWalletBase
|
||||
}
|
||||
|
||||
bool isTokenPropertiesSuspicious(Erc20Token token) {
|
||||
final baseCurrencySymbols = CryptoCurrency.all.map((e) => e.title.toUpperCase()).toList();
|
||||
|
||||
bool isTokenWhitelisted = getDefaultTokenContractAddresses
|
||||
.any((element) => element.toLowerCase() == token.contractAddress.toLowerCase());
|
||||
|
||||
@@ -459,10 +457,18 @@ abstract class EVMChainWalletBase
|
||||
'http',
|
||||
'https',
|
||||
'.com',
|
||||
'.org',
|
||||
'.top',
|
||||
'.live',
|
||||
'airdrop',
|
||||
'reward',
|
||||
'distribution',
|
||||
'www',
|
||||
'.xyz',
|
||||
'🎁',
|
||||
'bot',
|
||||
'claim',
|
||||
'reward',
|
||||
];
|
||||
|
||||
final hasSuspiciousData = suspiciousStrings.any(
|
||||
@@ -472,11 +478,10 @@ abstract class EVMChainWalletBase
|
||||
normalizedTitle.toLowerCase().contains(element),
|
||||
);
|
||||
|
||||
// Check if the token symbol is the same as any of the base currencies symbols (ETH, SOL, POL, TRX, etc).
|
||||
// If it is, then it's probably a scam unless it's in the whitelist.
|
||||
final hasSuspiciousSymbol = baseCurrencySymbols.contains(normalizedSymbol);
|
||||
final nativeSymbol = currency.title.toUpperCase();
|
||||
final hasSuspiciousSymbol = normalizedSymbol == nativeSymbol && !isTokenWhitelisted;
|
||||
|
||||
return hasSuspiciousData || (hasSuspiciousSymbol && !isTokenWhitelisted);
|
||||
return hasSuspiciousData || hasSuspiciousSymbol;
|
||||
}
|
||||
|
||||
Future<void> _checkForExistingScamTokens() async {
|
||||
@@ -1287,6 +1292,9 @@ abstract class EVMChainWalletBase
|
||||
}
|
||||
|
||||
Future<void> addErc20Token(Erc20Token token) async {
|
||||
final isSuspicious = isTokenPropertiesSuspicious(token);
|
||||
token.isPotentialScam = token.isPotentialScam || isSuspicious;
|
||||
|
||||
String? iconPath;
|
||||
|
||||
if ((token.iconPath == null || token.iconPath!.isEmpty) && !token.isPotentialScam) {
|
||||
|
||||
@@ -230,19 +230,18 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
|
||||
);
|
||||
|
||||
bool isPotentialScam = hasPotentialError && !isWhitelisted;
|
||||
final tokenSymbol = _tokenSymbolController.text.toUpperCase();
|
||||
|
||||
// check if the token symbol is the same as any of the base currencies symbols (ETH, SOL, POL, TRX, etc):
|
||||
// if it is, then it's probably a scam unless it's in the whitelist
|
||||
|
||||
// ugh, should it be commented out?
|
||||
// because there are some tokens that has the name of original currencies
|
||||
// like: 0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6
|
||||
|
||||
final baseCurrencySymbols =
|
||||
CryptoCurrency.all.map((e) => e.title.toUpperCase()).toList();
|
||||
if (baseCurrencySymbols.contains(tokenSymbol.trim().toUpperCase()) &&
|
||||
!isWhitelisted) {
|
||||
// check if the token symbol is the same as the native token symbol
|
||||
// to prevent token impersonation
|
||||
// (e.g. fake ETH on Ethereum, fake SOL on Solana)
|
||||
final tokenSymbol = _tokenSymbolController.text
|
||||
.trim()
|
||||
.toUpperCase();
|
||||
final nativeSymbol = widget.homeSettingsViewModel
|
||||
.nativeToken
|
||||
.title
|
||||
.toUpperCase();
|
||||
if (tokenSymbol == nativeSymbol && !isWhitelisted) {
|
||||
isPotentialScam = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -173,46 +173,44 @@ class BalanceRowWidget extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
//width: min(MediaQuery.of(context).size.width * 0.2, 100),
|
||||
child: Center(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
CakeImageWidget(
|
||||
imageUrl: currency.iconPath,
|
||||
height: 40,
|
||||
width: 40,
|
||||
errorWidget: Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: Center(
|
||||
child: Text(
|
||||
currency.title.substring(0, min(currency.title.length, 2)),
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
fontSize: 11,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
CakeImageWidget(
|
||||
imageUrl: currency.iconPath,
|
||||
height: 40,
|
||||
width: 40,
|
||||
errorWidget: Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: Center(
|
||||
child: Text(
|
||||
currency.title.substring(0, min(currency.title.length, 2)),
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
fontSize: 11,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
currency.title,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
currency.title,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user