Skip to content
Merged
Show file tree
Hide file tree
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
5 changes: 4 additions & 1 deletion assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,9 @@
"dexErrorMessage": "Something went wrong!",
"seedConfirmInitialText": "Enter the seed phrase",
"seedConfirmIncorrectText": "Incorrect seed phrase",
"mnemonicInvalidWordError": "Your seed phrase contains an unknown word. Please check spelling and try again.",
"mnemonicInvalidChecksumError": "Your seed phrase appears valid but the checksum doesn't match. Check the word order and spacing.",
"mnemonicInvalidLengthError": "Seed phrase must contain between {} and {} words.",
"usedSamePassword": "This password matches your current one. Please create a different password.",
"passwordNotAccepted": "Password not accepted",
"confirmNewPassword": "Confirm new password",
Expand Down Expand Up @@ -737,4 +740,4 @@
"fetchingPrivateKeysMessage": "Please wait while we securely fetch your private keys...",
"pubkeyType": "Type",
"securitySettings": "Security Settings"
}
}
171 changes: 101 additions & 70 deletions lib/bloc/coin_addresses/bloc/coin_addresses_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import 'dart:async';

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:komodo_defi_sdk/komodo_defi_sdk.dart';
import 'package:komodo_defi_types/komodo_defi_types.dart' show Asset;
import 'package:komodo_defi_types/komodo_defi_types.dart' show NewAddressStatus;
import 'package:komodo_defi_types/komodo_defi_types.dart'
show Asset, NewAddressStatus, AssetPubkeys;
import 'package:web_dex/analytics/events.dart';
import 'package:web_dex/bloc/analytics/analytics_bloc.dart';
import 'package:web_dex/bloc/coin_addresses/bloc/coin_addresses_event.dart';
Expand All @@ -15,7 +15,7 @@ class CoinAddressesBloc extends Bloc<CoinAddressesEvent, CoinAddressesState> {
final String assetId;
final AnalyticsBloc analyticsBloc;

StreamSubscription<dynamic>? _pubkeysSub;
StreamSubscription<AssetPubkeys>? _pubkeysSub;
CoinAddressesBloc(this.sdk, this.assetId, this.analyticsBloc)
: super(const CoinAddressesState()) {
on<CoinAddressesAddressCreationSubmitted>(_onCreateAddressSubmitted);
Expand Down Expand Up @@ -43,57 +43,71 @@ class CoinAddressesBloc extends Bloc<CoinAddressesEvent, CoinAddressesState> {
newAddressState: () => null,
),
);

final stream = sdk.pubkeys.createNewPubkeyStream(getSdkAsset(sdk, assetId));

await for (final newAddressState in stream) {
emit(state.copyWith(newAddressState: () => newAddressState));

switch (newAddressState.status) {
case NewAddressStatus.completed:
final pubkey = newAddressState.address;
final derivation = pubkey?.derivationPath;
if (derivation != null) {
final parsed = parseDerivationPath(derivation);
analyticsBloc.logEvent(
HdAddressGeneratedEventData(
accountIndex: parsed.accountIndex,
addressIndex: parsed.addressIndex,
assetSymbol: assetId,
try {
final asset = getSdkAsset(sdk, assetId);
final stream = sdk.pubkeys.watchCreateNewPubkey(asset);

await for (final newAddressState in stream) {
emit(state.copyWith(newAddressState: () => newAddressState));

switch (newAddressState.status) {
case NewAddressStatus.completed:
final pubkey = newAddressState.address;
final derivation = pubkey?.derivationPath;
if (derivation != null) {
try {
final parsed = parseDerivationPath(derivation);
analyticsBloc.logEvent(
HdAddressGeneratedEventData(
accountIndex: parsed.accountIndex,
addressIndex: parsed.addressIndex,
assetSymbol: assetId,
),
);
} catch (_) {
// Non-fatal: continue without analytics if derivation parsing fails
}
}

add(const CoinAddressesSubscriptionRequested());

emit(
state.copyWith(
createAddressStatus: () => FormStatus.success,
newAddressState: () => null,
),
);
}

add(const CoinAddressesSubscriptionRequested());

emit(
state.copyWith(
createAddressStatus: () => FormStatus.success,
newAddressState: () => null,
),
);
return;
case NewAddressStatus.error:
emit(
state.copyWith(
createAddressStatus: () => FormStatus.failure,
errorMessage: () => newAddressState.error,
newAddressState: () => null,
),
);
return;
case NewAddressStatus.cancelled:
emit(
state.copyWith(
createAddressStatus: () => FormStatus.initial,
newAddressState: () => null,
),
);
return;
default:
// continue listening for next events
break;
return;
case NewAddressStatus.error:
emit(
state.copyWith(
createAddressStatus: () => FormStatus.failure,
errorMessage: () => newAddressState.error,
newAddressState: () => null,
),
);
return;
case NewAddressStatus.cancelled:
emit(
state.copyWith(
createAddressStatus: () => FormStatus.initial,
newAddressState: () => null,
),
);
return;
default:
// continue listening for next events
break;
}
}
} catch (e) {
emit(
state.copyWith(
createAddressStatus: () => FormStatus.failure,
errorMessage: () => e.toString(),
newAddressState: () => null,
),
);
}
}

Expand All @@ -114,10 +128,11 @@ class CoinAddressesBloc extends Bloc<CoinAddressesEvent, CoinAddressesState> {
status: () => FormStatus.success,
addresses: () => addresses,
cantCreateNewAddressReasons: () => reasons,
errorMessage: () => null,
),
);

_startWatchingPubkeys(asset);
await _startWatchingPubkeys(asset);
} catch (e) {
emit(
state.copyWith(
Expand Down Expand Up @@ -159,26 +174,42 @@ class CoinAddressesBloc extends Bloc<CoinAddressesEvent, CoinAddressesState> {
CoinAddressesPubkeysSubscriptionFailed event,
Emitter<CoinAddressesState> emit,
) {
emit(state.copyWith(errorMessage: () => event.error));
emit(
state.copyWith(
status: () => FormStatus.failure,
errorMessage: () => event.error,
),
);
}

void _startWatchingPubkeys(Asset asset) {
_pubkeysSub?.cancel();
// pre-cache pubkeys to ensure that any newly created pubkeys are available
// when we start watching. UI flickering between old and new states is
// avoided this way. The watchPubkeys function yields the last known pubkeys
// when the pubkeys stream is first activated.
sdk.pubkeys.preCachePubkeys(asset);
_pubkeysSub = sdk.pubkeys
.watchPubkeys(asset, activateIfNeeded: true)
.listen(
(assetPubkeys) {
add(CoinAddressesPubkeysUpdated(assetPubkeys.keys));
},
onError: (Object err) {
add(CoinAddressesPubkeysSubscriptionFailed(err.toString()));
},
);
Future<void> _startWatchingPubkeys(Asset asset) async {
try {
await _pubkeysSub?.cancel();
_pubkeysSub = null;
// Pre-cache pubkeys to ensure that any newly created pubkeys are available
// when we start watching. UI flickering between old and new states is
// avoided this way. The watchPubkeys function yields the last known pubkeys
// when the pubkeys stream is first activated.
await sdk.pubkeys.precachePubkeys(asset);
_pubkeysSub = sdk.pubkeys
.watchPubkeys(asset, activateIfNeeded: true)
.listen(
(AssetPubkeys assetPubkeys) {
if (!isClosed) {
add(CoinAddressesPubkeysUpdated(assetPubkeys.keys));
}
},
onError: (Object err) {
if (!isClosed) {
add(CoinAddressesPubkeysSubscriptionFailed(err.toString()));
}
},
);
} catch (e) {
if (!isClosed) {
add(CoinAddressesPubkeysSubscriptionFailed(e.toString()));
}
}
}

@override
Expand Down
3 changes: 3 additions & 0 deletions lib/generated/codegen_loader.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,9 @@ abstract class LocaleKeys {
static const dexErrorMessage = 'dexErrorMessage';
static const seedConfirmInitialText = 'seedConfirmInitialText';
static const seedConfirmIncorrectText = 'seedConfirmIncorrectText';
static const mnemonicInvalidWordError = 'mnemonicInvalidWordError';
static const mnemonicInvalidChecksumError = 'mnemonicInvalidChecksumError';
static const mnemonicInvalidLengthError = 'mnemonicInvalidLengthError';
static const usedSamePassword = 'usedSamePassword';
static const passwordNotAccepted = 'passwordNotAccepted';
static const confirmNewPassword = 'confirmNewPassword';
Expand Down
41 changes: 22 additions & 19 deletions lib/views/wallets_manager/widgets/wallet_simple_import.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ class WalletSimpleImport extends StatefulWidget {
required String name,
required String password,
required WalletConfig walletConfig,
}) onImport;
})
onImport;

final void Function() onCancel;

final void Function({required String fileName, required String fileData})
onUploadFiles;
onUploadFiles;

@override
State<WalletSimpleImport> createState() => _WalletImportWrapperState();
Expand Down Expand Up @@ -340,14 +341,16 @@ class _WalletImportWrapperState extends State<WalletSimpleImport> {
return null;
}

final maybeFailedReason =
context.read<KomodoDefiSdk>().mnemonicValidator.validateMnemonic(
seed ?? '',
minWordCount: 12,
maxWordCount: 24,
isHd: _isHdMode,
allowCustomSeed: _allowCustomSeed,
);
final maybeFailedReason = context
.read<KomodoDefiSdk>()
.mnemonicValidator
.validateMnemonic(
seed ?? '',
minWordCount: 12,
maxWordCount: 24,
isHd: _isHdMode,
allowCustomSeed: _allowCustomSeed,
);

if (maybeFailedReason == null) {
return null;
Expand All @@ -356,18 +359,18 @@ class _WalletImportWrapperState extends State<WalletSimpleImport> {
return switch (maybeFailedReason) {
MnemonicFailedReason.empty =>
LocaleKeys.walletCreationEmptySeedError.tr(),
MnemonicFailedReason.customNotSupportedForHd => _isHdMode
? LocaleKeys.walletCreationHdBip39SeedError.tr()
: LocaleKeys.walletCreationBip39SeedError.tr(),
MnemonicFailedReason.customNotAllowed =>
LocaleKeys.customSeedWarningText.tr(),
MnemonicFailedReason.invalidLength =>
// TODO: Add this string has placeholders for min/max counts, which we
// specify as "12" and "24"
// LocaleKeys.seedPhraseCheckingEnterWord.tr(args: ['12', '24']),
MnemonicFailedReason.customNotSupportedForHd =>
_isHdMode
? LocaleKeys.walletCreationHdBip39SeedError.tr()
: LocaleKeys.walletCreationBip39SeedError.tr(),
MnemonicFailedReason.customNotAllowed =>
LocaleKeys.customSeedWarningText.tr(),
MnemonicFailedReason.invalidWord =>
LocaleKeys.mnemonicInvalidWordError.tr(),
MnemonicFailedReason.invalidChecksum =>
LocaleKeys.mnemonicInvalidChecksumError.tr(),
MnemonicFailedReason.invalidLength =>
LocaleKeys.mnemonicInvalidLengthError.tr(args: ['12', '24']),
};
}
}
22 changes: 19 additions & 3 deletions packages/komodo_ui_kit/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.19.1"
crypto:
dependency: transitive
description:
name: crypto
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
url: "https://pub.dev"
source: hosted
version: "3.0.6"
decimal:
dependency: transitive
description:
Expand Down Expand Up @@ -95,7 +103,7 @@ packages:
description:
path: "packages/komodo_defi_rpc_methods"
ref: dev
resolved-ref: "68429b23dac43eddd53434dda1bd23296523f27d"
resolved-ref: d5b5c38da93e62f59bffb8e6b3e1e7ceb3fb91d5
url: "https://github.com/KomodoPlatform/komodo-defi-sdk-flutter.git"
source: git
version: "0.3.0+0"
Expand All @@ -104,7 +112,7 @@ packages:
description:
path: "packages/komodo_defi_types"
ref: dev
resolved-ref: "68429b23dac43eddd53434dda1bd23296523f27d"
resolved-ref: d5b5c38da93e62f59bffb8e6b3e1e7ceb3fb91d5
url: "https://github.com/KomodoPlatform/komodo-defi-sdk-flutter.git"
source: git
version: "0.3.0+0"
Expand All @@ -113,7 +121,7 @@ packages:
description:
path: "packages/komodo_ui"
ref: dev
resolved-ref: "68429b23dac43eddd53434dda1bd23296523f27d"
resolved-ref: d5b5c38da93e62f59bffb8e6b3e1e7ceb3fb91d5
url: "https://github.com/KomodoPlatform/komodo-defi-sdk-flutter.git"
source: git
version: "0.3.0+0"
Expand Down Expand Up @@ -178,6 +186,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vector_math:
dependency: transitive
description:
Expand Down
Loading
Loading