fix: walletconnect fee refresh (#3153)

* fix: refresh EIP-1559 fees before sign for walletconnect transactions

* fix: add missing data to configure file

---------

Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
David Adegoke
2026-04-09 10:45:14 +02:00
committed by GitHub
co-authored by Omar Hatem
parent fd62cd5b52
commit ef752c747e
5 changed files with 209 additions and 80 deletions
+20 -6
View File
@@ -239,10 +239,7 @@ class CWEVM extends EVM {
(wallet as EVMChainWallet).isApprovalRequired(tokenContract, spender, requiredAmount);
@override
Future<BigInt?> getAllowance(
WalletBase wallet,
String tokenContract,
String spender) =>
Future<BigInt?> getAllowance(WalletBase wallet, String tokenContract, String spender) =>
(wallet as EVMChainWallet).getAllowance(tokenContract, spender);
@override
@@ -272,7 +269,7 @@ class CWEVM extends EVM {
String to,
String dataHex,
BigInt valueWei,
TransactionPriority? priority,{
TransactionPriority? priority, {
bool useBlinkProtection = true,
String? sourceTokenAddress,
BigInt? sourceTokenAmount,
@@ -481,7 +478,7 @@ class CWEVM extends EVM {
@override
BigInt? getERC20AvailableBalance(Object balance) {
if(balance is EVMChainERC20Balance) {
if (balance is EVMChainERC20Balance) {
return balance.balance;
}
return null;
@@ -544,6 +541,23 @@ class CWEVM extends EVM {
@override
bool hasPriorityFee(int chainId) => EVMChainUtils.hasPriorityFee(chainId);
@override
Future<EvmWalletConnectFeeQuote?> getWCBufferedFeeQuote(
WalletBase wallet,
TransactionPriority priority,
) async {
if (wallet is! EVMChainWallet) return null;
final data = await wallet.getWCBufferedFeeQuote(priority);
if (data == null) return null;
return EvmWalletConnectFeeQuote(
maxFeePerGasWei: data.maxFeePerGasWei,
maxPriorityFeePerGasWei: data.maxPriorityFeePerGasWei,
latestBaseFeeWei: data.latestBaseFeeWei,
);
}
Future<({double usdValue, bool hasValidFiatPrice})> _getTokenUsdValueAndFiatCheck(
Erc20Token token,
BigInt balanceWei,
@@ -432,43 +432,14 @@ class EvmChainServiceImpl {
}
}
// we need to check if dApp provides the gas values and if not, we need to estimate them
final hasGasLimit = transaction.maxGas != null && transaction.maxGas! > 0;
final hasGasPrice = transaction.gasPrice != null;
final hasMaxFeePerGas = transaction.maxFeePerGas != null;
final hasMaxPriorityFeePerGas = transaction.maxPriorityFeePerGas != null;
final needsGasEstimation = !hasGasLimit || (!hasGasPrice && !hasMaxFeePerGas);
if (needsGasEstimation) {
try {
final gasPrice = hasGasPrice ? transaction.gasPrice! : await ethClient.getGasPrice();
if (!hasGasLimit) {
final gasLimit = await ethClient.estimateGas(
sender: transaction.from,
to: transaction.to,
value: transaction.value,
data: transaction.data,
gasPrice: gasPrice,
);
if (hasMaxFeePerGas || hasMaxPriorityFeePerGas) {
transaction = transaction.copyWith(maxGas: gasLimit.toInt());
} else {
transaction = transaction.copyWith(
gasPrice: hasGasPrice ? transaction.gasPrice : gasPrice,
maxGas: gasLimit.toInt(),
);
}
} else if (!hasGasPrice && !hasMaxFeePerGas) {
transaction = transaction.copyWith(gasPrice: gasPrice);
}
} on RPCError catch (e) {
return JsonRpcError(code: e.errorCode, message: e.message);
}
try {
transaction = await _ensureWCTransactionHasGasLimit(transaction);
} on RPCError catch (e) {
return JsonRpcError(code: e.errorCode, message: e.message);
}
transaction = await _applyWCBufferedFees(transaction);
final gweiGasPrice =
(transaction.gasPrice?.getInWei ?? transaction.maxFeePerGas?.getInWei ?? BigInt.zero) /
BigInt.from(1000000000);
@@ -500,6 +471,90 @@ class EvmChainServiceImpl {
return JsonRpcError(code: 5002, message: S.current.user_rejected_method);
}
Future<Transaction> _ensureWCTransactionHasGasLimit(Transaction transaction) async {
final hasGasLimit = transaction.maxGas != null && transaction.maxGas! > 0;
if (hasGasLimit) return transaction;
final hint = transaction.gasPrice ?? transaction.maxFeePerGas ?? await ethClient.getGasPrice();
final gasLimit = await ethClient.estimateGas(
sender: transaction.from,
to: transaction.to,
value: transaction.value,
data: transaction.data,
gasPrice: hint,
);
if (transaction.isEIP1559) {
return transaction.copyWith(maxGas: gasLimit.toInt());
}
return transaction.copyWith(
maxGas: gasLimit.toInt(),
gasPrice: transaction.gasPrice ?? hint,
);
}
Future<Transaction> _applyWCBufferedFees(Transaction transaction) async {
try {
final storedPriority =
appStore.settingsStore.getPriority(appStore.wallet!.type, chainId: reference.chainId);
final priority = storedPriority ?? evm!.getDefaultTransactionPriority();
final quote = await evm!.getWCBufferedFeeQuote(appStore.wallet!, priority);
if (quote != null) {
return _mergeWCBufferedFees(transaction, quote);
}
} catch (e) {
debugPrint('WalletConnect fee refresh failed: $e');
}
if (!transaction.isEIP1559 && transaction.gasPrice == null) {
return transaction.copyWith(gasPrice: await ethClient.getGasPrice());
}
return transaction;
}
Transaction _mergeWCBufferedFees(Transaction transaction, EvmWalletConnectFeeQuote quote) {
if (transaction.isEIP1559) {
// the fees coming from the dApp
final dAppMax = transaction.maxFeePerGas?.getInWei ?? BigInt.zero;
final dAppPri = transaction.maxPriorityFeePerGas?.getInWei ?? BigInt.zero;
// the updated fees coming from the wallet, handles buffered fees
final quoteMax = BigInt.from(quote.maxFeePerGasWei);
final quotePri = BigInt.from(quote.maxPriorityFeePerGasWei);
// we'll just use the higher of the two
var newMaxFeePerGasWei = dAppMax > quoteMax ? dAppMax : quoteMax;
var newPriorityFeePerGasWei = dAppPri > quotePri ? dAppPri : quotePri;
final base = quote.latestBaseFeeWei;
if (base != null) {
final baseB = BigInt.from(base);
final maxPriAllowed = newMaxFeePerGasWei - baseB;
if (newPriorityFeePerGasWei > maxPriAllowed) {
if (maxPriAllowed > BigInt.zero) {
newPriorityFeePerGasWei = maxPriAllowed;
} else {
newMaxFeePerGasWei = baseB + newPriorityFeePerGasWei;
}
}
}
return transaction.copyWith(
maxFeePerGas: EtherAmount.inWei(newMaxFeePerGasWei),
maxPriorityFeePerGas: EtherAmount.inWei(newPriorityFeePerGasWei),
);
}
final dPrice = transaction.gasPrice?.getInWei ?? BigInt.zero;
final floor = BigInt.from(quote.maxFeePerGasWei);
final newPriceWei = dPrice > floor ? dPrice : floor;
return transaction.copyWith(gasPrice: EtherAmount.inWei(newPriceWei));
}
void _onSessionRequest(SessionRequestEvent? args) async {
if (args != null && args.chainId == getChainId()) {
debugPrint('_onSessionRequest ${args.toString()}');