Fix int overflow

This commit is contained in:
OmarHatem 2023-07-22 03:39:10 +03:00
parent 2e0b02766e
commit 87d414a34c
3 changed files with 52 additions and 21 deletions

View file

@ -1,6 +1,28 @@
import 'dart:math'; import 'dart:math';
import 'package:intl/intl.dart';
const ethereumAmountLength = 12;
const ethereumAmountDivider = 1000000000000;
final ethereumAmountFormat = NumberFormat()
..maximumFractionDigits = ethereumAmountLength
..minimumFractionDigits = 1;
class EthereumFormatter { class EthereumFormatter {
static int parseEthereumAmount(String amount) => static int parseEthereumAmount(String amount) {
BigInt.from(double.parse(amount) * (pow(10, 18))).toInt(); try {
return (double.parse(amount) * ethereumAmountDivider).round();
} catch (_) {
return 0;
}
}
static int parseEthereumBigIntAmount(BigInt amount) {
try {
double result = amount / BigInt.from(pow(10, 18 - ethereumAmountLength));
return result.toInt();
} catch (_) {
return 0;
}
}
} }

View file

@ -6,31 +6,34 @@ class EthereumTransactionInfo extends TransactionInfo {
EthereumTransactionInfo({ EthereumTransactionInfo({
required this.id, required this.id,
required this.height, required this.height,
required this.amount, required this.ethAmount,
required this.fee, required this.ethFee,
this.tokenSymbol = "ETH", this.tokenSymbol = "ETH",
this.exponent = 18, this.exponent = 18,
required this.direction, required this.direction,
required this.isPending, required this.isPending,
required this.date, required this.date,
required this.confirmations, required this.confirmations,
}); }) : this.amount = ethAmount.toInt(),
this.fee = ethFee.toInt();
final String id; final String id;
final int height; final int height;
final int amount; final int amount;
final BigInt ethAmount;
final int exponent; final int exponent;
final TransactionDirection direction; final TransactionDirection direction;
final DateTime date; final DateTime date;
final bool isPending; final bool isPending;
final int fee; final int fee;
final BigInt ethFee;
final int confirmations; final int confirmations;
final String tokenSymbol; final String tokenSymbol;
String? _fiatAmount; String? _fiatAmount;
@override @override
String amountFormatted() => String amountFormatted() =>
'${formatAmount((BigInt.from(amount) / BigInt.from(10).pow(exponent)).toString())} $tokenSymbol'; '${formatAmount((ethAmount / BigInt.from(10).pow(exponent)).toString())} $tokenSymbol';
@override @override
String fiatAmount() => _fiatAmount ?? ''; String fiatAmount() => _fiatAmount ?? '';
@ -39,15 +42,15 @@ class EthereumTransactionInfo extends TransactionInfo {
void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount); void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
@override @override
String feeFormatted() => '${(BigInt.from(fee) / BigInt.from(10).pow(18)).toString()} ETH'; String feeFormatted() => '${(ethFee / BigInt.from(10).pow(18)).toString()} ETH';
factory EthereumTransactionInfo.fromJson(Map<String, dynamic> data) { factory EthereumTransactionInfo.fromJson(Map<String, dynamic> data) {
return EthereumTransactionInfo( return EthereumTransactionInfo(
id: data['id'] as String, id: data['id'] as String,
height: data['height'] as int, height: data['height'] as int,
amount: data['amount'] as int, ethAmount: data['amount'] as BigInt,
exponent: data['exponent'] as int, exponent: data['exponent'] as int,
fee: data['fee'] as int, ethFee: data['fee'] as BigInt,
direction: parseTransactionDirectionFromInt(data['direction'] as int), direction: parseTransactionDirectionFromInt(data['direction'] as int),
date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int), date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int),
isPending: data['isPending'] as bool, isPending: data['isPending'] as bool,
@ -59,9 +62,9 @@ class EthereumTransactionInfo extends TransactionInfo {
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'id': id, 'id': id,
'height': height, 'height': height,
'amount': amount, 'amount': ethAmount,
'exponent': exponent, 'exponent': exponent,
'fee': fee, 'fee': ethFee,
'direction': direction.index, 'direction': direction.index,
'date': date.millisecondsSinceEpoch, 'date': date.millisecondsSinceEpoch,
'isPending': isPending, 'isPending': isPending,

View file

@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:math';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/node.dart'; import 'package:cw_core/node.dart';
@ -16,6 +17,7 @@ import 'package:cw_ethereum/default_erc20_tokens.dart';
import 'package:cw_ethereum/erc20_balance.dart'; import 'package:cw_ethereum/erc20_balance.dart';
import 'package:cw_ethereum/ethereum_client.dart'; import 'package:cw_ethereum/ethereum_client.dart';
import 'package:cw_ethereum/ethereum_exceptions.dart'; import 'package:cw_ethereum/ethereum_exceptions.dart';
import 'package:cw_ethereum/ethereum_formatter.dart';
import 'package:cw_ethereum/ethereum_transaction_credentials.dart'; import 'package:cw_ethereum/ethereum_transaction_credentials.dart';
import 'package:cw_ethereum/ethereum_transaction_history.dart'; import 'package:cw_ethereum/ethereum_transaction_history.dart';
import 'package:cw_ethereum/ethereum_transaction_info.dart'; import 'package:cw_ethereum/ethereum_transaction_info.dart';
@ -144,26 +146,30 @@ abstract class EthereumWalletBase
final outputs = _credentials.outputs; final outputs = _credentials.outputs;
final hasMultiDestination = outputs.length > 1; final hasMultiDestination = outputs.length > 1;
final _erc20Balance = balance[_credentials.currency]!; final _erc20Balance = balance[_credentials.currency]!;
int totalAmount = 0; BigInt totalAmount = BigInt.zero;
BigInt amountToEthereumMultiplier = BigInt.from(pow(10, 18 - ethereumAmountLength));
if (hasMultiDestination) { if (hasMultiDestination) {
if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) { if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
throw EthereumTransactionCreationException(); throw EthereumTransactionCreationException();
} }
totalAmount = outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)); totalAmount =
BigInt.from(outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0))) *
amountToEthereumMultiplier;
if (_erc20Balance.balance < EtherAmount.inWei(totalAmount as BigInt).getInWei) { if (_erc20Balance.balance < totalAmount) {
throw EthereumTransactionCreationException(); throw EthereumTransactionCreationException();
} }
} else { } else {
final output = outputs.first; final output = outputs.first;
final int allAmount = _erc20Balance.balance.toInt() - feeRate(_credentials.priority!); final BigInt allAmount = _erc20Balance.balance - BigInt.from(feeRate(_credentials.priority!));
totalAmount = output.sendAll ? allAmount : output.formattedCryptoAmount ?? 0; totalAmount = output.sendAll
? allAmount
: BigInt.from(output.formattedCryptoAmount ?? 0) * amountToEthereumMultiplier;
if ((output.sendAll && if ((output.sendAll && _erc20Balance.balance < totalAmount) ||
_erc20Balance.balance < EtherAmount.inWei(totalAmount as BigInt).getInWei) || (!output.sendAll && _erc20Balance.balance <= BigInt.zero)) {
(!output.sendAll && _erc20Balance.balance.toInt() <= 0)) {
throw EthereumTransactionCreationException(); throw EthereumTransactionCreationException();
} }
} }
@ -228,14 +234,14 @@ abstract class EthereumWalletBase
result[transactionModel.hash] = EthereumTransactionInfo( result[transactionModel.hash] = EthereumTransactionInfo(
id: transactionModel.hash, id: transactionModel.hash,
height: transactionModel.blockNumber, height: transactionModel.blockNumber,
amount: transactionModel.amount.toInt(), ethAmount: transactionModel.amount,
direction: transactionModel.from == address direction: transactionModel.from == address
? TransactionDirection.outgoing ? TransactionDirection.outgoing
: TransactionDirection.incoming, : TransactionDirection.incoming,
isPending: false, isPending: false,
date: transactionModel.date, date: transactionModel.date,
confirmations: transactionModel.confirmations, confirmations: transactionModel.confirmations,
fee: transactionModel.gasUsed * transactionModel.gasPrice.toInt(), ethFee: BigInt.from(transactionModel.gasUsed) * transactionModel.gasPrice,
exponent: transactionModel.tokenDecimal ?? 18, exponent: transactionModel.tokenDecimal ?? 18,
tokenSymbol: transactionModel.tokenSymbol ?? "ETH", tokenSymbol: transactionModel.tokenSymbol ?? "ETH",
); );