diff --git a/analysis_options.yaml b/analysis_options.yaml index a217eaf08..52f1e3224 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,5 +1,3 @@ -include: package:pedantic/analysis_options.yaml - analyzer: strong-mode: implicit-casts: false diff --git a/cw_monero/ios/Classes/monero_api.cpp b/cw_monero/ios/Classes/monero_api.cpp index 8d471b22c..6393eaea9 100644 --- a/cw_monero/ios/Classes/monero_api.cpp +++ b/cw_monero/ios/Classes/monero_api.cpp @@ -180,7 +180,7 @@ extern "C" void change_current_wallet(Monero::Wallet *wallet) { m_wallet = wallet; - // m_listener = nullptr; + m_listener = nullptr; if (wallet != nullptr) @@ -553,7 +553,7 @@ extern "C" if (m_listener != nullptr) { - free(m_listener); + // free(m_listener); } m_listener = new MoneroWalletListener(); diff --git a/cw_monero/lib/wallet.dart b/cw_monero/lib/wallet.dart index e1206ff83..c42cd3523 100644 --- a/cw_monero/lib/wallet.dart +++ b/cw_monero/lib/wallet.dart @@ -254,12 +254,12 @@ class SyncListner { onNewBlock(syncHeight, left, ptc); } - if (newTransactionExist && onNewTransaction != null) { - onNewTransaction(); + if (newTransactionExist) { + onNewTransaction?.call(); } - if (needToRefresh && onNeedToRefresh != null) { - onNeedToRefresh(); + if (needToRefresh) { + onNeedToRefresh?.call(); } }); } diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 451d74c1f..63e247dc4 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -3,6 +3,13 @@ PODS: - Flutter - MTBBarcodeScanner - SwiftProtobuf + - connectivity (0.0.1): + - Flutter + - Reachability + - connectivity_for_web (0.1.0): + - Flutter + - connectivity_macos (0.0.1): + - Flutter - cw_monero (0.0.2): - cw_monero/Boost (= 0.0.2) - cw_monero/lmdb (= 0.0.2) @@ -40,6 +47,7 @@ PODS: - Flutter - path_provider_macos (0.0.1): - Flutter + - Reachability (3.2) - share (0.0.1): - Flutter - shared_preferences (0.0.1): @@ -62,6 +70,9 @@ PODS: DEPENDENCIES: - barcode_scan (from `.symlinks/plugins/barcode_scan/ios`) + - connectivity (from `.symlinks/plugins/connectivity/ios`) + - connectivity_for_web (from `.symlinks/plugins/connectivity_for_web/ios`) + - connectivity_macos (from `.symlinks/plugins/connectivity_macos/ios`) - cw_monero (from `.symlinks/plugins/cw_monero/ios`) - devicelocale (from `.symlinks/plugins/devicelocale/ios`) - esys_flutter_share (from `.symlinks/plugins/esys_flutter_share/ios`) @@ -86,11 +97,18 @@ DEPENDENCIES: SPEC REPOS: trunk: - MTBBarcodeScanner + - Reachability - SwiftProtobuf EXTERNAL SOURCES: barcode_scan: :path: ".symlinks/plugins/barcode_scan/ios" + connectivity: + :path: ".symlinks/plugins/connectivity/ios" + connectivity_for_web: + :path: ".symlinks/plugins/connectivity_for_web/ios" + connectivity_macos: + :path: ".symlinks/plugins/connectivity_macos/ios" cw_monero: :path: ".symlinks/plugins/cw_monero/ios" devicelocale: @@ -134,6 +152,9 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479 + connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467 + connectivity_for_web: 2b8584556930d4bd490d82b836bcf45067ce345b + connectivity_macos: e2e9731b6b22dda39eb1b128f6969d574460e191 cw_monero: 2e1f79929880cc2293b5bc1b25e28152e4d84649 devicelocale: feebbe5e7a30adb8c4f83185de1b50ff19b44f00 esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4 @@ -146,6 +167,7 @@ SPEC CHECKSUMS: path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4 path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0 + Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 share: 0b2c3e82132f5888bccca3351c504d0003b3b410 shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d shared_preferences_linux: afefbfe8d921e207f01ede8b60373d9e3b566b78 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 822dd4355..bd4100941 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -275,8 +275,10 @@ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", "${PODS_ROOT}/../Flutter/Flutter.framework", "${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework", + "${BUILT_PRODUCTS_DIR}/Reachability/Reachability.framework", "${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework", "${BUILT_PRODUCTS_DIR}/barcode_scan/barcode_scan.framework", + "${BUILT_PRODUCTS_DIR}/connectivity/connectivity.framework", "${BUILT_PRODUCTS_DIR}/cw_monero/cw_monero.framework", "${BUILT_PRODUCTS_DIR}/devicelocale/devicelocale.framework", "${BUILT_PRODUCTS_DIR}/esys_flutter_share/esys_flutter_share.framework", @@ -293,8 +295,10 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reachability.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/barcode_scan.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cw_monero.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/devicelocale.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/esys_flutter_share.framework", diff --git a/lib/bitcoin/bitcoin_transaction_history.dart b/lib/bitcoin/bitcoin_transaction_history.dart index 4a18d18c1..81ed01fe7 100644 --- a/lib/bitcoin/bitcoin_transaction_history.dart +++ b/lib/bitcoin/bitcoin_transaction_history.dart @@ -9,8 +9,6 @@ import 'package:cake_wallet/bitcoin/electrum.dart'; part 'bitcoin_transaction_history.g.dart'; -// TODO: Think about another transaction store for bitcoin transaction history.. - const _transactionsHistoryFileName = 'transactions.json'; class BitcoinTransactionHistory = BitcoinTransactionHistoryBase diff --git a/lib/bitcoin/bitcoin_wallet.dart b/lib/bitcoin/bitcoin_wallet.dart index 4fc46f8fa..fe6cbf184 100644 --- a/lib/bitcoin/bitcoin_wallet.dart +++ b/lib/bitcoin/bitcoin_wallet.dart @@ -1,39 +1,29 @@ import 'dart:async'; -import 'dart:typed_data'; import 'dart:convert'; +import 'package:mobx/mobx.dart'; +import 'package:bip39/bip39.dart' as bip39; +import 'package:flutter/foundation.dart'; +import 'package:rxdart/rxdart.dart'; +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; import 'package:cake_wallet/bitcoin/bitcoin_transaction_credentials.dart'; -import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart'; import 'package:cake_wallet/bitcoin/bitcoin_transaction_no_inputs_exception.dart'; import 'package:cake_wallet/bitcoin/bitcoin_transaction_wrong_balance_exception.dart'; import 'package:cake_wallet/bitcoin/bitcoin_unspent.dart'; import 'package:cake_wallet/bitcoin/bitcoin_wallet_keys.dart'; +import 'package:cake_wallet/bitcoin/electrum.dart'; import 'package:cake_wallet/bitcoin/pending_bitcoin_transaction.dart'; import 'package:cake_wallet/bitcoin/script_hash.dart'; import 'package:cake_wallet/bitcoin/utils.dart'; import 'package:cake_wallet/src/domain/bitcoin/bitcoin_amount_format.dart'; -import 'package:cake_wallet/src/domain/common/crypto_currency.dart'; import 'package:cake_wallet/src/domain/common/sync_status.dart'; -import 'package:cake_wallet/src/domain/common/transaction_direction.dart'; import 'package:cake_wallet/src/domain/common/transaction_priority.dart'; -import 'package:cw_monero/transaction_history.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:mobx/mobx.dart'; -import 'package:bip39/bip39.dart' as bip39; -import 'package:flutter/foundation.dart'; -import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; -import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData; -import 'package:cake_wallet/src/domain/common/wallet_type.dart'; +import 'package:cake_wallet/src/domain/common/wallet_info.dart'; import 'package:cake_wallet/bitcoin/bitcoin_transaction_history.dart'; import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart'; import 'package:cake_wallet/bitcoin/file.dart'; -import 'package:cake_wallet/bitcoin/electrum.dart'; import 'package:cake_wallet/bitcoin/bitcoin_balance.dart'; import 'package:cake_wallet/src/domain/common/node.dart'; import 'package:cake_wallet/core/wallet_base.dart'; -import 'package:rxdart/rxdart.dart'; -import 'package:hex/hex.dart'; -import 'package:cake_wallet/di.dart'; -import 'package:shared_preferences/shared_preferences.dart'; part 'bitcoin_wallet.g.dart'; @@ -44,8 +34,8 @@ abstract class BitcoinWalletBase extends WalletBase with Store { {@required this.eclient, @required this.path, @required String password, - @required this.name, - List initialAddresses, + @required WalletInfo walletInfo, + @required List initialAddresses, int accountIndex = 0, this.transactionHistory, this.mnemonic, @@ -60,9 +50,7 @@ abstract class BitcoinWalletBase extends WalletBase with Store { syncStatus = NotConnectedSyncStatus(), _password = password, _accountIndex = accountIndex, - _addressesKeys = {} { - type = WalletType.bitcoin; - currency = CryptoCurrency.btc; + super(walletInfo) { _scripthashesUpdateSubject = {}; } @@ -114,7 +102,6 @@ abstract class BitcoinWalletBase extends WalletBase with Store { return BitcoinWallet._internal( eclient: eclient, path: walletPath, - name: name, mnemonic: mnemonic, password: password, accountIndex: accountIndex, @@ -130,9 +117,6 @@ abstract class BitcoinWalletBase extends WalletBase with Store { final ElectrumClient eclient; final String mnemonic; - @override - String name; - @override @observable String address; @@ -147,8 +131,6 @@ abstract class BitcoinWalletBase extends WalletBase with Store { ObservableList addresses; - Map _addressesKeys; - List get scriptHashes => addresses.map((addr) => scriptHash(addr.address)).toList(); @@ -161,8 +143,8 @@ abstract class BitcoinWalletBase extends WalletBase with Store { BitcoinWalletKeys get keys => BitcoinWalletKeys( wif: hd.wif, privateKey: hd.privKey, publicKey: hd.pubKey); + final String _password; int _accountIndex; - String _password; Map> _scripthashesUpdateSubject; Future init() async { diff --git a/lib/bitcoin/file.dart b/lib/bitcoin/file.dart index ddb6c23cb..53f8f06b0 100644 --- a/lib/bitcoin/file.dart +++ b/lib/bitcoin/file.dart @@ -1,5 +1,4 @@ import 'dart:io'; -import 'dart:convert'; import 'package:cake_wallet/bitcoin/key.dart'; import 'package:encrypt/encrypt.dart' as encrypt; import 'package:flutter/foundation.dart'; @@ -28,14 +27,13 @@ Future writeData( f.writeAsStringSync(encrypted); } -Future read( - {@required String path, @required String password}) async { +Future read({@required String path, @required String password}) async { final file = File(path); if (!file.existsSync()) { file.createSync(); } - + final encrypted = file.readAsStringSync(); return decode(password: password, data: encrypted); diff --git a/lib/core/auth_service.dart b/lib/core/auth_service.dart index f66f44a83..557800fd6 100644 --- a/lib/core/auth_service.dart +++ b/lib/core/auth_service.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:shared_preferences/shared_preferences.dart'; diff --git a/lib/core/wallet_base.dart b/lib/core/wallet_base.dart index 3d0246251..b5f8e27cc 100644 --- a/lib/core/wallet_base.dart +++ b/lib/core/wallet_base.dart @@ -1,4 +1,5 @@ import 'package:flutter/foundation.dart'; +import 'package:cake_wallet/src/domain/common/wallet_info.dart'; import 'package:cake_wallet/core/pending_transaction.dart'; import 'package:cake_wallet/core/transaction_history.dart'; import 'package:cake_wallet/src/domain/common/transaction_priority.dart'; @@ -7,18 +8,43 @@ import 'package:cake_wallet/src/domain/common/sync_status.dart'; import 'package:cake_wallet/src/domain/common/node.dart'; import 'package:cake_wallet/src/domain/common/wallet_type.dart'; +// FIXME: Move me. +CryptoCurrency currencyForWalletType(WalletType type) { + switch (type) { + case WalletType.bitcoin: + return CryptoCurrency.btc; + case WalletType.monero: + return CryptoCurrency.xmr; + default: + return null; + } +} + abstract class WalletBase { - WalletType type; + WalletBase(this.walletInfo); - CryptoCurrency currency; + static String idFor(String name, WalletType type) => + walletTypeToString(type).toLowerCase() + '_' + name; - String get name; + WalletInfo walletInfo; - String address; + WalletType get type => walletInfo.type; - BalaceType balance; + CryptoCurrency get currency => currencyForWalletType(type); - SyncStatus syncStatus; + String get id => walletInfo.id; + + String get name => walletInfo.name; + + String get address; + + set address(String address); + + BalaceType get balance; + + SyncStatus get syncStatus; + + set syncStatus(SyncStatus status); String get seed; @@ -26,8 +52,6 @@ abstract class WalletBase { TransactionHistoryBase transactionHistory; - String get id => walletTypeToString(type).toLowerCase() + '_' + name; - Future connectToNode({@required Node node}); Future startSync(); diff --git a/lib/core/wallet_creation_service.dart b/lib/core/wallet_creation_service.dart index 5c5cb43df..ce14fa1e2 100644 --- a/lib/core/wallet_creation_service.dart +++ b/lib/core/wallet_creation_service.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/di.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -32,17 +33,7 @@ class WalletCreationService { void changeWalletType({@required WalletType type}) { this.type = type; - - switch (type) { - case WalletType.monero: - _service = MoneroWalletService(); - break; - case WalletType.bitcoin: - _service = BitcoinWalletService(); - break; - default: - break; - } + _service = getIt.get(param1: type); } Future create(WalletCredentials credentials) async { diff --git a/lib/core/wallet_credentials.dart b/lib/core/wallet_credentials.dart index ee7b1ef58..7dc93f848 100644 --- a/lib/core/wallet_credentials.dart +++ b/lib/core/wallet_credentials.dart @@ -1,6 +1,10 @@ +import 'package:cake_wallet/src/domain/common/wallet_info.dart'; + abstract class WalletCredentials { - WalletCredentials({this.name, this.password}); + WalletCredentials({this.name, this.password, this.height}); final String name; + final int height; String password; -} \ No newline at end of file + WalletInfo walletInfo; +} diff --git a/lib/di.dart b/lib/di.dart index 5453010ca..523f80aed 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -1,7 +1,11 @@ +import 'package:cake_wallet/bitcoin/bitcoin_wallet_service.dart'; import 'package:cake_wallet/core/contact_service.dart'; +import 'package:cake_wallet/core/wallet_service.dart'; +import 'package:cake_wallet/monero/monero_wallet_service.dart'; import 'package:cake_wallet/src/domain/common/contact.dart'; import 'package:cake_wallet/src/domain/common/node.dart'; import 'package:cake_wallet/src/domain/exchange/trade.dart'; +// import 'package:cake_wallet/src/domain/services/wallet_service.dart'; import 'package:cake_wallet/src/screens/contact/contact_list_page.dart'; import 'package:cake_wallet/src/screens/contact/contact_page.dart'; import 'package:cake_wallet/src/screens/exchange_trade/exchange_confirm_page.dart'; @@ -367,6 +371,22 @@ Future setup( getIt.registerFactory( () => ExchangeTemplatePage(getIt.get())); + + getIt.registerFactory(() => MoneroWalletService(walletInfoSource)); + + getIt.registerFactory(() => BitcoinWalletService()); + + getIt.registerFactoryParam( + (WalletType param1, __) { + switch (param1) { + case WalletType.monero: + return getIt.get(); + case WalletType.bitcoin: + return getIt.get(); + default: + return null; + } + }); } void setupThemeChangerStore(ThemeChanger themeChanger) { diff --git a/lib/main.dart b/lib/main.dart index 8f4080a30..19e4fe1b8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -251,6 +251,17 @@ class MaterialAppWithTheme extends StatelessWidget { _settingsStore.isDarkTheme ? Brightness.light : Brightness.dark; final statusBarIconBrightness = _settingsStore.isDarkTheme ? Brightness.light : Brightness.dark; + final authenticationStore = getIt.get(); + String initialRoute; + + switch (authenticationStore.state) { + case AuthenticationState.denied: + initialRoute = Routes.welcome; + break; + default: + initialRoute = Routes.login; + break; + } SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( statusBarColor: statusBarColor, @@ -258,7 +269,7 @@ class MaterialAppWithTheme extends StatelessWidget { statusBarIconBrightness: statusBarIconBrightness)); return Root( - authenticationStore: getIt.get(), + authenticationStore: authenticationStore, child: MaterialApp( navigatorKey: navigatorKey, debugShowCheckedModeBanner: false, @@ -286,8 +297,7 @@ class MaterialAppWithTheme extends StatelessWidget { nodes: nodes, trades: trades, transactionDescriptions: transactionDescriptions), - initialRoute: Routes.login, // FIXME: get initial route! - // home: Container(color: Colors.blue), + initialRoute: initialRoute, )); } } diff --git a/lib/monero/monero_wallet.dart b/lib/monero/monero_wallet.dart index d7e8a4d26..bf01d0ec7 100644 --- a/lib/monero/monero_wallet.dart +++ b/lib/monero/monero_wallet.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/src/domain/common/wallet_info.dart'; import 'package:cake_wallet/src/domain/monero/monero_transaction_creation_credentials.dart'; import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; @@ -9,36 +10,29 @@ import 'package:cake_wallet/monero/monero_transaction_history.dart'; import 'package:cake_wallet/monero/monero_subaddress_list.dart'; import 'package:cake_wallet/monero/monero_account_list.dart'; import 'package:cake_wallet/core/wallet_base.dart'; -import 'package:cake_wallet/core/transaction_history.dart'; -import 'package:cake_wallet/src/domain/common/crypto_currency.dart'; -import 'package:cake_wallet/src/domain/common/wallet_type.dart'; import 'package:cake_wallet/src/domain/common/sync_status.dart'; import 'package:cake_wallet/src/domain/monero/account.dart'; -import 'package:cake_wallet/src/domain/monero/account_list.dart'; import 'package:cake_wallet/src/domain/monero/subaddress.dart'; import 'package:cake_wallet/src/domain/common/node.dart'; import 'package:cake_wallet/core/pending_transaction.dart'; import 'package:cake_wallet/src/domain/common/transaction_priority.dart'; -import 'package:cake_wallet/src/domain/common/calculate_fiat_amount.dart' - as cfa; part 'monero_wallet.g.dart'; +const moneroBlockSize = 1000; + class MoneroWallet = MoneroWalletBase with _$MoneroWallet; abstract class MoneroWalletBase extends WalletBase with Store { - MoneroWalletBase({String filename, this.isRecovery = false}) + MoneroWalletBase({String filename, WalletInfo walletInfo}) : transactionHistory = MoneroTransactionHistory(), accountList = MoneroAccountList(), - subaddressList = MoneroSubaddressList() { + subaddressList = MoneroSubaddressList(), + super(walletInfo) { _filename = filename; balance = MoneroBalance( fullBalance: monero_wallet.getFullBalance(accountIndex: 0), unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0)); - currency = CryptoCurrency.xmr; - type = WalletType.monero; - _rct = reaction( - (_) => syncStatus, (SyncStatus status) => print(status.toString())); _onAccountChangeReaction = reaction((_) => account, (Account account) { subaddressList.update(accountIndex: account.id); subaddress = subaddressList.subaddresses.first; @@ -46,8 +40,6 @@ abstract class MoneroWalletBase extends WalletBase with Store { }); } - ReactionDisposer _rct; - @override final MoneroTransactionHistory transactionHistory; @@ -57,15 +49,17 @@ abstract class MoneroWalletBase extends WalletBase with Store { @observable Subaddress subaddress; + @override @observable SyncStatus syncStatus; @override - String get name => _filename.split('/').last; + @observable + String address; @override @observable - String address; + MoneroBalance balance; @override String get seed => monero_wallet.getSeed(); @@ -81,8 +75,6 @@ abstract class MoneroWalletBase extends WalletBase with Store { final MoneroAccountList accountList; - bool isRecovery; - String _filename; SyncListner _listener; ReactionDisposer _onAccountChangeReaction; @@ -107,8 +99,6 @@ abstract class MoneroWalletBase extends WalletBase with Store { @override Future connectToNode({@required Node node}) async { - final node = Node(uri: 'xmr-node-uk.cakewallet.com:18081'); - try { syncStatus = ConnectingSyncStatus(); await monero_wallet.setupNode( @@ -127,6 +117,10 @@ abstract class MoneroWalletBase extends WalletBase with Store { @override Future startSync() async { + try { + _setInitialHeight(); + } catch (_) {} + try { syncStatus = StartingSyncStatus(); monero_wallet.startRefresh(); @@ -180,25 +174,18 @@ abstract class MoneroWalletBase extends WalletBase with Store { @override Future save() async { -// if (_isSaving) { -// return; -// } - - try { -// _isSaving = true; - await monero_wallet.store(); -// _isSaving = false; - } catch (e) { - print(e); -// _isSaving = false; - rethrow; - } + await monero_wallet.store(); } Future getNodeHeight() async => monero_wallet.getNodeHeight(); Future isConnected() async => monero_wallet.isConnected(); + Future setAsRecovered() async { + walletInfo.isRecovery = false; + await walletInfo.save(); + } + void _setListeners() { _listener?.stop(); _listener = monero_wallet.setListeners( @@ -206,6 +193,41 @@ abstract class MoneroWalletBase extends WalletBase with Store { _listener.start(); } + void _setInitialHeight() { + if (walletInfo.isRecovery) { + return; + } + + final currentHeight = getCurrentHeight(); + print('currentHeight $currentHeight'); + + if (currentHeight <= 1) { + final height = _getHeightByDate(walletInfo.date); + monero_wallet.setRecoveringFromSeed(isRecovery: true); + monero_wallet.setRefreshFromBlockHeight(height: height); + } + } + + int _getHeightDistance(DateTime date) { + final distance = + DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch; + final daysTmp = (distance / 86400).round(); + final days = daysTmp < 1 ? 1 : daysTmp; + + return days * 1000; + } + + int _getHeightByDate(DateTime date) { + final nodeHeight = monero_wallet.getNodeHeightSync(); + final heightDistance = _getHeightDistance(date); + + if (nodeHeight <= 0) { + return 0; + } + + return nodeHeight - heightDistance; + } + void _askForUpdateBalance() { final fullBalance = _getFullBalance(); final unlockedBalance = _getUnlockedBalance(); @@ -236,13 +258,17 @@ abstract class MoneroWalletBase extends WalletBase with Store { syncStatus = SyncedSyncStatus(); - if (isRecovery) { + if (walletInfo.isRecovery) { _askForUpdateTransactionHistory(); } -// if (isRecovery && (nodeHeight - currentHeight < moneroBlockSize)) { -// await setAsRecovered(); -// } + final currentHeight = getCurrentHeight(); + final nodeHeight = monero_wallet.getNodeHeightSync(); + + if (walletInfo.isRecovery && + (nodeHeight - currentHeight < moneroBlockSize)) { + await setAsRecovered(); + } await save(); } diff --git a/lib/monero/monero_wallet_service.dart b/lib/monero/monero_wallet_service.dart index c6e2d20af..637646f2a 100644 --- a/lib/monero/monero_wallet_service.dart +++ b/lib/monero/monero_wallet_service.dart @@ -1,12 +1,14 @@ import 'dart:io'; - +import 'package:cake_wallet/core/wallet_base.dart'; +import 'package:hive/hive.dart'; +import 'package:cw_monero/wallet_manager.dart' as monero_wallet_manager; +import 'package:cw_monero/wallet.dart' as monero_wallet; import 'package:cake_wallet/monero/monero_wallet.dart'; import 'package:cake_wallet/core/wallet_credentials.dart'; import 'package:cake_wallet/core/wallet_service.dart'; import 'package:cake_wallet/src/domain/common/pathForWallet.dart'; +import 'package:cake_wallet/src/domain/common/wallet_info.dart'; import 'package:cake_wallet/src/domain/common/wallet_type.dart'; -import 'package:cw_monero/wallet_manager.dart' as monero_wallet_manager; -import 'package:cw_monero/wallet.dart' as monero_wallet; class MoneroNewWalletCredentials extends WalletCredentials { MoneroNewWalletCredentials({String name, String password, this.language}) @@ -17,11 +19,10 @@ class MoneroNewWalletCredentials extends WalletCredentials { class MoneroRestoreWalletFromSeedCredentials extends WalletCredentials { MoneroRestoreWalletFromSeedCredentials( - {String name, String password, this.mnemonic, this.height}) - : super(name: name, password: password); + {String name, String password, int height, this.mnemonic}) + : super(name: name, password: password, height: height); final String mnemonic; - final int height; } class MoneroRestoreWalletFromKeysCredentials extends WalletCredentials { @@ -32,32 +33,35 @@ class MoneroRestoreWalletFromKeysCredentials extends WalletCredentials { this.address, this.viewKey, this.spendKey, - this.height}) - : super(name: name, password: password); + int height}) + : super(name: name, password: password, height: height); final String language; final String address; final String viewKey; final String spendKey; - final int height; } class MoneroWalletService extends WalletService< MoneroNewWalletCredentials, MoneroRestoreWalletFromSeedCredentials, MoneroRestoreWalletFromKeysCredentials> { + MoneroWalletService(this.walletInfoSource); + + final Box walletInfoSource; + @override Future create(MoneroNewWalletCredentials credentials) async { try { final path = await pathForWallet(name: credentials.name, type: WalletType.monero); - await monero_wallet_manager.createWallet( path: path, password: credentials.password, language: credentials.language); - - final wallet = MoneroWallet(filename: monero_wallet.getFilename()); + final wallet = MoneroWallet( + filename: monero_wallet.getFilename(), + walletInfo: credentials.walletInfo); await wallet.init(); return wallet; @@ -84,8 +88,16 @@ class MoneroWalletService extends WalletService< Future openWallet(String name, String password) async { try { final path = await pathForWallet(name: name, type: WalletType.monero); + final file = File(path); + final stat = await file.stat(); + print(stat.changed); + print(stat.modified); + print(stat.accessed); monero_wallet_manager.openWallet(path: path, password: password); - final wallet = MoneroWallet(filename: monero_wallet.getFilename()); + final walletInfo = walletInfoSource.values.firstWhere( + (info) => info.id == WalletBase.idFor(name, WalletType.monero)); + final wallet = MoneroWallet( + filename: monero_wallet.getFilename(), walletInfo: walletInfo); await wallet.init(); return wallet; @@ -107,7 +119,6 @@ class MoneroWalletService extends WalletService< try { final path = await pathForWallet(name: credentials.name, type: WalletType.monero); - await monero_wallet_manager.restoreFromKeys( path: path, password: credentials.password, @@ -116,8 +127,9 @@ class MoneroWalletService extends WalletService< address: credentials.address, viewKey: credentials.viewKey, spendKey: credentials.spendKey); - - final wallet = MoneroWallet(filename: monero_wallet.getFilename()); + final wallet = MoneroWallet( + filename: monero_wallet.getFilename(), + walletInfo: credentials.walletInfo); await wallet.init(); return wallet; @@ -134,14 +146,14 @@ class MoneroWalletService extends WalletService< try { final path = await pathForWallet(name: credentials.name, type: WalletType.monero); - await monero_wallet_manager.restoreFromSeed( path: path, password: credentials.password, seed: credentials.mnemonic, restoreHeight: credentials.height); - - final wallet = MoneroWallet(filename: monero_wallet.getFilename()); + final wallet = MoneroWallet( + filename: monero_wallet.getFilename(), + walletInfo: credentials.walletInfo); await wallet.init(); return wallet; diff --git a/lib/reactions/bootstrap.dart b/lib/reactions/bootstrap.dart index fd41c6ed5..a92ed01b8 100644 --- a/lib/reactions/bootstrap.dart +++ b/lib/reactions/bootstrap.dart @@ -1,28 +1,20 @@ import 'dart:async'; - -import 'package:cake_wallet/core/key_service.dart'; -import 'package:cake_wallet/router.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/domain/common/sync_status.dart'; -import 'package:cake_wallet/src/screens/auth/auth_page.dart'; -import 'package:cake_wallet/src/screens/dashboard/dashboard_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/widgets.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/di.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:cake_wallet/bitcoin/bitcoin_wallet_service.dart'; -import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart'; -import 'package:cake_wallet/monero/monero_wallet_service.dart'; +import 'package:connectivity/connectivity.dart'; +import 'package:cake_wallet/core/key_service.dart'; +import 'package:cake_wallet/router.dart'; +import 'package:cake_wallet/src/domain/common/sync_status.dart'; import 'package:cake_wallet/core/wallet_base.dart'; import 'package:cake_wallet/core/wallet_service.dart'; import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/authentication_store.dart'; import 'package:cake_wallet/src/domain/common/wallet_type.dart'; -import 'package:cake_wallet/src/domain/common/secret_store_key.dart'; -import 'package:cake_wallet/src/domain/common/encrypt.dart'; import 'package:cake_wallet/src/domain/services/fiat_convertation_service.dart'; import 'package:cake_wallet/src/domain/common/fiat_currency.dart'; import 'package:cake_wallet/store/dashboard/fiat_convertation_store.dart'; @@ -36,19 +28,7 @@ Future loadCurrentWallet() async { final type = deserializeFromInt(typeRaw); final password = await getIt.get().getWalletPassword(walletName: name); - - WalletService _service; - switch (type) { - case WalletType.monero: - _service = MoneroWalletService(); - break; - case WalletType.bitcoin: - _service = BitcoinWalletService(); - break; - default: - break; - } - + final _service = getIt.get(param1: type); final wallet = await _service.openWallet(name, password); appStore.wallet = wallet; } @@ -79,9 +59,6 @@ Future bootstrap( if (state == AuthenticationState.installed) { await loadCurrentWallet(); - } - - if (state == AuthenticationState.installed) { await navigatorKey.currentState .pushAndRemoveUntil(createLoginRoute(), (_) => false); } @@ -101,16 +78,31 @@ Future bootstrap( reaction((_) => getIt.get().wallet, (WalletBase wallet) async { _onWalletSyncStatusChangeReaction?.reaction?.dispose(); _reconnectionTimer?.cancel(); - _onWalletSyncStatusChangeReaction = reaction( - (_) => wallet.syncStatus is ConnectedSyncStatus, - (Object _) async => await wallet.startSync()); + _onWalletSyncStatusChangeReaction = + reaction((_) => wallet.syncStatus, (SyncStatus status) async { + if (status is ConnectedSyncStatus) { + await wallet.startSync(); + } + }); _reconnectionTimer = Timer.periodic(Duration(seconds: 5), (_) async { + final connectivityResult = await (Connectivity().checkConnectivity()); + + if (connectivityResult == ConnectivityResult.none) { + wallet.syncStatus = FailedSyncStatus(); + return; + } + if (wallet.syncStatus is LostConnectionSyncStatus || wallet.syncStatus is FailedSyncStatus) { try { - await wallet.connectToNode( - node: settingsStore.getCurrentNode(wallet.type)); + final alive = + await settingsStore.getCurrentNode(wallet.type).requestNode(); + + if (alive) { + await wallet.connectToNode( + node: settingsStore.getCurrentNode(wallet.type)); + } } catch (_) {} } }); diff --git a/lib/src/domain/common/fs_migration.dart b/lib/src/domain/common/fs_migration.dart index db17cd134..0d848aeb9 100644 --- a/lib/src/domain/common/fs_migration.dart +++ b/lib/src/domain/common/fs_migration.dart @@ -82,28 +82,28 @@ Future migrate_wallets({Directory appDocDir}) async { Future migrate_ios_wallet_info( {@required Directory appDocDir, @required Box walletsInfo}) async { - final walletsDir = Directory('${appDocDir.path}/wallets'); - final moneroWalletsDir = Directory('${walletsDir.path}/monero'); + // final walletsDir = Directory('${appDocDir.path}/wallets'); + // final moneroWalletsDir = Directory('${walletsDir.path}/monero'); - moneroWalletsDir.listSync().forEach((item) async { - try { - if (item is Directory) { - final name = item.path.split('/').last; - final configFile = File('${item.path}/$name.json'); - final config = - json.decode(configFile.readAsStringSync()) as Map; - final isRecovery = config["isRecovery"] as bool ?? false; - final id = - walletTypeToString(WalletType.monero).toLowerCase() + '_' + name; - final walletInfo = - WalletInfo(id: id, name: name, isRecovery: isRecovery); + // moneroWalletsDir.listSync().forEach((item) async { + // try { + // if (item is Directory) { + // final name = item.path.split('/').last; + // final configFile = File('${item.path}/$name.json'); + // final config = + // json.decode(configFile.readAsStringSync()) as Map; + // final isRecovery = config["isRecovery"] as bool ?? false; + // final id = + // walletTypeToString(WalletType.monero).toLowerCase() + '_' + name; + // final walletInfo = + // WalletInfo(id: id, name: name, isRecovery: isRecovery); - await walletsInfo.add(walletInfo); - } - } catch (e) { - print(e.toString()); - } - }); + // await walletsInfo.add(walletInfo); + // } + // } catch (e) { + // print(e.toString()); + // } + // }); } Future migrate_ios_trades_list( diff --git a/lib/src/domain/common/wallet_info.dart b/lib/src/domain/common/wallet_info.dart index fcc5eac14..c9682f103 100644 --- a/lib/src/domain/common/wallet_info.dart +++ b/lib/src/domain/common/wallet_info.dart @@ -1,12 +1,26 @@ -import 'package:cake_wallet/src/domain/common/wallet_type.dart'; +import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; +import 'package:cake_wallet/src/domain/common/wallet_type.dart'; part 'wallet_info.g.dart'; @HiveType(typeId: 4) class WalletInfo extends HiveObject { - WalletInfo( - {this.id, this.name, this.type, this.isRecovery, this.restoreHeight}); + WalletInfo(this.id, this.name, this.type, this.isRecovery, this.restoreHeight, + this.timestamp, this.dirPath, this.path); + + factory WalletInfo.external( + {@required String id, + @required String name, + @required WalletType type, + @required bool isRecovery, + @required int restoreHeight, + @required DateTime date, + @required String dirPath, + @required String path}) { + return WalletInfo(id, name, type, isRecovery, restoreHeight, + date.millisecondsSinceEpoch ?? 0, dirPath, path); + } static const boxName = 'WalletInfo'; @@ -24,4 +38,15 @@ class WalletInfo extends HiveObject { @HiveField(4) int restoreHeight; + + @HiveField(5) + int timestamp; + + @HiveField(6) + String dirPath; + + @HiveField(7) + String path; + + DateTime get date => DateTime.fromMillisecondsSinceEpoch(timestamp); } diff --git a/lib/src/domain/monero/monero_wallet.dart b/lib/src/domain/monero/monero_wallet.dart index 66e46a6fc..1eacfc1c9 100644 --- a/lib/src/domain/monero/monero_wallet.dart +++ b/lib/src/domain/monero/monero_wallet.dart @@ -47,18 +47,19 @@ class MoneroWallet extends Wallet { String name, bool isRecovery = false, int restoreHeight = 0}) async { - const type = WalletType.monero; - final id = walletTypeToString(type).toLowerCase() + '_' + name; - final walletInfo = WalletInfo( - id: id, - name: name, - type: type, - isRecovery: isRecovery, - restoreHeight: restoreHeight); - await walletInfoSource.add(walletInfo); + // const type = WalletType.monero; + // final id = walletTypeToString(type).toLowerCase() + '_' + name; + // final walletInfo = WalletInfo( + // id: id, + // name: name, + // type: type, + // isRecovery: isRecovery, + // restoreHeight: restoreHeight); + // await walletInfoSource.add(walletInfo); - return await configured( - walletInfo: walletInfo, walletInfoSource: walletInfoSource); + // return await configured( + // walletInfo: walletInfo, walletInfoSource: walletInfoSource); + return null; } static Future load( diff --git a/lib/src/domain/monero/monero_wallets_manager.dart b/lib/src/domain/monero/monero_wallets_manager.dart index b75fb3091..71f8406c2 100644 --- a/lib/src/domain/monero/monero_wallets_manager.dart +++ b/lib/src/domain/monero/monero_wallets_manager.dart @@ -12,8 +12,6 @@ import 'package:cake_wallet/src/domain/common/wallet.dart'; import 'package:cake_wallet/src/domain/monero/monero_wallet.dart'; import 'package:cake_wallet/src/domain/common/wallet_description.dart'; - - class MoneroWalletsManager extends WalletsManager { MoneroWalletsManager({@required this.walletInfoSource}); @@ -27,7 +25,8 @@ class MoneroWalletsManager extends WalletsManager { const isRecovery = false; final path = await pathForWallet(name: name, type: WalletType.monero); - await monero_wallet_manager.createWallet(path: path, password: password, language: language); + await monero_wallet_manager.createWallet( + path: path, password: password, language: language); final wallet = await MoneroWallet.createdWallet( walletInfoSource: walletInfoSource, diff --git a/lib/src/reactions/set_reactions.dart b/lib/src/reactions/set_reactions.dart index b95671e95..1584dc89f 100644 --- a/lib/src/reactions/set_reactions.dart +++ b/lib/src/reactions/set_reactions.dart @@ -65,18 +65,18 @@ void onSyncStatusChange( {SyncStore syncStore, WalletStore walletStore, SettingsStore settingsStore}) { - _onSyncStatusChangeDisposer?.call(); + // _onSyncStatusChangeDisposer?.call(); - reaction((_) => syncStore.status, (SyncStatus status) async { - if (status is ConnectedSyncStatus) { - await walletStore.startSync(); - } + // reaction((_) => syncStore.status, (SyncStatus status) async { + // if (status is ConnectedSyncStatus) { + // await walletStore.startSync(); + // } - // Reconnect to the node if the app is not started sync after 30 seconds - if (status is StartingSyncStatus) { - startReconnectionObserver(syncStore: syncStore, walletStore: walletStore); - } - }); + // // Reconnect to the node if the app is not started sync after 30 seconds + // if (status is StartingSyncStatus) { + // startReconnectionObserver(syncStore: syncStore, walletStore: walletStore); + // } + // }); } void startReconnectionObserver({SyncStore syncStore, WalletStore walletStore}) { diff --git a/lib/view_model/exchange/exchange_trade_view_model.dart b/lib/view_model/exchange/exchange_trade_view_model.dart index f773cab37..414a40ebe 100644 --- a/lib/view_model/exchange/exchange_trade_view_model.dart +++ b/lib/view_model/exchange/exchange_trade_view_model.dart @@ -14,7 +14,8 @@ import 'package:cake_wallet/generated/i18n.dart'; part 'exchange_trade_view_model.g.dart'; -class ExchangeTradeViewModel = ExchangeTradeViewModelBase with _$ExchangeTradeViewModel; +class ExchangeTradeViewModel = ExchangeTradeViewModelBase + with _$ExchangeTradeViewModel; abstract class ExchangeTradeViewModelBase with Store { ExchangeTradeViewModelBase({this.wallet, this.trades, this.tradesStore}) { @@ -38,17 +39,11 @@ abstract class ExchangeTradeViewModelBase with Store { items = ObservableList(); items.addAll([ ExchangeTradeItem( - title: S.current.id, - data: '${trade.id}', - isCopied: true), + title: S.current.id, data: '${trade.id}', isCopied: true), ExchangeTradeItem( - title: S.current.amount, - data: '${trade.amount}', - isCopied: false), + title: S.current.amount, data: '${trade.amount}', isCopied: false), ExchangeTradeItem( - title: S.current.status, - data: '${trade.state}', - isCopied: false), + title: S.current.status, data: '${trade.state}', isCopied: false), ExchangeTradeItem( title: S.current.widgets_address + ':', data: trade.inputAddress, @@ -90,4 +85,4 @@ abstract class ExchangeTradeViewModelBase with Store { print(e.toString()); } } -} \ No newline at end of file +} diff --git a/lib/view_model/node_list/node_list_view_model.dart b/lib/view_model/node_list/node_list_view_model.dart index 4a68d23aa..2807443b1 100644 --- a/lib/view_model/node_list/node_list_view_model.dart +++ b/lib/view_model/node_list/node_list_view_model.dart @@ -1,5 +1,3 @@ -import 'package:cake_wallet/utils/item_cell.dart'; -import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/core/wallet_base.dart'; @@ -10,6 +8,7 @@ import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/src/domain/common/default_settings_migration.dart'; import 'package:cake_wallet/src/domain/common/wallet_type.dart'; import 'package:cake_wallet/utils/mobx.dart'; +import 'package:cake_wallet/utils/item_cell.dart'; part 'node_list_view_model.g.dart'; diff --git a/lib/view_model/send_view_model.dart b/lib/view_model/send_view_model.dart index 0942c7841..5c06ad9c4 100644 --- a/lib/view_model/send_view_model.dart +++ b/lib/view_model/send_view_model.dart @@ -1,3 +1,6 @@ +import 'package:flutter/foundation.dart'; +import 'package:intl/intl.dart'; +import 'package:mobx/mobx.dart'; import 'package:cake_wallet/core/address_validator.dart'; import 'package:cake_wallet/core/amount_validator.dart'; import 'package:cake_wallet/core/template_validator.dart'; @@ -5,7 +8,6 @@ import 'package:cake_wallet/core/validator.dart'; import 'package:cake_wallet/core/wallet_base.dart'; import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart'; import 'package:cake_wallet/monero/monero_wallet.dart'; -import 'package:cake_wallet/src/domain/common/balance.dart'; import 'package:cake_wallet/src/domain/common/balance_display_mode.dart'; import 'package:cake_wallet/src/domain/common/calculate_estimated_fee.dart'; import 'package:cake_wallet/src/domain/common/crypto_currency.dart'; @@ -14,15 +16,6 @@ import 'package:cake_wallet/src/domain/common/sync_status.dart'; import 'package:cake_wallet/src/domain/common/transaction_priority.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/templates/send_template_store.dart'; -import 'package:flutter/foundation.dart'; -import 'package:intl/intl.dart'; -import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/monero/monero_wallet_service.dart'; -import 'package:cake_wallet/bitcoin/bitcoin_wallet_creation_credentials.dart'; -import 'package:cake_wallet/core/wallet_creation_service.dart'; -import 'package:cake_wallet/core/wallet_credentials.dart'; -import 'package:cake_wallet/src/domain/common/wallet_type.dart'; -import 'package:cake_wallet/view_model/wallet_creation_vm.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/domain/common/openalias_record.dart'; import 'package:cake_wallet/store/dashboard/fiat_convertation_store.dart'; @@ -51,12 +44,8 @@ class SendingFailed extends SendViewModelState { class SendViewModel = SendViewModelBase with _$SendViewModel; abstract class SendViewModelBase with Store { - SendViewModelBase( - this._wallet, - this._settingsStore, - this._fiatConvertationStore, - this.sendTemplateStore) { - + SendViewModelBase(this._wallet, this._settingsStore, + this._fiatConvertationStore, this.sendTemplateStore) { state = InitialSendViewModelState(); _cryptoNumberFormat = NumberFormat()..maximumFractionDigits = 12; @@ -116,9 +105,10 @@ abstract class SendViewModelBase with Store { double get price => _fiatConvertationStore.price; @computed - ObservableList