fix: validate EVM restore mnemonic checksum (#3498)

* fix: validate EVM restore mnemonics

* chore: drop test changes from this PR

Removes the test additions/modifications introduced by this branch so the
test design is left to the maintainers. Production code is unchanged.
This commit is contained in:
Seth For Privacy
2026-08-16 10:57:47 +02:00
committed by GitHub
parent 8f38ba6b17
commit 8a366129f8
3 changed files with 34 additions and 16 deletions
@@ -11,6 +11,7 @@ import 'package:cake_wallet/view_model/restore/restore_mode.dart';
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
import 'package:cw_core/currency_for_wallet_type.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:bip39/bip39.dart' as bip39;
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:collection/collection.dart';
@@ -89,9 +90,7 @@ class WalletRestoreFromQRCode {
try {
return AddressResolverUtils.extractAddressByType(
raw: rawString,
type: walletTypeToCryptoCurrency(
type,
),
type: walletTypeToCryptoCurrency(type),
requireSurroundingWhitespaces: false,
);
} catch (_) {
@@ -127,8 +126,8 @@ class WalletRestoreFromQRCode {
final prefix = code.startsWith('xpub')
? 'xpub'
: code.startsWith('zpub')
? 'zpub'
: '????';
? 'zpub'
: '????';
if (walletType == null) {
await _specifyWalletAssets(context, "Can't determine wallet type, please pick it manually");
walletType =
@@ -140,8 +139,8 @@ class WalletRestoreFromQRCode {
formattedUri = seedPhrase != null
? '$walletType:?seed=$seedPhrase'
: code.startsWith(prefix)
? '$walletType:?$prefix=$code'
: throw Exception('Failed to determine valid seed phrase');
? '$walletType:?$prefix=$code'
: throw Exception('Failed to determine valid seed phrase');
} else {
final index = code.indexOf(':');
final query = code.substring(index + 1).replaceAll('?', '&');
@@ -202,9 +201,15 @@ class WalletRestoreFromQRCode {
seedValue.split(' ').forEach((element) {
if (!words.contains(element)) {
throw Exception(
"Unexpected restore mode: mnemonic_seed is invalid or doesn't match wallet type");
"Unexpected restore mode: mnemonic_seed is invalid or doesn't match wallet type",
);
}
});
if (isEVMCompatibleChain(type) && !bip39.validateMnemonic(seedValue)) {
throw Exception(
'EVM mnemonic has an invalid checksum. Please check the seed phrase for typos.',
);
}
return WalletRestoreMode.seed;
}
@@ -268,12 +273,14 @@ class WalletRestoreFromQRCode {
Future<void> _specifyWalletAssets(BuildContext context, String error) async {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.current.error,
alertContent: error,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.current.error,
alertContent: error,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop(),
);
},
);
}