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

David Adegoke committed Sep 5, 2025 at 22:05 UTC 31b9bb7f539849bb7d17ff7487666bf43c654965
1 file changed +5 -64
lib/view_model/dashboard/home_settings_view_model.dart
+5 -64
@@ -81,7 +81,7 @@ abstract class HomeSettingsViewModelBase with Store {
81 name: token.name,
82 symbol: token.title,
83 decimal: token.decimals,
84 - contractAddress: contractAddress,
84 + contractAddress: contractAddress.toLowerCase(),
85 iconPath: token.iconPath,
86 isPotentialScam: token.isPotentialScam,
87 );
@@ -94,7 +94,7 @@ abstract class HomeSettingsViewModelBase with Store {
94 name: token.name,
95 symbol: token.title,
96 decimal: token.decimals,
97 - contractAddress: contractAddress,
97 + contractAddress: contractAddress.toLowerCase(),
98 iconPath: token.iconPath,
99 isPotentialScam: token.isPotentialScam,
100 );
@@ -198,18 +198,12 @@ abstract class HomeSettingsViewModelBase with Store {
198 isEthereum ? 'eth' : 'polygon',
199 );
200
201 - bool isPotentialScamViaExplorers = await _isPotentialScamTokenViaExplorers(
202 - contractAddress,
203 - isEthereum: isEthereum,
204 - );
205 -
201 bool isUnverifiedContract = await _isContractUnverified(
202 contractAddress,
203 isEthereum: isEthereum,
204 );
205
211 - final showWarningForContractAddress =
212 - isPotentialScamViaMoralis || isUnverifiedContract || isPotentialScamViaExplorers;
206 + final showWarningForContractAddress = isPotentialScamViaMoralis || isUnverifiedContract;
207
208 return showWarningForContractAddress;
209 } finally {
@@ -275,7 +269,7 @@ abstract class HomeSettingsViewModelBase with Store {
269 "X-API-Key": secrets.moralisApiKey,
270 },
271 );
278 -
272 +
273 final decodedResponse = jsonDecode(response.body);
274
275 final tokenInfo = Erc20TokenInfoMoralis.fromJson(decodedResponse[0] as Map<String, dynamic>);
@@ -291,12 +285,7 @@ abstract class HomeSettingsViewModelBase with Store {
285 }
286
287 // Tokens with a security score less than 40 are potentially risky, requiring caution when dealing with them.
294 - if (tokenInfo.securityScore == null || tokenInfo.securityScore! < 40) {
295 - return true;
296 - }
297 -
298 - // 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.
299 - if (tokenInfo.links?.website == null || tokenInfo.links!.website!.isEmpty) {
288 + if (tokenInfo.securityScore != null && tokenInfo.securityScore! < 40) {
289 return true;
290 }
291
@@ -308,11 +297,6 @@ abstract class HomeSettingsViewModelBase with Store {
297 return true;
298 }
299
311 - // I mean, a logo is the most basic of all the potential causes, but why does your fully functional project not have a logo?
312 - if (tokenInfo.logo == null) {
313 - return true;
314 - }
315 -
300 return false;
301 } catch (e) {
302 printV('Error while checking scam via moralis: ${e.toString()}');
@@ -320,48 +304,6 @@ abstract class HomeSettingsViewModelBase with Store {
304 }
305 }
306
323 - Future<bool> _isPotentialScamTokenViaExplorers(
324 - String contractAddress, {
325 - required bool isEthereum,
326 - }) async {
327 - final uri = Uri.https(
328 - "api.etherscan.io",
329 - "/v2/api",
330 - {
331 - "chainid": isEthereum ? "1" : "137",
332 - "module": "token",
333 - "action": "tokeninfo",
334 - "contractaddress": contractAddress,
335 - "apikey": secrets.etherScanApiKey,
336 - },
337 - );
338 -
339 - try {
340 - final response = await ProxyWrapper().get(clearnetUri: uri);
341 -
342 - final decodedResponse = jsonDecode(response.body) as Map<String, dynamic>;
343 -
344 - if (decodedResponse['status'] != '1') {
345 - log('${response.body}\n');
346 - log('${decodedResponse['result']}\n');
347 - return true;
348 - }
349 -
350 - final tokenInfo =
351 - Erc20TokenInfoExplorers.fromJson(decodedResponse['result'][0] as Map<String, dynamic>);
352 -
353 - // A token without a website is a potential red flag
354 - if (tokenInfo.website?.isEmpty == true) {
355 - return true;
356 - }
357 -
358 - return false;
359 - } catch (e) {
360 - printV('Error while checking scam via explorers: ${e.toString()}');
361 - return true;
362 - }
363 - }
364 -
307 Future<bool> _isContractUnverified(
308 String contractAddress, {
309 required bool isEthereum,
@@ -380,7 +322,6 @@ abstract class HomeSettingsViewModelBase with Store {
322
323 try {
324 final response = await ProxyWrapper().get(clearnetUri: uri);
383 -
325
326 final decodedResponse = jsonDecode(response.body) as Map<String, dynamic>;
327