Add Balances for ERC20 tokens

This commit is contained in:
OmarHatem 2023-05-23 21:31:54 +03:00
parent d3f0c7fb85
commit 0dae347190
5 changed files with 84 additions and 25 deletions

View file

@ -152,6 +152,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
static const uni = CryptoCurrency(title: 'UNI', tag: 'ETH', fullName: 'Uniswap', raw: 60, name: 'uni', iconPath: 'assets/images/uni_icon.png');
static const stx = CryptoCurrency(title: 'STX', fullName: 'Stacks', raw: 61, name: 'stx', iconPath: 'assets/images/stx_icon.png');
static const btcln = CryptoCurrency(title: 'BTC', tag: 'LN', fullName: 'Bitcoin Lightning Network', raw: 62, name: 'btcln', iconPath: 'assets/images/btc.png');
static const shib = CryptoCurrency(title: 'SHIB', tag: 'ETH', fullName: 'SHIBA INU', raw: 63, name: 'shib', iconPath: 'assets/images/shib.png'); // TODO: add image
static final Map<int, CryptoCurrency> _rawCurrencyMap =

View file

@ -2,30 +2,33 @@ import 'dart:convert';
import 'dart:math';
import 'package:cw_core/balance.dart';
import 'package:web3dart/web3dart.dart';
class EthereumBalance extends Balance {
EthereumBalance(this.balance)
: super(balance.getValueInUnit(EtherUnit.wei).toInt(),
balance.getValueInUnit(EtherUnit.wei).toInt());
class ERC20Balance extends Balance {
ERC20Balance(this.balance, {this.exponent = 18})
: super(balance.toInt(),
balance.toInt());
final EtherAmount balance;
final BigInt balance;
final int exponent;
@override
String get formattedAdditionalBalance {
final String formattedBalance = balance.getValueInUnit(EtherUnit.ether).toString();
final String formattedBalance = (balance / BigInt.from(10).pow(exponent)).toString();
return formattedBalance.substring(0, min(12, formattedBalance.length));
}
@override
String get formattedAvailableBalance {
final String formattedBalance = balance.getValueInUnit(EtherUnit.ether).toString();
final String formattedBalance = (balance / BigInt.from(10).pow(exponent)).toString();
return formattedBalance.substring(0, min(12, formattedBalance.length));
}
String toJSON() => json.encode({'balanceInWei': balance.getInWei.toString()});
String toJSON() => json.encode({
'balanceInWei': balance.toString(),
'exponent': exponent,
});
static EthereumBalance? fromJSON(String? jsonSource) {
static ERC20Balance? fromJSON(String? jsonSource) {
if (jsonSource == null) {
return null;
}
@ -33,9 +36,12 @@ class EthereumBalance extends Balance {
final decoded = json.decode(jsonSource) as Map;
try {
return EthereumBalance(EtherAmount.inWei(BigInt.parse(decoded['balanceInWei'])));
return ERC20Balance(
BigInt.parse(decoded['balanceInWei']),
exponent: decoded['exponent'],
);
} catch (e) {
return EthereumBalance(EtherAmount.zero());
return ERC20Balance(BigInt.zero);
}
}
}

View file

@ -1,6 +1,7 @@
import 'dart:typed_data';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_ethereum/ethereum_balance.dart';
import 'package:cw_ethereum/pending_ethereum_transaction.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart';
import 'package:web3dart/web3dart.dart';
import 'package:cw_core/node.dart';
@ -32,9 +33,9 @@ class EthereumClient {
// [53000, 53000, 53000]
final result = await Future.wait(EthereumTransactionPriority.all.map(
(priority) => _client!.estimateGas(
maxPriorityFeePerGas: EtherAmount.fromUnitAndValue(EtherUnit.gwei, priority.tip),
maxFeePerGas: EtherAmount.fromUnitAndValue(EtherUnit.gwei, priority.tip),
),
// maxPriorityFeePerGas: EtherAmount.fromUnitAndValue(EtherUnit.gwei, priority.tip),
// maxFeePerGas: EtherAmount.fromUnitAndValue(EtherUnit.gwei, priority.tip),
),
));
return result.map((e) => e.toInt()).toList();
@ -133,4 +134,53 @@ I/flutter ( 4474): Gas Used: 53000
// },
// ));
// }
Future<Map<CryptoCurrency, ERC20Balance>> fetchERC20Balances(EthereumAddress userAddress) async {
final String abi = await rootBundle.loadString("assets/abi_json/erc20_abi.json");
final contractAbi = ContractAbi.fromJson(abi, "ERC20");
final Map<CryptoCurrency, ERC20Balance> erc20Balances = {};
for (var currency in _erc20Currencies.keys) {
final contractAddress = _erc20Currencies[currency]!;
try {
final contract = DeployedContract(
contractAbi,
EthereumAddress.fromHex(contractAddress),
);
final balanceFunction = contract.function('balanceOf');
final balance = await _client!.call(
contract: contract,
function: balanceFunction,
params: [userAddress],
);
final decimalsFunction = contract.function('decimals');
final decimals = await _client!.call(
contract: contract,
function: decimalsFunction,
params: [],
);
BigInt tokenBalance = BigInt.parse(balance.first.toString());
int exponent = int.parse(decimals.first.toString());
erc20Balances[currency] = ERC20Balance(tokenBalance, exponent: exponent);
} catch (e, s) {
print(e);
print(s);
continue;
}
}
return erc20Balances;
}
}
Map<CryptoCurrency, String> _erc20Currencies = {
CryptoCurrency.usdc: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
CryptoCurrency.usdterc20: "0xdac17f958d2ee523a2206206994597c13d831ec7",
CryptoCurrency.shib: "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE",
};

View file

@ -30,21 +30,21 @@ part 'ethereum_wallet.g.dart';
class EthereumWallet = EthereumWalletBase with _$EthereumWallet;
abstract class EthereumWalletBase
extends WalletBase<EthereumBalance, EthereumTransactionHistory, EthereumTransactionInfo>
extends WalletBase<ERC20Balance, EthereumTransactionHistory, EthereumTransactionInfo>
with Store {
EthereumWalletBase({
required WalletInfo walletInfo,
required String mnemonic,
required String password,
EthereumBalance? initialBalance,
ERC20Balance? initialBalance,
}) : syncStatus = NotConnectedSyncStatus(),
_password = password,
_mnemonic = mnemonic,
_priorityFees = [],
_client = EthereumClient(),
walletAddresses = EthereumWalletAddresses(walletInfo),
balance = ObservableMap<CryptoCurrency, EthereumBalance>.of(
{CryptoCurrency.eth: initialBalance ?? EthereumBalance(EtherAmount.zero())}),
balance = ObservableMap<CryptoCurrency, ERC20Balance>.of(
{CryptoCurrency.eth: initialBalance ?? ERC20Balance(BigInt.zero)}),
super(walletInfo) {
this.walletInfo = walletInfo;
}
@ -68,7 +68,7 @@ abstract class EthereumWalletBase
@override
@observable
late ObservableMap<CryptoCurrency, EthereumBalance> balance;
late ObservableMap<CryptoCurrency, ERC20Balance> balance;
Future<void> init() async {
await walletAddresses.init();
@ -234,7 +234,7 @@ abstract class EthereumWalletBase
final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String;
final balance =
EthereumBalance.fromJSON(data['balance'] as String) ?? EthereumBalance(EtherAmount.zero());
ERC20Balance.fromJSON(data['balance'] as String) ?? ERC20Balance(BigInt.zero);
return EthereumWallet(
walletInfo: walletInfo,
@ -246,12 +246,13 @@ abstract class EthereumWalletBase
Future<void> _updateBalance() async {
balance[currency] = await _fetchBalances();
balance.addAll(await _client.fetchERC20Balances(_privateKey.address));
await save();
}
Future<EthereumBalance> _fetchBalances() async {
Future<ERC20Balance> _fetchBalances() async {
final balance = await _client.getBalance(_privateKey.address);
return EthereumBalance(balance);
return ERC20Balance(balance.getInWei);
}
Future<EthPrivateKey> getPrivateKey(String mnemonic, String password) async {

View file

@ -112,6 +112,7 @@ flutter:
- assets/text/
- assets/faq/
- assets/animation/
- assets/abi_json/
fonts:
- family: Lato