mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
CW-672: Enhance ETH Transaction Fee Calculation (#1545)
* fix: Eth transaction fees WIP
* Revert "fix: Eth transaction fees WIP"
This reverts commit b9a469bc7e
.
* fix: Modifying fee WIP
* fix: Enhance ETH Wallet fee calculation WIP
* feat: Enhance Transaction fees for ETH Transactions, Native transactions done, left with ERC20 transactions
* fix: Pre PR cleanups
* minor things [skip ci]
---------
Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
This commit is contained in:
parent
4410101672
commit
415d2a3573
3 changed files with 186 additions and 45 deletions
|
@ -2,7 +2,7 @@ import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:web3dart/web3dart.dart' as web3;
|
import 'package:web3dart/web3dart.dart' as web3;
|
||||||
|
|
||||||
final _contractAbi = web3.ContractAbi.fromJson(
|
final ethereumContractAbi = web3.ContractAbi.fromJson(
|
||||||
'[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]',
|
'[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]',
|
||||||
'Erc20');
|
'Erc20');
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ class ERC20 extends web3.GeneratedContract {
|
||||||
required web3.EthereumAddress address,
|
required web3.EthereumAddress address,
|
||||||
required web3.Web3Client client,
|
required web3.Web3Client client,
|
||||||
int? chainId,
|
int? chainId,
|
||||||
}) : super(web3.DeployedContract(_contractAbi, address), client, chainId);
|
}) : super(web3.DeployedContract(ethereumContractAbi, address), client, chainId);
|
||||||
|
|
||||||
/// Returns the remaining number of tokens that [spender] will be allowed to spend on behalf of [owner] through [transferFrom]. This is zero by default. This value changes when [approve] or [transferFrom] are called.
|
/// Returns the remaining number of tokens that [spender] will be allowed to spend on behalf of [owner] through [transferFrom]. This is zero by default. This value changes when [approve] or [transferFrom] are called.
|
||||||
///
|
///
|
||||||
|
|
|
@ -10,7 +10,7 @@ import 'package:cw_evm/evm_chain_transaction_priority.dart';
|
||||||
import 'package:cw_evm/evm_erc20_balance.dart';
|
import 'package:cw_evm/evm_erc20_balance.dart';
|
||||||
import 'package:cw_evm/pending_evm_chain_transaction.dart';
|
import 'package:cw_evm/pending_evm_chain_transaction.dart';
|
||||||
import 'package:cw_evm/.secrets.g.dart' as secrets;
|
import 'package:cw_evm/.secrets.g.dart' as secrets;
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hex/hex.dart' as hex;
|
import 'package:hex/hex.dart' as hex;
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:web3dart/web3dart.dart';
|
import 'package:web3dart/web3dart.dart';
|
||||||
|
@ -65,16 +65,65 @@ abstract class EVMChainClient {
|
||||||
Future<int> getGasUnitPrice() async {
|
Future<int> getGasUnitPrice() async {
|
||||||
try {
|
try {
|
||||||
final gasPrice = await _client!.getGasPrice();
|
final gasPrice = await _client!.getGasPrice();
|
||||||
|
|
||||||
return gasPrice.getInWei.toInt();
|
return gasPrice.getInWei.toInt();
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> getEstimatedGas() async {
|
Future<int> getGasBaseFee() async {
|
||||||
try {
|
try {
|
||||||
final estimatedGas = await _client!.estimateGas();
|
final blockInfo = await _client!.getBlockInformation(isContainFullObj: false);
|
||||||
return estimatedGas.toInt();
|
final baseFee = blockInfo.baseFeePerGas;
|
||||||
|
|
||||||
|
return baseFee!.getInWei.toInt();
|
||||||
|
} catch (_) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> getEstimatedGas({
|
||||||
|
String? contractAddress,
|
||||||
|
required EthereumAddress toAddress,
|
||||||
|
required EthereumAddress senderAddress,
|
||||||
|
required EtherAmount value,
|
||||||
|
EtherAmount? gasPrice,
|
||||||
|
// EtherAmount? maxFeePerGas,
|
||||||
|
// EtherAmount? maxPriorityFeePerGas,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
if (contractAddress == null) {
|
||||||
|
final estimatedGas = await _client!.estimateGas(
|
||||||
|
sender: senderAddress,
|
||||||
|
gasPrice: gasPrice,
|
||||||
|
to: toAddress,
|
||||||
|
value: value,
|
||||||
|
// maxPriorityFeePerGas: maxPriorityFeePerGas,
|
||||||
|
// maxFeePerGas: maxFeePerGas,
|
||||||
|
);
|
||||||
|
|
||||||
|
return estimatedGas.toInt();
|
||||||
|
} else {
|
||||||
|
final contract = DeployedContract(
|
||||||
|
ethereumContractAbi,
|
||||||
|
EthereumAddress.fromHex(contractAddress),
|
||||||
|
);
|
||||||
|
|
||||||
|
final transferFunction = contract.function('transferFrom');
|
||||||
|
|
||||||
|
final estimatedGas = await _client!.estimateGas(
|
||||||
|
sender: senderAddress,
|
||||||
|
to: toAddress,
|
||||||
|
value: value,
|
||||||
|
data: transferFunction.encodeCall([
|
||||||
|
senderAddress,
|
||||||
|
toAddress,
|
||||||
|
value.getInWei,
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
return estimatedGas.toInt();
|
||||||
|
}
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +133,7 @@ abstract class EVMChainClient {
|
||||||
required Credentials privateKey,
|
required Credentials privateKey,
|
||||||
required String toAddress,
|
required String toAddress,
|
||||||
required BigInt amount,
|
required BigInt amount,
|
||||||
required int gas,
|
required BigInt gas,
|
||||||
required EVMChainTransactionPriority priority,
|
required EVMChainTransactionPriority priority,
|
||||||
required CryptoCurrency currency,
|
required CryptoCurrency currency,
|
||||||
required int exponent,
|
required int exponent,
|
||||||
|
@ -97,8 +146,6 @@ abstract class EVMChainClient {
|
||||||
|
|
||||||
bool isNativeToken = currency == CryptoCurrency.eth || currency == CryptoCurrency.maticpoly;
|
bool isNativeToken = currency == CryptoCurrency.eth || currency == CryptoCurrency.maticpoly;
|
||||||
|
|
||||||
final price = _client!.getGasPrice();
|
|
||||||
|
|
||||||
final Transaction transaction = createTransaction(
|
final Transaction transaction = createTransaction(
|
||||||
from: privateKey.address,
|
from: privateKey.address,
|
||||||
to: EthereumAddress.fromHex(toAddress),
|
to: EthereumAddress.fromHex(toAddress),
|
||||||
|
@ -130,11 +177,10 @@ abstract class EVMChainClient {
|
||||||
|
|
||||||
_sendTransaction = () async => await sendTransaction(signedTransaction);
|
_sendTransaction = () async => await sendTransaction(signedTransaction);
|
||||||
|
|
||||||
|
|
||||||
return PendingEVMChainTransaction(
|
return PendingEVMChainTransaction(
|
||||||
signedTransaction: signedTransaction,
|
signedTransaction: signedTransaction,
|
||||||
amount: amount.toString(),
|
amount: amount.toString(),
|
||||||
fee: BigInt.from(gas) * (await price).getInWei,
|
fee: gas,
|
||||||
sendTransaction: _sendTransaction,
|
sendTransaction: _sendTransaction,
|
||||||
exponent: exponent,
|
exponent: exponent,
|
||||||
);
|
);
|
||||||
|
@ -233,7 +279,6 @@ abstract class EVMChainClient {
|
||||||
|
|
||||||
final decodedResponse = jsonDecode(response.body)[0] as Map<String, dynamic>;
|
final decodedResponse = jsonDecode(response.body)[0] as Map<String, dynamic>;
|
||||||
|
|
||||||
|
|
||||||
final symbol = (decodedResponse['symbol'] ?? '') as String;
|
final symbol = (decodedResponse['symbol'] ?? '') as String;
|
||||||
String filteredSymbol = symbol.replaceFirst(RegExp('^\\\$'), '');
|
String filteredSymbol = symbol.replaceFirst(RegExp('^\\\$'), '');
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import 'package:cw_evm/evm_chain_transaction_priority.dart';
|
||||||
import 'package:cw_evm/evm_chain_wallet_addresses.dart';
|
import 'package:cw_evm/evm_chain_wallet_addresses.dart';
|
||||||
import 'package:cw_evm/evm_ledger_credentials.dart';
|
import 'package:cw_evm/evm_ledger_credentials.dart';
|
||||||
import 'package:cw_evm/file.dart';
|
import 'package:cw_evm/file.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hex/hex.dart';
|
import 'package:hex/hex.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
@ -102,10 +103,12 @@ abstract class EVMChainWalletBase
|
||||||
|
|
||||||
Credentials get evmChainPrivateKey => _evmChainPrivateKey;
|
Credentials get evmChainPrivateKey => _evmChainPrivateKey;
|
||||||
|
|
||||||
late EVMChainClient _client;
|
late final EVMChainClient _client;
|
||||||
|
|
||||||
|
int gasPrice = 0;
|
||||||
|
int? gasBaseFee = 0;
|
||||||
|
int estimatedGasUnits = 0;
|
||||||
|
|
||||||
int? _gasPrice;
|
|
||||||
int? _estimatedGas;
|
|
||||||
bool _isTransactionUpdating;
|
bool _isTransactionUpdating;
|
||||||
|
|
||||||
// TODO: remove after integrating our own node and having eth_newPendingTransactionFilter
|
// TODO: remove after integrating our own node and having eth_newPendingTransactionFilter
|
||||||
|
@ -173,12 +176,70 @@ abstract class EVMChainWalletBase
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int calculateEstimatedFee(TransactionPriority priority, int? amount) {
|
int calculateEstimatedFee(TransactionPriority priority, int? amount) {
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (priority is EVMChainTransactionPriority) {
|
||||||
|
final priorityFee = EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
|
||||||
|
|
||||||
|
int maxFeePerGas;
|
||||||
|
if (gasBaseFee != null) {
|
||||||
|
// MaxFeePerGas with EIP1559;
|
||||||
|
maxFeePerGas = gasBaseFee! + priorityFee;
|
||||||
|
} else {
|
||||||
|
// MaxFeePerGas with gasPrice;
|
||||||
|
maxFeePerGas = gasPrice;
|
||||||
|
debugPrint('MaxFeePerGas with gasPrice: $maxFeePerGas');
|
||||||
|
}
|
||||||
|
|
||||||
|
final totalGasFee = estimatedGasUnits * maxFeePerGas;
|
||||||
|
return totalGasFee;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} catch (e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows more customization to the fetch estimatedFees flow.
|
||||||
|
///
|
||||||
|
/// We are able to pass in:
|
||||||
|
/// - The exact amount the user wants to send,
|
||||||
|
/// - The addressHex for the receiving wallet,
|
||||||
|
/// - A contract address which would be essential in determining if to calcualate the estimate for ERC20 or native ETH
|
||||||
|
Future<int> calculateActualEstimatedFeeForCreateTransaction({
|
||||||
|
required amount,
|
||||||
|
required String? contractAddress,
|
||||||
|
required String receivingAddressHex,
|
||||||
|
required TransactionPriority priority,
|
||||||
|
}) async {
|
||||||
try {
|
try {
|
||||||
if (priority is EVMChainTransactionPriority) {
|
if (priority is EVMChainTransactionPriority) {
|
||||||
final priorityFee = EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
|
final priorityFee = EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
|
||||||
return (_gasPrice! + priorityFee) * (_estimatedGas ?? 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
int maxFeePerGas;
|
||||||
|
if (gasBaseFee != null) {
|
||||||
|
// MaxFeePerGas with EIP1559;
|
||||||
|
maxFeePerGas = gasBaseFee! + priorityFee;
|
||||||
|
} else {
|
||||||
|
// MaxFeePerGas with gasPrice
|
||||||
|
maxFeePerGas = gasPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
final estimatedGas = await _client.getEstimatedGas(
|
||||||
|
contractAddress: contractAddress,
|
||||||
|
senderAddress: _evmChainPrivateKey.address,
|
||||||
|
value: EtherAmount.fromBigInt(EtherUnit.wei, amount!),
|
||||||
|
gasPrice: EtherAmount.fromInt(EtherUnit.wei, gasPrice),
|
||||||
|
toAddress: EthereumAddress.fromHex(receivingAddressHex),
|
||||||
|
// maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas),
|
||||||
|
// maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip),
|
||||||
|
);
|
||||||
|
|
||||||
|
final totalGasFee = estimatedGas * maxFeePerGas;
|
||||||
|
return totalGasFee;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -225,13 +286,12 @@ abstract class EVMChainWalletBase
|
||||||
syncStatus = AttemptingSyncStatus();
|
syncStatus = AttemptingSyncStatus();
|
||||||
await _updateBalance();
|
await _updateBalance();
|
||||||
await _updateTransactions();
|
await _updateTransactions();
|
||||||
_gasPrice = await _client.getGasUnitPrice();
|
|
||||||
_estimatedGas = await _client.getEstimatedGas();
|
|
||||||
|
|
||||||
Timer.periodic(
|
await _updateEstimatedGasFeeParams();
|
||||||
const Duration(minutes: 1), (timer) async => _gasPrice = await _client.getGasUnitPrice());
|
|
||||||
Timer.periodic(const Duration(seconds: 10),
|
Timer.periodic(const Duration(seconds: 10), (timer) async {
|
||||||
(timer) async => _estimatedGas = await _client.getEstimatedGas());
|
await _updateEstimatedGasFeeParams();
|
||||||
|
});
|
||||||
|
|
||||||
syncStatus = SyncedSyncStatus();
|
syncStatus = SyncedSyncStatus();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -239,6 +299,19 @@ abstract class EVMChainWalletBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _updateEstimatedGasFeeParams() async {
|
||||||
|
gasBaseFee = await _client.getGasBaseFee();
|
||||||
|
|
||||||
|
gasPrice = await _client.getGasUnitPrice();
|
||||||
|
|
||||||
|
estimatedGasUnits = await _client.getEstimatedGas(
|
||||||
|
senderAddress: _evmChainPrivateKey.address,
|
||||||
|
toAddress: _evmChainPrivateKey.address,
|
||||||
|
gasPrice: EtherAmount.fromInt(EtherUnit.wei, gasPrice),
|
||||||
|
value: EtherAmount.fromBigInt(EtherUnit.wei, BigInt.one),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||||
final _credentials = credentials as EVMChainTransactionCredentials;
|
final _credentials = credentials as EVMChainTransactionCredentials;
|
||||||
|
@ -258,8 +331,17 @@ abstract class EVMChainWalletBase
|
||||||
|
|
||||||
final erc20Balance = balance[transactionCurrency]!;
|
final erc20Balance = balance[transactionCurrency]!;
|
||||||
BigInt totalAmount = BigInt.zero;
|
BigInt totalAmount = BigInt.zero;
|
||||||
|
BigInt estimatedFeesForTransaction = BigInt.zero;
|
||||||
int exponent = transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18;
|
int exponent = transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18;
|
||||||
num amountToEVMChainMultiplier = pow(10, exponent);
|
num amountToEVMChainMultiplier = pow(10, exponent);
|
||||||
|
String? contractAddress;
|
||||||
|
String toAddress = _credentials.outputs.first.isParsedAddress
|
||||||
|
? _credentials.outputs.first.extractedAddress!
|
||||||
|
: _credentials.outputs.first.address;
|
||||||
|
|
||||||
|
if (transactionCurrency is Erc20Token) {
|
||||||
|
contractAddress = transactionCurrency.contractAddress;
|
||||||
|
}
|
||||||
|
|
||||||
// so far this can not be made with Ethereum as Ethereum does not support multiple recipients
|
// so far this can not be made with Ethereum as Ethereum does not support multiple recipients
|
||||||
if (hasMultiDestination) {
|
if (hasMultiDestination) {
|
||||||
|
@ -271,35 +353,50 @@ abstract class EVMChainWalletBase
|
||||||
outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)));
|
outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)));
|
||||||
totalAmount = BigInt.from(totalOriginalAmount * amountToEVMChainMultiplier);
|
totalAmount = BigInt.from(totalOriginalAmount * amountToEVMChainMultiplier);
|
||||||
|
|
||||||
|
final estimateFees = await calculateActualEstimatedFeeForCreateTransaction(
|
||||||
|
amount: totalAmount,
|
||||||
|
receivingAddressHex: toAddress,
|
||||||
|
priority: _credentials.priority!,
|
||||||
|
contractAddress: contractAddress,
|
||||||
|
);
|
||||||
|
|
||||||
|
estimatedFeesForTransaction = BigInt.from(estimateFees);
|
||||||
|
|
||||||
if (erc20Balance.balance < totalAmount) {
|
if (erc20Balance.balance < totalAmount) {
|
||||||
throw EVMChainTransactionCreationException(transactionCurrency);
|
throw EVMChainTransactionCreationException(transactionCurrency);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final output = outputs.first;
|
final output = outputs.first;
|
||||||
// since the fees are taken from Ethereum
|
if (!output.sendAll) {
|
||||||
// then no need to subtract the fees from the amount if send all
|
|
||||||
final BigInt allAmount;
|
|
||||||
if (transactionCurrency is Erc20Token) {
|
|
||||||
allAmount = erc20Balance.balance;
|
|
||||||
} else {
|
|
||||||
final estimatedFee = BigInt.from(calculateEstimatedFee(_credentials.priority!, null));
|
|
||||||
|
|
||||||
if (estimatedFee > erc20Balance.balance) {
|
|
||||||
throw EVMChainTransactionFeesException();
|
|
||||||
}
|
|
||||||
|
|
||||||
allAmount = erc20Balance.balance - estimatedFee;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output.sendAll) {
|
|
||||||
totalAmount = allAmount;
|
|
||||||
} else {
|
|
||||||
final totalOriginalAmount =
|
final totalOriginalAmount =
|
||||||
EVMChainFormatter.parseEVMChainAmountToDouble(output.formattedCryptoAmount ?? 0);
|
EVMChainFormatter.parseEVMChainAmountToDouble(output.formattedCryptoAmount ?? 0);
|
||||||
|
|
||||||
totalAmount = BigInt.from(totalOriginalAmount * amountToEVMChainMultiplier);
|
totalAmount = BigInt.from(totalOriginalAmount * amountToEVMChainMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (output.sendAll && transactionCurrency is Erc20Token) {
|
||||||
|
totalAmount = erc20Balance.balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
final estimateFees = await calculateActualEstimatedFeeForCreateTransaction(
|
||||||
|
amount: totalAmount,
|
||||||
|
receivingAddressHex: toAddress,
|
||||||
|
priority: _credentials.priority!,
|
||||||
|
contractAddress: contractAddress,
|
||||||
|
);
|
||||||
|
|
||||||
|
estimatedFeesForTransaction = BigInt.from(estimateFees);
|
||||||
|
|
||||||
|
debugPrint('Estimated Fees for Transaction: $estimatedFeesForTransaction');
|
||||||
|
|
||||||
|
if (output.sendAll && transactionCurrency is! Erc20Token) {
|
||||||
|
totalAmount = (erc20Balance.balance - estimatedFeesForTransaction);
|
||||||
|
|
||||||
|
if (estimatedFeesForTransaction > erc20Balance.balance) {
|
||||||
|
throw EVMChainTransactionFeesException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (erc20Balance.balance < totalAmount) {
|
if (erc20Balance.balance < totalAmount) {
|
||||||
throw EVMChainTransactionCreationException(transactionCurrency);
|
throw EVMChainTransactionCreationException(transactionCurrency);
|
||||||
}
|
}
|
||||||
|
@ -312,11 +409,9 @@ abstract class EVMChainWalletBase
|
||||||
|
|
||||||
final pendingEVMChainTransaction = await _client.signTransaction(
|
final pendingEVMChainTransaction = await _client.signTransaction(
|
||||||
privateKey: _evmChainPrivateKey,
|
privateKey: _evmChainPrivateKey,
|
||||||
toAddress: _credentials.outputs.first.isParsedAddress
|
toAddress: toAddress,
|
||||||
? _credentials.outputs.first.extractedAddress!
|
|
||||||
: _credentials.outputs.first.address,
|
|
||||||
amount: totalAmount,
|
amount: totalAmount,
|
||||||
gas: _estimatedGas!,
|
gas: estimatedFeesForTransaction,
|
||||||
priority: _credentials.priority!,
|
priority: _credentials.priority!,
|
||||||
currency: transactionCurrency,
|
currency: transactionCurrency,
|
||||||
exponent: exponent,
|
exponent: exponent,
|
||||||
|
@ -483,6 +578,7 @@ abstract class EVMChainWalletBase
|
||||||
return EthPrivateKey.fromHex(HEX.encode(addressAtIndex.privateKey as List<int>));
|
return EthPrivateKey.fromHex(HEX.encode(addressAtIndex.privateKey as List<int>));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void>? updateBalance() async => await _updateBalance();
|
Future<void>? updateBalance() async => await _updateBalance();
|
||||||
|
|
||||||
List<Erc20Token> get erc20Currencies => evmChainErc20TokensBox.values.toList();
|
List<Erc20Token> get erc20Currencies => evmChainErc20TokensBox.values.toList();
|
||||||
|
|
Loading…
Reference in a new issue