From 87d414a34c982d2c19c707b19ec2342c8c6cd566 Mon Sep 17 00:00:00 2001 From: OmarHatem Date: Sat, 22 Jul 2023 03:39:10 +0300 Subject: [PATCH] Fix int overflow --- cw_ethereum/lib/ethereum_formatter.dart | 26 +++++++++++++++++-- .../lib/ethereum_transaction_info.dart | 21 ++++++++------- cw_ethereum/lib/ethereum_wallet.dart | 26 ++++++++++++------- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/cw_ethereum/lib/ethereum_formatter.dart b/cw_ethereum/lib/ethereum_formatter.dart index 87991f3ee..245e9da50 100644 --- a/cw_ethereum/lib/ethereum_formatter.dart +++ b/cw_ethereum/lib/ethereum_formatter.dart @@ -1,6 +1,28 @@ import 'dart:math'; +import 'package:intl/intl.dart'; + +const ethereumAmountLength = 12; +const ethereumAmountDivider = 1000000000000; +final ethereumAmountFormat = NumberFormat() + ..maximumFractionDigits = ethereumAmountLength + ..minimumFractionDigits = 1; + class EthereumFormatter { - static int parseEthereumAmount(String amount) => - BigInt.from(double.parse(amount) * (pow(10, 18))).toInt(); + static int parseEthereumAmount(String amount) { + 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; + } + } } diff --git a/cw_ethereum/lib/ethereum_transaction_info.dart b/cw_ethereum/lib/ethereum_transaction_info.dart index fcf79961f..be3c2c0e2 100644 --- a/cw_ethereum/lib/ethereum_transaction_info.dart +++ b/cw_ethereum/lib/ethereum_transaction_info.dart @@ -6,31 +6,34 @@ class EthereumTransactionInfo extends TransactionInfo { EthereumTransactionInfo({ required this.id, required this.height, - required this.amount, - required this.fee, + required this.ethAmount, + required this.ethFee, this.tokenSymbol = "ETH", this.exponent = 18, required this.direction, required this.isPending, required this.date, required this.confirmations, - }); + }) : this.amount = ethAmount.toInt(), + this.fee = ethFee.toInt(); final String id; final int height; final int amount; + final BigInt ethAmount; final int exponent; final TransactionDirection direction; final DateTime date; final bool isPending; final int fee; + final BigInt ethFee; final int confirmations; final String tokenSymbol; String? _fiatAmount; @override String amountFormatted() => - '${formatAmount((BigInt.from(amount) / BigInt.from(10).pow(exponent)).toString())} $tokenSymbol'; + '${formatAmount((ethAmount / BigInt.from(10).pow(exponent)).toString())} $tokenSymbol'; @override String fiatAmount() => _fiatAmount ?? ''; @@ -39,15 +42,15 @@ class EthereumTransactionInfo extends TransactionInfo { void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount); @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 data) { return EthereumTransactionInfo( id: data['id'] as String, height: data['height'] as int, - amount: data['amount'] as int, + ethAmount: data['amount'] as BigInt, exponent: data['exponent'] as int, - fee: data['fee'] as int, + ethFee: data['fee'] as BigInt, direction: parseTransactionDirectionFromInt(data['direction'] as int), date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int), isPending: data['isPending'] as bool, @@ -59,9 +62,9 @@ class EthereumTransactionInfo extends TransactionInfo { Map toJson() => { 'id': id, 'height': height, - 'amount': amount, + 'amount': ethAmount, 'exponent': exponent, - 'fee': fee, + 'fee': ethFee, 'direction': direction.index, 'date': date.millisecondsSinceEpoch, 'isPending': isPending, diff --git a/cw_ethereum/lib/ethereum_wallet.dart b/cw_ethereum/lib/ethereum_wallet.dart index e57b7fbfd..1faf86e7b 100644 --- a/cw_ethereum/lib/ethereum_wallet.dart +++ b/cw_ethereum/lib/ethereum_wallet.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'dart:math'; import 'package:cw_core/crypto_currency.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/ethereum_client.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_history.dart'; import 'package:cw_ethereum/ethereum_transaction_info.dart'; @@ -144,26 +146,30 @@ abstract class EthereumWalletBase final outputs = _credentials.outputs; final hasMultiDestination = outputs.length > 1; final _erc20Balance = balance[_credentials.currency]!; - int totalAmount = 0; + BigInt totalAmount = BigInt.zero; + BigInt amountToEthereumMultiplier = BigInt.from(pow(10, 18 - ethereumAmountLength)); if (hasMultiDestination) { if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) { 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(); } } else { final output = outputs.first; - final int allAmount = _erc20Balance.balance.toInt() - feeRate(_credentials.priority!); - totalAmount = output.sendAll ? allAmount : output.formattedCryptoAmount ?? 0; + final BigInt allAmount = _erc20Balance.balance - BigInt.from(feeRate(_credentials.priority!)); + totalAmount = output.sendAll + ? allAmount + : BigInt.from(output.formattedCryptoAmount ?? 0) * amountToEthereumMultiplier; - if ((output.sendAll && - _erc20Balance.balance < EtherAmount.inWei(totalAmount as BigInt).getInWei) || - (!output.sendAll && _erc20Balance.balance.toInt() <= 0)) { + if ((output.sendAll && _erc20Balance.balance < totalAmount) || + (!output.sendAll && _erc20Balance.balance <= BigInt.zero)) { throw EthereumTransactionCreationException(); } } @@ -228,14 +234,14 @@ abstract class EthereumWalletBase result[transactionModel.hash] = EthereumTransactionInfo( id: transactionModel.hash, height: transactionModel.blockNumber, - amount: transactionModel.amount.toInt(), + ethAmount: transactionModel.amount, direction: transactionModel.from == address ? TransactionDirection.outgoing : TransactionDirection.incoming, isPending: false, date: transactionModel.date, confirmations: transactionModel.confirmations, - fee: transactionModel.gasUsed * transactionModel.gasPrice.toInt(), + ethFee: BigInt.from(transactionModel.gasUsed) * transactionModel.gasPrice, exponent: transactionModel.tokenDecimal ?? 18, tokenSymbol: transactionModel.tokenSymbol ?? "ETH", );