fix: Error while approving transactions via walletconnect for ARB (#2878)

* fix: Error while approving transactions via walletconnect for ARB * fix: Error while approving transactions via walletconnect for ARB

David Adegoke committed Feb 9, 2026 at 15:58 UTC 143ce845045926faa1c1dbb9dbdd44dff10e6487
2 files changed +66 -37
lib/src/screens/wallet_connect/services/chain_service/eth/evm_chain_service.dart
+60 -30
@@ -1,7 +1,6 @@
1 import 'dart:convert';
2
3 import 'package:cake_wallet/generated/i18n.dart';
4 -import 'package:cake_wallet/reactions/wallet_connect.dart';
4 import 'package:cw_core/utils/proxy_wrapper.dart';
5 import 'package:eth_sig_util/eth_sig_util.dart';
6 import 'package:eth_sig_util/util/utils.dart';
@@ -17,6 +16,8 @@ import 'package:cake_wallet/src/screens/wallet_connect/utils/eth_utils.dart';
16 import 'package:cake_wallet/src/screens/wallet_connect/utils/method_utils.dart';
17 import 'package:cake_wallet/store/app_store.dart';
18 import 'package:cake_wallet/.secrets.g.dart' as secrets;
19 +import 'package:cake_wallet/evm/evm.dart';
20 +import 'package:cake_wallet/reactions/wallet_connect.dart';
21
22 class EvmChainServiceImpl {
23 Map<String, dynamic Function(String, dynamic)> get sessionRequestHandlers => {
@@ -38,11 +39,7 @@ class EvmChainServiceImpl {
39 required this.bottomSheetService,
40 required this.walletKit,
41 Web3Client? web3Client,
41 - }) : ethClient = web3Client ??
42 - Web3Client(
43 - _getNodeUriForChain(reference, appStore),
44 - ProxyWrapper().getHttpIOClient(),
45 - ) {
42 + }) : ethClient = web3Client ?? _createWeb3Client(reference, appStore) {
43 for (final event in EventsConstants.allEvents) {
44 walletKit.registerEventEmitter(
45 chainId: getChainId(),
@@ -77,17 +74,16 @@ class EvmChainServiceImpl {
74
75 String getChainId() => reference.chain();
76
80 - static String _getNodeUriForChain(EVMChainId reference, AppStore appStore) {
81 - final walletType = appStore.wallet!.type;
82 -
83 - if (isEVMCompatibleChain(walletType)) {
84 - final chainId = reference.chainId;
77 + static Web3Client _createWeb3Client(EVMChainId reference, AppStore appStore) {
78 + if (appStore.wallet != null && isEVMCompatibleChain(appStore.wallet!.type)) {
79 + final walletClient = evm?.getWeb3Client(appStore.wallet!);
80
86 - return appStore.settingsStore.getCurrentNode(walletType, chainId: chainId).uri.toString();
81 + if (walletClient != null) return walletClient;
82 }
83
89 - // For old wallet types, use the wallet type directly
90 - return appStore.settingsStore.getCurrentNode(walletType).uri.toString();
84 + final node = appStore.settingsStore.getCurrentNode(appStore.wallet!.type);
85 +
86 + return Web3Client(node.uri.toString(), ProxyWrapper().getHttpIOClient());
87 }
88
89 Future<void> personalSign(String topic, dynamic parameters) async {
@@ -423,25 +419,59 @@ class EvmChainServiceImpl {
419 }) async {
420 Transaction transaction = transactionJson.toTransaction();
421
426 - final gasPrice = await ethClient.getGasPrice();
427 - try {
428 - final gasLimit = await ethClient.estimateGas(
429 - sender: transaction.from,
430 - to: transaction.to,
431 - value: transaction.value,
432 - data: transaction.data,
433 - gasPrice: gasPrice,
434 - );
422 + if (transactionJson.containsKey('gas') && transaction.maxGas == null) {
423 + final gasHex = transactionJson['gas'].toString();
424 + try {
425 + final gasValue = int.parse(
426 + gasHex.replaceFirst('0x', '').replaceFirst('0X', ''),
427 + radix: 16,
428 + );
429 + transaction = transaction.copyWith(maxGas: gasValue);
430 + } catch (e) {
431 + debugPrint('Failed to parse gas value: $gasHex, error: $e');
432 + }
433 + }
434
436 - transaction = transaction.copyWith(
437 - gasPrice: gasPrice,
438 - maxGas: gasLimit.toInt(),
439 - );
440 - } on RPCError catch (e) {
441 - return JsonRpcError(code: e.errorCode, message: e.message);
435 + // we need to check if dApp provides the gas values and if not, we need to estimate them
436 + final hasGasLimit = transaction.maxGas != null && transaction.maxGas! > 0;
437 + final hasGasPrice = transaction.gasPrice != null;
438 + final hasMaxFeePerGas = transaction.maxFeePerGas != null;
439 + final hasMaxPriorityFeePerGas = transaction.maxPriorityFeePerGas != null;
440 +
441 + final needsGasEstimation = !hasGasLimit || (!hasGasPrice && !hasMaxFeePerGas);
442 +
443 + if (needsGasEstimation) {
444 + try {
445 + final gasPrice = hasGasPrice ? transaction.gasPrice! : await ethClient.getGasPrice();
446 +
447 + if (!hasGasLimit) {
448 + final gasLimit = await ethClient.estimateGas(
449 + sender: transaction.from,
450 + to: transaction.to,
451 + value: transaction.value,
452 + data: transaction.data,
453 + gasPrice: gasPrice,
454 + );
455 +
456 + if (hasMaxFeePerGas || hasMaxPriorityFeePerGas) {
457 + transaction = transaction.copyWith(maxGas: gasLimit.toInt());
458 + } else {
459 + transaction = transaction.copyWith(
460 + gasPrice: hasGasPrice ? transaction.gasPrice : gasPrice,
461 + maxGas: gasLimit.toInt(),
462 + );
463 + }
464 + } else if (!hasGasPrice && !hasMaxFeePerGas) {
465 + transaction = transaction.copyWith(gasPrice: gasPrice);
466 + }
467 + } on RPCError catch (e) {
468 + return JsonRpcError(code: e.errorCode, message: e.message);
469 + }
470 }
471
444 - final gweiGasPrice = (transaction.gasPrice?.getInWei ?? BigInt.zero) / BigInt.from(1000000000);
472 + final gweiGasPrice =
473 + (transaction.gasPrice?.getInWei ?? transaction.maxFeePerGas?.getInWei ?? BigInt.zero) /
474 + BigInt.from(1000000000);
475
476 final amount = (transaction.value?.getInWei ?? BigInt.zero) / BigInt.from(1e18);
477
lib/src/screens/wallet_connect/widgets/bottom_sheet/bottom_sheet_listener_widget.dart
+6 -7
@@ -42,16 +42,15 @@ class BottomSheetListenerState extends State<BottomSheetListener> {
42 backgroundColor: Color.fromARGB(0, 0, 0, 0),
43 isScrollControlled: true,
44 constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.9),
45 - builder: (context) {
45 + builder: (BuildContext bottomSheetContext) {
46 if (item.closeAfter > 0) {
47 Future.delayed(Duration(seconds: item.closeAfter), () {
48 try {
49 - if (!mounted) return;
50 - if (Navigator.canPop(context)) {
51 - Navigator.pop(context);
52 - }
53 - } catch (e, s) {
54 - debugPrint('[$runtimeType] close $e $s');
49 + final navigator = Navigator.maybeOf(bottomSheetContext, rootNavigator: false);
50 + navigator?.maybePop();
51 + } catch (e) {
52 + // the context is invalid as the bottom sheet was already closed,
53 + // this is expected and can be safely ignored
54 }
55 });
56 }