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
}