mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
Node Auto-reconnect and connectivity enhancements (#1513)
* Add auto-reconnect Enhance connectivity issues * minor enhancement [skip ci] * minor: remove core secrets since it's empty * pending transactions fix * temporary fix for RBF * remove unused hashes from cache key * fix minimum limits check * Add authentication to services api * update polyseed * override hashlib package
This commit is contained in:
parent
0335702aa9
commit
f902a644db
19 changed files with 131 additions and 222 deletions
2
.github/workflows/pr_test_build.yml
vendored
2
.github/workflows/pr_test_build.yml
vendored
|
@ -80,7 +80,7 @@ jobs:
|
||||||
/opt/android/cake_wallet/cw_monero/ios/External
|
/opt/android/cake_wallet/cw_monero/ios/External
|
||||||
/opt/android/cake_wallet/cw_shared_external/ios/External
|
/opt/android/cake_wallet/cw_shared_external/ios/External
|
||||||
/opt/android/cake_wallet/scripts/monero_c/release
|
/opt/android/cake_wallet/scripts/monero_c/release
|
||||||
key: ${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh', '**/build_haven.sh', '**/monero_api.cpp') }}
|
key: ${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh') }}
|
||||||
|
|
||||||
- if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
|
- if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
|
||||||
name: Generate Externals
|
name: Generate Externals
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
-
|
-
|
||||||
uri: ltc-electrum.cakewallet.com:50002
|
uri: ltc-electrum.cakewallet.com:50002
|
||||||
|
useSSL: true
|
||||||
|
isDefault: true
|
|
@ -97,26 +97,7 @@ abstract class ElectrumWalletBase
|
||||||
this.walletInfo = walletInfo;
|
this.walletInfo = walletInfo;
|
||||||
transactionHistory = ElectrumTransactionHistory(walletInfo: walletInfo, password: password);
|
transactionHistory = ElectrumTransactionHistory(walletInfo: walletInfo, password: password);
|
||||||
|
|
||||||
reaction((_) => syncStatus, (SyncStatus syncStatus) async {
|
reaction((_) => syncStatus, _syncStatusReaction);
|
||||||
if (syncStatus is! AttemptingSyncStatus && syncStatus is! SyncedTipSyncStatus) {
|
|
||||||
silentPaymentsScanningActive = syncStatus is SyncingSyncStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (syncStatus is NotConnectedSyncStatus) {
|
|
||||||
// Needs to re-subscribe to all scripthashes when reconnected
|
|
||||||
_scripthashesUpdateSubject = {};
|
|
||||||
|
|
||||||
// TODO: double check this and make sure it doesn't cause any un-necessary calls
|
|
||||||
// await this.electrumClient.connectToUri(node!.uri, useSSL: node!.useSSL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Message is shown on the UI for 3 seconds, revert to synced
|
|
||||||
if (syncStatus is SyncedTipSyncStatus) {
|
|
||||||
Timer(Duration(seconds: 3), () {
|
|
||||||
if (this.syncStatus is SyncedTipSyncStatus) this.syncStatus = SyncedSyncStatus();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bitcoin.HDWallet getAccountHDWallet(
|
static bitcoin.HDWallet getAccountHDWallet(
|
||||||
|
@ -201,6 +182,8 @@ abstract class ElectrumWalletBase
|
||||||
@observable
|
@observable
|
||||||
bool silentPaymentsScanningActive = false;
|
bool silentPaymentsScanningActive = false;
|
||||||
|
|
||||||
|
bool _isTryingToConnect = false;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> setSilentPaymentsScanning(bool active, bool usingElectrs) async {
|
Future<void> setSilentPaymentsScanning(bool active, bool usingElectrs) async {
|
||||||
silentPaymentsScanningActive = active;
|
silentPaymentsScanningActive = active;
|
||||||
|
@ -1830,6 +1813,38 @@ abstract class ElectrumWalletBase
|
||||||
syncStatus = NotConnectedSyncStatus();
|
syncStatus = NotConnectedSyncStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _syncStatusReaction(SyncStatus syncStatus) async {
|
||||||
|
if (syncStatus is! AttemptingSyncStatus && syncStatus is! SyncedTipSyncStatus) {
|
||||||
|
silentPaymentsScanningActive = syncStatus is SyncingSyncStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syncStatus is NotConnectedSyncStatus) {
|
||||||
|
// Needs to re-subscribe to all scripthashes when reconnected
|
||||||
|
_scripthashesUpdateSubject = {};
|
||||||
|
|
||||||
|
if (_isTryingToConnect) return;
|
||||||
|
|
||||||
|
_isTryingToConnect = true;
|
||||||
|
|
||||||
|
Future.delayed(Duration(seconds: 10), () {
|
||||||
|
if (this.syncStatus is! SyncedSyncStatus && this.syncStatus is! SyncedTipSyncStatus) {
|
||||||
|
this.electrumClient.connectToUri(
|
||||||
|
node!.uri,
|
||||||
|
useSSL: node!.useSSL ?? false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_isTryingToConnect = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message is shown on the UI for 3 seconds, revert to synced
|
||||||
|
if (syncStatus is SyncedTipSyncStatus) {
|
||||||
|
Timer(Duration(seconds: 3), () {
|
||||||
|
if (this.syncStatus is SyncedTipSyncStatus) this.syncStatus = SyncedSyncStatus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ScanNode {
|
class ScanNode {
|
||||||
|
|
|
@ -866,10 +866,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: unorm_dart
|
name: unorm_dart
|
||||||
sha256: "5b35bff83fce4d76467641438f9e867dc9bcfdb8c1694854f230579d68cd8f4b"
|
sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "0.3.0"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -227,6 +227,9 @@ class Node extends HiveObject with Keyable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this will return true most of the time, even if the node has useSSL set to true while
|
||||||
|
// it doesn't support SSL or vice versa, because it will connect normally, but it will fail if
|
||||||
|
// you try to communicate with it
|
||||||
Future<bool> requestElectrumServer() async {
|
Future<bool> requestElectrumServer() async {
|
||||||
try {
|
try {
|
||||||
if (useSSL == true) {
|
if (useSSL == true) {
|
||||||
|
|
|
@ -655,6 +655,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.3.1"
|
||||||
|
unorm_dart:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: unorm_dart
|
||||||
|
sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.0"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -543,10 +543,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: polyseed
|
name: polyseed
|
||||||
sha256: a340962242d7917b0f3e6bd02c4acc3f90eae8ff766f1244f793ae7a6414dd68
|
sha256: edf28042e7b0b28f97a0469aa98e6e4015937cef6b9340cd6ad2822139c95217
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.4"
|
version: "0.0.5"
|
||||||
pool:
|
pool:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -696,6 +696,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.3.1"
|
||||||
|
unorm_dart:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: unorm_dart
|
||||||
|
sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.0"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -805,6 +805,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.2"
|
version: "1.3.2"
|
||||||
|
unorm_dart:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: unorm_dart
|
||||||
|
sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.0"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -543,10 +543,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: polyseed
|
name: polyseed
|
||||||
sha256: a340962242d7917b0f3e6bd02c4acc3f90eae8ff766f1244f793ae7a6414dd68
|
sha256: edf28042e7b0b28f97a0469aa98e6e4015937cef6b9340cd6ad2822139c95217
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.4"
|
version: "0.0.5"
|
||||||
pool:
|
pool:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -696,6 +696,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.3.1"
|
||||||
|
unorm_dart:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: unorm_dart
|
||||||
|
sha256: "23d8bf65605401a6a32cff99435fed66ef3dab3ddcad3454059165df46496a3b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.0"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -19,7 +19,7 @@ dependencies:
|
||||||
flutter_mobx: ^2.0.6+1
|
flutter_mobx: ^2.0.6+1
|
||||||
intl: ^0.18.0
|
intl: ^0.18.0
|
||||||
encrypt: ^5.0.1
|
encrypt: ^5.0.1
|
||||||
polyseed: ^0.0.4
|
polyseed: ^0.0.5
|
||||||
cw_core:
|
cw_core:
|
||||||
path: ../cw_core
|
path: ../cw_core
|
||||||
monero:
|
monero:
|
||||||
|
|
|
@ -438,7 +438,7 @@ class CWBitcoin extends Bitcoin {
|
||||||
@override
|
@override
|
||||||
int getMaxCustomFeeRate(Object wallet) {
|
int getMaxCustomFeeRate(Object wallet) {
|
||||||
final bitcoinWallet = wallet as ElectrumWallet;
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
return (bitcoinWallet.feeRate(BitcoinTransactionPriority.fast) * 1.1).round();
|
return (bitcoinWallet.feeRate(BitcoinTransactionPriority.fast) * 10).round();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -242,6 +242,7 @@ Future<void> defaultSettingsMigration(
|
||||||
await fixBtcDerivationPaths(walletInfoSource);
|
await fixBtcDerivationPaths(walletInfoSource);
|
||||||
break;
|
break;
|
||||||
case 39:
|
case 39:
|
||||||
|
_fixNodesUseSSLFlag(nodes);
|
||||||
await changeDefaultNanoNode(nodes, sharedPreferences);
|
await changeDefaultNanoNode(nodes, sharedPreferences);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -258,6 +259,17 @@ Future<void> defaultSettingsMigration(
|
||||||
await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version);
|
await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _fixNodesUseSSLFlag(Box<Node> nodes) {
|
||||||
|
for (Node node in nodes.values) {
|
||||||
|
switch (node.uriRaw) {
|
||||||
|
case cakeWalletLitecoinElectrumUri:
|
||||||
|
case cakeWalletBitcoinElectrumUri:
|
||||||
|
node.useSSL = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> updateNanoNodeList({required Box<Node> nodes}) async {
|
Future<void> updateNanoNodeList({required Box<Node> nodes}) async {
|
||||||
final nodeList = await loadDefaultNanoNodes();
|
final nodeList = await loadDefaultNanoNodes();
|
||||||
var listOfNewEndpoints = <String>[
|
var listOfNewEndpoints = <String>[
|
||||||
|
|
|
@ -1,163 +0,0 @@
|
||||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
|
||||||
import 'package:cake_wallet/core/email_validator.dart';
|
|
||||||
import 'package:cake_wallet/ionia/ionia_create_state.dart';
|
|
||||||
import 'package:cake_wallet/routes.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
|
||||||
import 'package:cake_wallet/typography.dart';
|
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
|
||||||
import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart';
|
|
||||||
import 'package:flutter/gestures.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
|
||||||
import 'package:mobx/mobx.dart';
|
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
|
||||||
|
|
||||||
class IoniaCreateAccountPage extends BasePage {
|
|
||||||
IoniaCreateAccountPage(this._authViewModel)
|
|
||||||
: _emailFocus = FocusNode(),
|
|
||||||
_emailController = TextEditingController(),
|
|
||||||
_formKey = GlobalKey<FormState>() {
|
|
||||||
_emailController.text = _authViewModel.email;
|
|
||||||
_emailController.addListener(() => _authViewModel.email = _emailController.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
final IoniaAuthViewModel _authViewModel;
|
|
||||||
|
|
||||||
final GlobalKey<FormState> _formKey;
|
|
||||||
|
|
||||||
final FocusNode _emailFocus;
|
|
||||||
final TextEditingController _emailController;
|
|
||||||
|
|
||||||
static const privacyPolicyUrl = 'https://ionia.docsend.com/view/jhjvdn7qq7k3ukwt';
|
|
||||||
static const termsAndConditionsUrl = 'https://ionia.docsend.com/view/uceirymz2ijacq5g';
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget middle(BuildContext context) {
|
|
||||||
return Text(
|
|
||||||
S.current.sign_up,
|
|
||||||
style: textMediumSemiBold(
|
|
||||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget body(BuildContext context) {
|
|
||||||
reaction((_) => _authViewModel.createUserState, (IoniaCreateAccountState state) {
|
|
||||||
if (state is IoniaCreateStateFailure) {
|
|
||||||
_onCreateUserFailure(context, state.error);
|
|
||||||
}
|
|
||||||
if (state is IoniaCreateStateSuccess) {
|
|
||||||
_onCreateSuccessful(context, _authViewModel);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return ScrollableWithBottomSection(
|
|
||||||
contentPadding: EdgeInsets.all(24),
|
|
||||||
content: Form(
|
|
||||||
key: _formKey,
|
|
||||||
child: BaseTextFormField(
|
|
||||||
hintText: S.of(context).email_address,
|
|
||||||
focusNode: _emailFocus,
|
|
||||||
validator: EmailValidator(),
|
|
||||||
keyboardType: TextInputType.emailAddress,
|
|
||||||
controller: _emailController,
|
|
||||||
onSubmit: (_) => _createAccount(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
bottomSectionPadding: EdgeInsets.symmetric(vertical: 36, horizontal: 24),
|
|
||||||
bottomSection: Column(
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: <Widget>[
|
|
||||||
Observer(
|
|
||||||
builder: (_) => LoadingPrimaryButton(
|
|
||||||
text: S.of(context).create_account,
|
|
||||||
onPressed: _createAccount,
|
|
||||||
isLoading:
|
|
||||||
_authViewModel.createUserState is IoniaCreateStateLoading,
|
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
textColor: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
height: 20,
|
|
||||||
),
|
|
||||||
RichText(
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
text: TextSpan(
|
|
||||||
text: S.of(context).agree_to,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Color(0xff7A93BA),
|
|
||||||
fontSize: 12,
|
|
||||||
fontFamily: 'Lato',
|
|
||||||
),
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: S.of(context).settings_terms_and_conditions,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
|
||||||
recognizer: TapGestureRecognizer()
|
|
||||||
..onTap = () async {
|
|
||||||
final uri = Uri.parse(termsAndConditionsUrl);
|
|
||||||
if (await canLaunchUrl(uri))
|
|
||||||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
TextSpan(text: ' ${S.of(context).and} '),
|
|
||||||
TextSpan(
|
|
||||||
text: S.of(context).privacy_policy,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
|
||||||
recognizer: TapGestureRecognizer()
|
|
||||||
..onTap = () async {
|
|
||||||
final uri = Uri.parse(privacyPolicyUrl);
|
|
||||||
if (await canLaunchUrl(uri))
|
|
||||||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
|
||||||
}),
|
|
||||||
TextSpan(text: ' ${S.of(context).by_cake_pay}'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onCreateUserFailure(BuildContext context, String error) {
|
|
||||||
showPopUp<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return AlertWithOneAction(
|
|
||||||
alertTitle: S.current.create_account,
|
|
||||||
alertContent: error,
|
|
||||||
buttonText: S.of(context).ok,
|
|
||||||
buttonAction: () => Navigator.of(context).pop());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onCreateSuccessful(BuildContext context, IoniaAuthViewModel authViewModel) => Navigator.pushNamed(
|
|
||||||
context,
|
|
||||||
Routes.ioniaVerifyIoniaOtpPage,
|
|
||||||
arguments: [authViewModel.email, false],
|
|
||||||
);
|
|
||||||
|
|
||||||
void _createAccount() async {
|
|
||||||
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await _authViewModel.createUser(_emailController.text);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -48,6 +48,7 @@ import 'package:mobx/mobx.dart';
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||||
|
|
||||||
part 'dashboard_view_model.g.dart';
|
part 'dashboard_view_model.g.dart';
|
||||||
|
|
||||||
|
@ -375,7 +376,8 @@ abstract class DashboardViewModelBase with Store {
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get hasSellProviders => ProvidersHelper.getAvailableSellProviderTypes(wallet.type).isNotEmpty;
|
bool get hasSellProviders =>
|
||||||
|
ProvidersHelper.getAvailableSellProviderTypes(wallet.type).isNotEmpty;
|
||||||
|
|
||||||
bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup;
|
bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup;
|
||||||
|
|
||||||
|
@ -535,7 +537,10 @@ abstract class DashboardViewModelBase with Store {
|
||||||
|
|
||||||
Future<List<String>> checkForHavenWallets() async {
|
Future<List<String>> checkForHavenWallets() async {
|
||||||
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
|
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
|
||||||
return walletInfoSource.values.where((element) => element.type == WalletType.haven).map((e) => e.name).toList();
|
return walletInfoSource.values
|
||||||
|
.where((element) => element.type == WalletType.haven)
|
||||||
|
.map((e) => e.name)
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<String>> checkAffectedWallets() async {
|
Future<List<String>> checkAffectedWallets() async {
|
||||||
|
@ -576,29 +581,34 @@ abstract class DashboardViewModelBase with Store {
|
||||||
Future<ServicesResponse> getServicesStatus() async {
|
Future<ServicesResponse> getServicesStatus() async {
|
||||||
try {
|
try {
|
||||||
if (isEnabledBulletinAction) {
|
if (isEnabledBulletinAction) {
|
||||||
final res = await http.get(Uri.parse("https://service-api.cakewallet.com/v1/active-notices"));
|
final uri = Uri.https(
|
||||||
|
"service-api.cakewallet.com",
|
||||||
|
"/v1/active-notices",
|
||||||
|
{'key': secrets.fiatApiKey},
|
||||||
|
);
|
||||||
|
|
||||||
if (res.statusCode < 200 || res.statusCode >= 300) {
|
final res = await http.get(uri);
|
||||||
throw res.body;
|
|
||||||
}
|
|
||||||
|
|
||||||
final oldSha = sharedPreferences.getString(PreferencesKey.serviceStatusShaKey);
|
if (res.statusCode < 200 || res.statusCode >= 300) {
|
||||||
|
throw res.body;
|
||||||
final hash = await Cryptography.instance.sha256().hash(utf8.encode(res.body));
|
|
||||||
final currentSha = bytesToHex(hash.bytes);
|
|
||||||
|
|
||||||
final hasUpdates = oldSha != currentSha;
|
|
||||||
|
|
||||||
return ServicesResponse.fromJson(
|
|
||||||
json.decode(res.body) as Map<String, dynamic>,
|
|
||||||
hasUpdates,
|
|
||||||
currentSha,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return ServicesResponse([], false, '');
|
|
||||||
}
|
}
|
||||||
} catch (_) {
|
|
||||||
|
final oldSha = sharedPreferences.getString(PreferencesKey.serviceStatusShaKey);
|
||||||
|
|
||||||
|
final hash = await Cryptography.instance.sha256().hash(utf8.encode(res.body));
|
||||||
|
final currentSha = bytesToHex(hash.bytes);
|
||||||
|
|
||||||
|
final hasUpdates = oldSha != currentSha;
|
||||||
|
|
||||||
|
return ServicesResponse.fromJson(
|
||||||
|
json.decode(res.body) as Map<String, dynamic>,
|
||||||
|
hasUpdates,
|
||||||
|
currentSha,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return ServicesResponse([], false, '');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
return ServicesResponse([], false, '');
|
return ServicesResponse([], false, '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -508,7 +508,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
if (limitsState is LimitsLoadedSuccessfully) {
|
if (limitsState is LimitsLoadedSuccessfully) {
|
||||||
if (double.tryParse(amount) == null) continue;
|
if (double.tryParse(amount) == null) continue;
|
||||||
|
|
||||||
if (limits.max != null && double.parse(amount) < limits.min!)
|
if (limits.min != null && double.parse(amount) < limits.min!)
|
||||||
continue;
|
continue;
|
||||||
else if (limits.max != null && double.parse(amount) > limits.max!)
|
else if (limits.max != null && double.parse(amount) > limits.max!)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import device_info_plus
|
||||||
import devicelocale
|
import devicelocale
|
||||||
import flutter_inappwebview_macos
|
import flutter_inappwebview_macos
|
||||||
import flutter_local_authentication
|
import flutter_local_authentication
|
||||||
|
import flutter_secure_storage_macos
|
||||||
import in_app_review
|
import in_app_review
|
||||||
import package_info
|
import package_info
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
|
@ -25,6 +26,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin"))
|
DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin"))
|
||||||
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
|
||||||
FlutterLocalAuthenticationPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalAuthenticationPlugin"))
|
FlutterLocalAuthenticationPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalAuthenticationPlugin"))
|
||||||
|
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||||
InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin"))
|
InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin"))
|
||||||
FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin"))
|
FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin"))
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
|
|
|
@ -106,6 +106,7 @@ dependencies:
|
||||||
url: https://github.com/cake-tech/bitcoin_base
|
url: https://github.com/cake-tech/bitcoin_base
|
||||||
ref: cake-update-v3
|
ref: cake-update-v3
|
||||||
ledger_flutter: ^1.0.1
|
ledger_flutter: ^1.0.1
|
||||||
|
hashlib: 1.12.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
@ -4,7 +4,6 @@ import 'utils/secret_key.dart';
|
||||||
import 'utils/utils.dart';
|
import 'utils/utils.dart';
|
||||||
|
|
||||||
const baseConfigPath = 'tool/.secrets-config.json';
|
const baseConfigPath = 'tool/.secrets-config.json';
|
||||||
const coreConfigPath = 'tool/.core-secrets-config.json';
|
|
||||||
const evmChainsConfigPath = 'tool/.evm-secrets-config.json';
|
const evmChainsConfigPath = 'tool/.evm-secrets-config.json';
|
||||||
const solanaConfigPath = 'tool/.solana-secrets-config.json';
|
const solanaConfigPath = 'tool/.solana-secrets-config.json';
|
||||||
const nanoConfigPath = 'tool/.nano-secrets-config.json';
|
const nanoConfigPath = 'tool/.nano-secrets-config.json';
|
||||||
|
@ -38,7 +37,6 @@ Future<void> generateSecretsConfig(List<String> args) async {
|
||||||
});
|
});
|
||||||
|
|
||||||
final baseConfigFile = File(baseConfigPath);
|
final baseConfigFile = File(baseConfigPath);
|
||||||
final coreConfigFile = File(coreConfigPath);
|
|
||||||
final evmChainsConfigFile = File(evmChainsConfigPath);
|
final evmChainsConfigFile = File(evmChainsConfigPath);
|
||||||
final solanaConfigFile = File(solanaConfigPath);
|
final solanaConfigFile = File(solanaConfigPath);
|
||||||
final nanoConfigFile = File(nanoConfigPath);
|
final nanoConfigFile = File(nanoConfigPath);
|
||||||
|
@ -64,7 +62,6 @@ Future<void> generateSecretsConfig(List<String> args) async {
|
||||||
|
|
||||||
await writeConfig(baseConfigFile, SecretKey.base, existingSecrets: secrets);
|
await writeConfig(baseConfigFile, SecretKey.base, existingSecrets: secrets);
|
||||||
|
|
||||||
await writeConfig(coreConfigFile, SecretKey.coreSecrets);
|
|
||||||
await writeConfig(evmChainsConfigFile, SecretKey.evmChainsSecrets);
|
await writeConfig(evmChainsConfigFile, SecretKey.evmChainsSecrets);
|
||||||
await writeConfig(solanaConfigFile, SecretKey.solanaSecrets);
|
await writeConfig(solanaConfigFile, SecretKey.solanaSecrets);
|
||||||
await writeConfig(nanoConfigFile, SecretKey.nanoSecrets);
|
await writeConfig(nanoConfigFile, SecretKey.nanoSecrets);
|
||||||
|
|
|
@ -45,8 +45,6 @@ class SecretKey {
|
||||||
SecretKey('authorization', () => ''),
|
SecretKey('authorization', () => ''),
|
||||||
];
|
];
|
||||||
|
|
||||||
static final coreSecrets = [];
|
|
||||||
|
|
||||||
static final evmChainsSecrets = [
|
static final evmChainsSecrets = [
|
||||||
SecretKey('etherScanApiKey', () => ''),
|
SecretKey('etherScanApiKey', () => ''),
|
||||||
SecretKey('polygonScanApiKey', () => ''),
|
SecretKey('polygonScanApiKey', () => ''),
|
||||||
|
|
Loading…
Reference in a new issue