mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-24 12:29:37 +00:00
Add validation for custom addresses and clean up
This commit is contained in:
parent
d53709c7b0
commit
f7e2568e6a
4 changed files with 65 additions and 99 deletions
|
@ -741,45 +741,7 @@ class EthereumWallet extends CoinServiceAPI {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> updateSentCachedTxData(Map<String, dynamic> txData) async {
|
Future<void> updateSentCachedTxData(Map<String, dynamic> txData) async {
|
||||||
final priceData =
|
//Only used for Electrumx coins
|
||||||
await _priceAPI.getPricesAnd24hChange(baseCurrency: _prefs.currency);
|
|
||||||
Decimal currentPrice = priceData[coin]?.item1 ?? Decimal.zero;
|
|
||||||
final locale = await Devicelocale.currentLocale;
|
|
||||||
final String worthNow = Format.localizedStringAsFixed(
|
|
||||||
value:
|
|
||||||
((currentPrice * Decimal.fromInt(txData["recipientAmt"] as int)) /
|
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
|
||||||
.toDecimal(scaleOnInfinitePrecision: 2),
|
|
||||||
decimalPlaces: 2,
|
|
||||||
locale: locale!);
|
|
||||||
|
|
||||||
final tx = models.Transaction(
|
|
||||||
txid: txData["txid"] as String,
|
|
||||||
confirmedStatus: false,
|
|
||||||
timestamp: DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
|
||||||
txType: "Sent",
|
|
||||||
amount: txData["recipientAmt"] as int,
|
|
||||||
worthNow: worthNow,
|
|
||||||
worthAtBlockTimestamp: worthNow,
|
|
||||||
fees: txData["fee"] as int,
|
|
||||||
inputSize: 0,
|
|
||||||
outputSize: 0,
|
|
||||||
inputs: [],
|
|
||||||
outputs: [],
|
|
||||||
address: txData["address"] as String,
|
|
||||||
height: -1,
|
|
||||||
confirmations: 0,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (cachedTxData == null) {
|
|
||||||
final data = await _fetchTransactionData();
|
|
||||||
_transactionData = Future(() => data);
|
|
||||||
} else {
|
|
||||||
final transactions = cachedTxData!.getAllTransactions();
|
|
||||||
transactions[tx.txid] = tx;
|
|
||||||
cachedTxData = models.TransactionData.fromMap(transactions);
|
|
||||||
_transactionData = Future(() => cachedTxData!);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
import 'package:devicelocale/devicelocale.dart';
|
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:decimal/decimal.dart';
|
import 'package:decimal/decimal.dart';
|
||||||
import 'package:stackwallet/utilities/eth_commons.dart';
|
import 'package:stackwallet/utilities/eth_commons.dart';
|
||||||
|
@ -42,6 +41,26 @@ class AbiRequestResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TokenData {
|
||||||
|
final String message;
|
||||||
|
final Map<String, dynamic> result;
|
||||||
|
final String status;
|
||||||
|
|
||||||
|
const TokenData({
|
||||||
|
required this.message,
|
||||||
|
required this.result,
|
||||||
|
required this.status,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory TokenData.fromJson(Map<String, dynamic> json) {
|
||||||
|
return TokenData(
|
||||||
|
message: json['message'] as String,
|
||||||
|
result: json['result'] as Map<String, dynamic>,
|
||||||
|
status: json['status'] as String,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const int MINIMUM_CONFIRMATIONS = 3;
|
const int MINIMUM_CONFIRMATIONS = 3;
|
||||||
|
|
||||||
class EthereumToken extends TokenServiceAPI {
|
class EthereumToken extends TokenServiceAPI {
|
||||||
|
@ -81,7 +100,7 @@ class EthereumToken extends TokenServiceAPI {
|
||||||
return AbiRequestResponse.fromJson(
|
return AbiRequestResponse.fromJson(
|
||||||
json.decode(response.body) as Map<String, dynamic>);
|
json.decode(response.body) as Map<String, dynamic>);
|
||||||
} else {
|
} else {
|
||||||
throw Exception('Failed to load token abi');
|
throw Exception("ERROR GETTING TOKENABI ${response.reasonPhrase}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +204,8 @@ class EthereumToken extends TokenServiceAPI {
|
||||||
_balanceFunction = _contract.function('balanceOf');
|
_balanceFunction = _contract.function('balanceOf');
|
||||||
_sendFunction = _contract.function('transfer');
|
_sendFunction = _contract.function('transfer');
|
||||||
_client = await getEthClient();
|
_client = await getEthClient();
|
||||||
|
|
||||||
|
// print(_credentials.p)
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -294,47 +315,6 @@ class EthereumToken extends TokenServiceAPI {
|
||||||
_transactionData ??= _fetchTransactionData();
|
_transactionData ??= _fetchTransactionData();
|
||||||
Future<TransactionData>? _transactionData;
|
Future<TransactionData>? _transactionData;
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> updateSentCachedTxData(Map<String, dynamic> txData) async {
|
|
||||||
Decimal currentPrice = Decimal.zero;
|
|
||||||
final locale = await Devicelocale.currentLocale;
|
|
||||||
final String worthNow = Format.localizedStringAsFixed(
|
|
||||||
value:
|
|
||||||
((currentPrice * Decimal.fromInt(txData["recipientAmt"] as int)) /
|
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
|
||||||
.toDecimal(scaleOnInfinitePrecision: 2),
|
|
||||||
decimalPlaces: 2,
|
|
||||||
locale: locale!);
|
|
||||||
|
|
||||||
final tx = models.Transaction(
|
|
||||||
txid: txData["txid"] as String,
|
|
||||||
confirmedStatus: false,
|
|
||||||
timestamp: DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
|
||||||
txType: "Sent",
|
|
||||||
amount: txData["recipientAmt"] as int,
|
|
||||||
worthNow: worthNow,
|
|
||||||
worthAtBlockTimestamp: worthNow,
|
|
||||||
fees: txData["fee"] as int,
|
|
||||||
inputSize: 0,
|
|
||||||
outputSize: 0,
|
|
||||||
inputs: [],
|
|
||||||
outputs: [],
|
|
||||||
address: txData["address"] as String,
|
|
||||||
height: -1,
|
|
||||||
confirmations: 0,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (cachedTxData == null) {
|
|
||||||
final data = await _fetchTransactionData();
|
|
||||||
_transactionData = Future(() => data);
|
|
||||||
} else {
|
|
||||||
final transactions = cachedTxData!.getAllTransactions();
|
|
||||||
transactions[tx.txid] = tx;
|
|
||||||
cachedTxData = models.TransactionData.fromMap(transactions);
|
|
||||||
_transactionData = Future(() => cachedTxData!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<TransactionData> _fetchTransactionData() async {
|
Future<TransactionData> _fetchTransactionData() async {
|
||||||
String thisAddress = await currentReceivingAddress;
|
String thisAddress = await currentReceivingAddress;
|
||||||
// final cachedTransactions = {} as TransactionData?;
|
// final cachedTransactions = {} as TransactionData?;
|
||||||
|
@ -440,9 +420,6 @@ class EthereumToken extends TokenServiceAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// final transactionsMap = {} as Map<String, models.Transaction>;
|
|
||||||
// transactionsMap
|
|
||||||
// .addAll(TransactionData.fromJson(result).getAllTransactions());
|
|
||||||
final txModel = TransactionData.fromMap(
|
final txModel = TransactionData.fromMap(
|
||||||
TransactionData.fromJson(result).getAllTransactions());
|
TransactionData.fromJson(result).getAllTransactions());
|
||||||
|
|
||||||
|
@ -455,6 +432,34 @@ class EthereumToken extends TokenServiceAPI {
|
||||||
return isValidEthereumAddress(address);
|
return isValidEthereumAddress(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Validate that a custom token is valid and is ERC-20, a token will be valid
|
||||||
|
@override
|
||||||
|
Future<TokenData> getTokenByContractAddress(String contractAddress) async {
|
||||||
|
final response = await get(Uri.parse(
|
||||||
|
"$blockExplorer?module=token&action=getToken&contractaddress=$contractAddress"));
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
return TokenData.fromJson(
|
||||||
|
json.decode(response.body) as Map<String, dynamic>);
|
||||||
|
} else {
|
||||||
|
throw Exception("ERROR GETTING TOKEN ${response.reasonPhrase}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Validate that a custom token is valid and is ERC-20
|
||||||
|
@override
|
||||||
|
Future<bool> isValidToken(String contractAddress) async {
|
||||||
|
TokenData tokenData = await getTokenByContractAddress(contractAddress);
|
||||||
|
|
||||||
|
if (tokenData.message == "OK") {
|
||||||
|
final result = tokenData.result;
|
||||||
|
if (result["type"] == "ERC-20") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Future<NodeModel> getCurrentNode() async {
|
Future<NodeModel> getCurrentNode() async {
|
||||||
return NodeService(secureStorageInterface: _secureStore)
|
return NodeService(secureStorageInterface: _secureStore)
|
||||||
.getPrimaryNodeFor(coin: coin) ??
|
.getPrimaryNodeFor(coin: coin) ??
|
||||||
|
|
|
@ -41,7 +41,6 @@ abstract class TokenServiceAPI {
|
||||||
Future<int> get maxFee;
|
Future<int> get maxFee;
|
||||||
|
|
||||||
Future<String> get currentReceivingAddress;
|
Future<String> get currentReceivingAddress;
|
||||||
// Future<String> get currentLegacyReceivingAddress;
|
|
||||||
|
|
||||||
Future<Decimal> get availableBalance;
|
Future<Decimal> get availableBalance;
|
||||||
Future<Decimal> get totalBalance;
|
Future<Decimal> get totalBalance;
|
||||||
|
@ -52,9 +51,6 @@ abstract class TokenServiceAPI {
|
||||||
|
|
||||||
Future<void> refresh();
|
Future<void> refresh();
|
||||||
|
|
||||||
// String get walletName;
|
|
||||||
// String get walletId;
|
|
||||||
|
|
||||||
bool validateAddress(String address);
|
bool validateAddress(String address);
|
||||||
|
|
||||||
Future<void> initializeNew();
|
Future<void> initializeNew();
|
||||||
|
@ -62,6 +58,5 @@ abstract class TokenServiceAPI {
|
||||||
|
|
||||||
Future<int> estimateFeeFor(int satoshiAmount, int feeRate);
|
Future<int> estimateFeeFor(int satoshiAmount, int feeRate);
|
||||||
|
|
||||||
// used for electrumx coins
|
Future<bool> isValidToken(String contractAddress);
|
||||||
Future<void> updateSentCachedTxData(Map<String, dynamic> txData);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,14 +58,18 @@ const _gasTrackerUrl =
|
||||||
|
|
||||||
Future<AddressTransaction> fetchAddressTransactions(
|
Future<AddressTransaction> fetchAddressTransactions(
|
||||||
String address, String action) async {
|
String address, String action) async {
|
||||||
|
try {
|
||||||
final response = await get(Uri.parse(
|
final response = await get(Uri.parse(
|
||||||
"$blockExplorer?module=account&action=$action&address=$address"));
|
"$blockExplorer?module=account&action=$action&address=$address"));
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
return AddressTransaction.fromJson(
|
return AddressTransaction.fromJson(
|
||||||
json.decode(response.body) as Map<String, dynamic>);
|
json.decode(response.body) as Map<String, dynamic>);
|
||||||
} else {
|
} else {
|
||||||
throw Exception('Failed to load transactions');
|
throw Exception(
|
||||||
|
'ERROR GETTING TRANSACTIONS WITH STATUS ${response.statusCode}');
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
throw Exception('ERROR GETTING TRANSACTIONS ${e.toString()}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue