Ease potential scam checks and handle case-insensitive addresses (#2497)

This commit is contained in:
David Adegoke
2025-09-06 00:05:06 +03:00
committed by GitHub
parent 2dc95b2bf0
commit 31b9bb7f53
@@ -81,7 +81,7 @@ abstract class HomeSettingsViewModelBase with Store {
name: token.name,
symbol: token.title,
decimal: token.decimals,
contractAddress: contractAddress,
contractAddress: contractAddress.toLowerCase(),
iconPath: token.iconPath,
isPotentialScam: token.isPotentialScam,
);
@@ -94,7 +94,7 @@ abstract class HomeSettingsViewModelBase with Store {
name: token.name,
symbol: token.title,
decimal: token.decimals,
contractAddress: contractAddress,
contractAddress: contractAddress.toLowerCase(),
iconPath: token.iconPath,
isPotentialScam: token.isPotentialScam,
);
@@ -198,18 +198,12 @@ abstract class HomeSettingsViewModelBase with Store {
isEthereum ? 'eth' : 'polygon',
);
bool isPotentialScamViaExplorers = await _isPotentialScamTokenViaExplorers(
contractAddress,
isEthereum: isEthereum,
);
bool isUnverifiedContract = await _isContractUnverified(
contractAddress,
isEthereum: isEthereum,
);
final showWarningForContractAddress =
isPotentialScamViaMoralis || isUnverifiedContract || isPotentialScamViaExplorers;
final showWarningForContractAddress = isPotentialScamViaMoralis || isUnverifiedContract;
return showWarningForContractAddress;
} finally {
@@ -275,7 +269,7 @@ abstract class HomeSettingsViewModelBase with Store {
"X-API-Key": secrets.moralisApiKey,
},
);
final decodedResponse = jsonDecode(response.body);
final tokenInfo = Erc20TokenInfoMoralis.fromJson(decodedResponse[0] as Map<String, dynamic>);
@@ -291,12 +285,7 @@ abstract class HomeSettingsViewModelBase with Store {
}
// Tokens with a security score less than 40 are potentially risky, requiring caution when dealing with them.
if (tokenInfo.securityScore == null || tokenInfo.securityScore! < 40) {
return true;
}
// Absence of a website URL for an ERC-20 token can be a potential red flag. A legitimate ERC-20 projects should have a well-maintained website that provides information about the token, its purpose, team, and roadmap.
if (tokenInfo.links?.website == null || tokenInfo.links!.website!.isEmpty) {
if (tokenInfo.securityScore != null && tokenInfo.securityScore! < 40) {
return true;
}
@@ -308,11 +297,6 @@ abstract class HomeSettingsViewModelBase with Store {
return true;
}
// I mean, a logo is the most basic of all the potential causes, but why does your fully functional project not have a logo?
if (tokenInfo.logo == null) {
return true;
}
return false;
} catch (e) {
printV('Error while checking scam via moralis: ${e.toString()}');
@@ -320,48 +304,6 @@ abstract class HomeSettingsViewModelBase with Store {
}
}
Future<bool> _isPotentialScamTokenViaExplorers(
String contractAddress, {
required bool isEthereum,
}) async {
final uri = Uri.https(
"api.etherscan.io",
"/v2/api",
{
"chainid": isEthereum ? "1" : "137",
"module": "token",
"action": "tokeninfo",
"contractaddress": contractAddress,
"apikey": secrets.etherScanApiKey,
},
);
try {
final response = await ProxyWrapper().get(clearnetUri: uri);
final decodedResponse = jsonDecode(response.body) as Map<String, dynamic>;
if (decodedResponse['status'] != '1') {
log('${response.body}\n');
log('${decodedResponse['result']}\n');
return true;
}
final tokenInfo =
Erc20TokenInfoExplorers.fromJson(decodedResponse['result'][0] as Map<String, dynamic>);
// A token without a website is a potential red flag
if (tokenInfo.website?.isEmpty == true) {
return true;
}
return false;
} catch (e) {
printV('Error while checking scam via explorers: ${e.toString()}');
return true;
}
}
Future<bool> _isContractUnverified(
String contractAddress, {
required bool isEthereum,
@@ -380,7 +322,6 @@ abstract class HomeSettingsViewModelBase with Store {
try {
final response = await ProxyWrapper().get(clearnetUri: uri);
final decodedResponse = jsonDecode(response.body) as Map<String, dynamic>;