CW-608-Fetch-And-Save-Icons-Of-ERC20-And-SPL-Tokens-When-Adding-Them (#1365)

* feat: Fetch and save icons of SPL tokens when adding them

* feat: Implement fetch and save icons for ERC20 tokens when adding them

* fix: Add moralisApiKey to evm secrets

* Add check to ensure decimals cannot be zero

* - Fallback to adding erc20 token from web3dart
- Wrap fetching spl token icon in a try/catch block

---------

Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
This commit is contained in:
Adegoke David 2024-04-08 23:53:14 +01:00 committed by GitHub
parent d4b317b3a0
commit 2877cc160c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 182 additions and 69 deletions

View file

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'package:cw_core/node.dart';
@ -9,6 +10,7 @@ import 'package:cw_evm/evm_erc20_balance.dart';
import 'package:cw_evm/evm_chain_transaction_model.dart';
import 'package:cw_evm/pending_evm_chain_transaction.dart';
import 'package:cw_evm/evm_chain_transaction_priority.dart';
import 'package:cw_evm/.secrets.g.dart' as secrets;
import 'package:flutter/services.dart';
import 'package:http/http.dart';
@ -211,26 +213,61 @@ abstract class EVMChainClient {
return EVMChainERC20Balance(balance, exponent: exponent);
}
Future<Erc20Token?> getErc20Token(String contractAddress) async {
Future<Erc20Token?> getErc20Token(String contractAddress, String chainName) async {
try {
final erc20 = ERC20(address: EthereumAddress.fromHex(contractAddress), client: _client!);
final name = await erc20.name();
final symbol = await erc20.symbol();
final decimal = await erc20.decimals();
final uri = Uri.https(
'deep-index.moralis.io',
'/api/v2.2/erc20/metadata',
{
"chain": chainName,
"addresses": contractAddress,
},
);
final response = await httpClient.get(
uri,
headers: {
"Accept": "application/json",
"X-API-Key": secrets.moralisApiKey,
},
);
final decodedResponse = jsonDecode(response.body)[0] as Map<String, dynamic>;
final name = decodedResponse['name'] ?? '';
final symbol = decodedResponse['symbol'] ?? '';
final decimal = decodedResponse['decimals'] ?? '0';
final iconPath = decodedResponse['logo'] ?? '';
return Erc20Token(
name: name,
symbol: symbol,
contractAddress: contractAddress,
decimal: decimal.toInt(),
decimal: int.tryParse(decimal) ?? 0,
iconPath: iconPath,
);
} catch (e) {
try {
final erc20 = ERC20(address: EthereumAddress.fromHex(contractAddress), client: _client!);
final name = await erc20.name();
final symbol = await erc20.symbol();
final decimal = await erc20.decimals();
return Erc20Token(
name: name,
symbol: symbol,
contractAddress: contractAddress,
decimal: decimal.toInt(),
);
} catch (_) {}
return null;
}
}
Uint8List hexToBytes(String hexString) {
return Uint8List.fromList(hex.HEX.decode(hexString.startsWith('0x') ? hexString.substring(2) : hexString));
return Uint8List.fromList(
hex.HEX.decode(hexString.startsWith('0x') ? hexString.substring(2) : hexString));
}
void stop() {

View file

@ -439,11 +439,16 @@ abstract class EVMChainWalletBase
Future<void> addErc20Token(Erc20Token token) async {
String? iconPath;
try {
iconPath = CryptoCurrency.all
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
.iconPath;
} catch (_) {}
if (token.iconPath == null || token.iconPath!.isEmpty) {
try {
iconPath = CryptoCurrency.all
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
.iconPath;
} catch (_) {}
} else {
iconPath = token.iconPath;
}
final newToken = createNewErc20TokenObject(token, iconPath);
@ -466,8 +471,8 @@ abstract class EVMChainWalletBase
_updateBalance();
}
Future<Erc20Token?> getErc20Token(String contractAddress) async =>
await _client.getErc20Token(contractAddress);
Future<Erc20Token?> getErc20Token(String contractAddress, String chainName) async =>
await _client.getErc20Token(contractAddress, chainName);
void _onNewTransaction() {
_updateBalance();