import 'dart:convert'; import 'dart:math'; import 'package:bip32/bip32.dart' as bip32; import 'package:bip39/bip39.dart' as bip39; import 'package:ethereum_addresses/ethereum_addresses.dart'; import "package:hex/hex.dart"; import 'package:http/http.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart'; class AddressTransaction { final String message; final List result; final String status; const AddressTransaction({ required this.message, required this.result, required this.status, }); factory AddressTransaction.fromJson(Map json) { return AddressTransaction( message: json['message'] as String, result: json['result'] as List, status: json['status'] as String, ); } @override String toString() { return "AddressTransaction: {" "\n\t message: $message," "\n\t status: $status," "\n\t result: $result," "\n}"; } } class GasTracker { final double average; final double fast; final double slow; // final Map data; const GasTracker({ required this.average, required this.fast, required this.slow, }); factory GasTracker.fromJson(Map json) { return GasTracker( average: json['average'] as double, fast: json['fast'] as double, slow: json['slow'] as double, ); } } const blockExplorer = "https://blockscout.com/eth/mainnet/api"; const abiUrl = "https://api.etherscan.io/api"; //TODO - Once our server has abi functionality update const hdPathEthereum = "m/44'/60'/0'/0"; const _gasTrackerUrl = "https://blockscout.com/eth/mainnet/api/v1/gas-price-oracle"; Future fetchAddressTransactions( String address, String action) async { try { final response = await get(Uri.parse( "$blockExplorer?module=account&action=$action&address=$address")); if (response.statusCode == 200) { return AddressTransaction.fromJson( json.decode(response.body) as Map); } else { throw Exception( 'ERROR GETTING TRANSACTIONS WITH STATUS ${response.statusCode}'); } } catch (e, s) { throw Exception('ERROR GETTING TRANSACTIONS ${e.toString()}'); } } Future> getWalletTokens(String address) async { AddressTransaction tokens = await fetchAddressTransactions(address, "tokentx"); List tokensList = []; var tokenMap = {}; if (tokens.message == "OK") { final allTxs = tokens.result; allTxs.forEach((element) { String key = element["tokenSymbol"] as String; tokenMap[key] = {}; tokenMap[key]["balance"] = 0; if (tokenMap.containsKey(key)) { tokenMap[key]["contractAddress"] = element["contractAddress"] as String; tokenMap[key]["decimals"] = element["tokenDecimal"]; tokenMap[key]["name"] = element["tokenName"]; tokenMap[key]["symbol"] = element["tokenSymbol"]; if (checksumEthereumAddress(address) == address) { tokenMap[key]["balance"] += int.parse(element["value"] as String); } else { tokenMap[key]["balance"] -= int.parse(element["value"] as String); } } }); tokenMap.forEach((key, value) { tokensList.add(value as Map); }); return tokensList; } return []; } String getPrivateKey(String mnemonic, String mnemonicPassphrase) { final isValidMnemonic = bip39.validateMnemonic(mnemonic); if (!isValidMnemonic) { throw 'Invalid mnemonic'; } final seed = bip39.mnemonicToSeed(mnemonic, passphrase: mnemonicPassphrase); final root = bip32.BIP32.fromSeed(seed); const index = 0; final addressAtIndex = root.derivePath("$hdPathEthereum/$index"); return HEX.encode(addressAtIndex.privateKey as List); } Future getGasOracle() async { final response = await get(Uri.parse(_gasTrackerUrl)); if (response.statusCode == 200) { return GasTracker.fromJson( json.decode(response.body) as Map); } else { throw Exception('Failed to load gas oracle'); } } Future getFees() async { GasTracker fees = await getGasOracle(); final feesFast = fees.fast * (pow(10, 9)); final feesStandard = fees.average * (pow(10, 9)); final feesSlow = fees.slow * (pow(10, 9)); return FeeObject( numberOfBlocksFast: 1, numberOfBlocksAverage: 3, numberOfBlocksSlow: 3, fast: feesFast.toInt(), medium: feesStandard.toInt(), slow: feesSlow.toInt()); } double estimateFee(int feeRate, int gasLimit, int decimals) { final gweiAmount = feeRate / (pow(10, 9)); final fee = gasLimit * gweiAmount; //Convert gwei to ETH final feeInWei = fee * (pow(10, 9)); final ethAmount = feeInWei / (pow(10, decimals)); return ethAmount; } BigInt amountToBigInt(num amount, int decimal) { final amountToSendinDecimal = amount * (pow(10, decimal)); return BigInt.from(amountToSendinDecimal); }