Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 60 additions & 2 deletions packages/komodo_defi_types/lib/src/utils/mnemonic_validator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,9 @@ class MnemonicValidator {
}

// Convert indices to binary string (11 bits per word)
final binaryString =
indices.map((i) => i.toRadixString(2).padLeft(11, '0')).join();
final binaryString = indices
.map((i) => i.toRadixString(2).padLeft(11, '0'))
.join();

// Calculate entropy and checksum lengths
final totalBits = binaryString.length;
Expand Down Expand Up @@ -198,4 +199,61 @@ class MnemonicValidator {

/// Checks if the wordlist has been initialized
bool get isInitialized => _validMnemonicWords.isNotEmpty;

/// Returns a set of BIP39 words that start with the given prefix.
///
/// This method is useful for implementing autocomplete functionality
/// when users are entering their seed phrase word by word.
///
/// [prefix] - The prefix to search for (case-insensitive)
/// [maxResults] - Maximum number of results to return (default: 10)
///
/// Returns an empty set if the wordlist is not initialized or if no matches
/// are found.
///
/// Example:
/// ```dart
/// final validator = MnemonicValidator();
/// await validator.init();
/// final matches = validator.getAutocompleteMatches('aba');
/// // Returns: {'abandon', 'ability', 'about'}
/// ```
Set<String> getAutocompleteMatches(String prefix, {int maxResults = 10}) {
assert(
_validMnemonicWords.isNotEmpty,
'Mnemonic wordlist is not initialized. '
'Call MnemonicValidator.init() first.',
);

if (prefix.isEmpty) {
return {};
}

final lowerPrefix = prefix.toLowerCase().trim();
final matches = <String>{};

for (final word in _validMnemonicWords) {
if (word.startsWith(lowerPrefix)) {
matches.add(word);
if (matches.length >= maxResults) {
break;
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Unpredictable Autocomplete Suggestions Due to Set Iteration

The getAutocompleteMatches method uses Sets for both its source wordlist and collected results. Since Set iteration order isn't guaranteed, hitting maxResults can lead to inconsistent autocomplete suggestions (different words or orders) for the same prefix across runs, creating an unpredictable user experience.

Fix in Cursor Fix in Web


return matches;
}

/// Returns all valid BIP39 words for reference.
///
/// This can be useful for implementing custom autocomplete UIs.
Set<String> getAllWords() {
assert(
_validMnemonicWords.isNotEmpty,
'Mnemonic wordlist is not initialized. '
'Call MnemonicValidator.init() first.',
);

return Set<String>.from(_validMnemonicWords);
}
}
Loading