diff --git a/cw_monero/ios/Classes/monero_api.cpp b/cw_monero/ios/Classes/monero_api.cpp index 757f05d8..8d471b22 100644 --- a/cw_monero/ios/Classes/monero_api.cpp +++ b/cw_monero/ios/Classes/monero_api.cpp @@ -14,6 +14,7 @@ using namespace std::chrono_literals; extern "C" { #endif + const uint64_t MONERO_BLOCK_SIZE = 1000; struct Utf8Box { @@ -173,6 +174,8 @@ extern "C" Monero::Subaddress *m_subaddress; Monero::SubaddressAccount *m_account; uint64_t m_last_known_wallet_height; + uint64_t m_cached_syncing_blockchain_height = 0; + void change_current_wallet(Monero::Wallet *wallet) { @@ -481,20 +484,34 @@ extern "C" return committed; } + uint64_t get_node_height_or_update(uint64_t base_eight) + { + if (m_cached_syncing_blockchain_height < base_eight) { + m_cached_syncing_blockchain_height = base_eight; + } + + return m_cached_syncing_blockchain_height; + } + uint64_t get_syncing_height() { if (m_listener == nullptr) { return 0; } - uint64_t _height = m_listener->height(); + uint64_t height = m_listener->height(); + uint64_t node_height = get_node_height_or_update(height); + + if (height <= 1 || node_height <= 0) { + return 0; + } - if (_height != m_last_known_wallet_height) + if (height != m_last_known_wallet_height) { - m_last_known_wallet_height = _height; + m_last_known_wallet_height = height; } - return _height; + return height; } uint64_t is_needed_to_refresh() @@ -504,8 +521,9 @@ extern "C" } bool should_refresh = m_listener->isNeedToRefresh(); + uint64_t node_height = get_node_height_or_update(m_last_known_wallet_height); - if (should_refresh) + if (should_refresh || (node_height - m_last_known_wallet_height < MONERO_BLOCK_SIZE)) { m_listener->resetNeedToRefresh(); } diff --git a/cw_monero/lib/wallet.dart b/cw_monero/lib/wallet.dart index 74d50006..e1206ff8 100644 --- a/cw_monero/lib/wallet.dart +++ b/cw_monero/lib/wallet.dart @@ -209,41 +209,74 @@ String getSecretSpendKey() => String getPublicSpendKey() => convertUTF8ToString(pointer: getPublicSpendKeyNative()); -Timer _updateSyncInfoTimer; +class SyncListner { + SyncListner({this.onNewBlock, this.onNeedToRefresh, this.onNewTransaction}); -int _lastKnownBlockHeight = 0; + void Function(int, int, double) onNewBlock; + void Function() onNeedToRefresh; + void Function() onNewTransaction; -void setListeners(Future Function(int) onNewBlock, - Future Function() onNeedToRefresh, Future Function() onNewTransaction) { - if (_updateSyncInfoTimer != null) { - _updateSyncInfoTimer.cancel(); + Timer _updateSyncInfoTimer; + int _cachedBlockchainHeight = 0; + int _lastKnownBlockHeight = 0; + int _initialSyncHeight = 0; + + Future getNodeHeightOrUpdate(int baseHeight) async { + if (_cachedBlockchainHeight < baseHeight) { + _cachedBlockchainHeight = await getNodeHeight(); + } + + return _cachedBlockchainHeight; } - _updateSyncInfoTimer = Timer.periodic(Duration(milliseconds: 200), (_) async { - final syncHeight = getSyncingHeight(); - final needToRefresh = isNeededToRefresh(); - final newTransactionExist = isNewTransactionExist(); + void start() { + _cachedBlockchainHeight = 0; + _lastKnownBlockHeight = 0; + _initialSyncHeight = 0; + _updateSyncInfoTimer ??= + Timer.periodic(Duration(milliseconds: 200), (_) async { + final syncHeight = getSyncingHeight(); + final needToRefresh = isNeededToRefresh(); + final newTransactionExist = isNewTransactionExist(); + final bchHeight = await getNodeHeightOrUpdate(syncHeight); + + if (_lastKnownBlockHeight != syncHeight && syncHeight != null) { + if (_initialSyncHeight <= 0) { + _initialSyncHeight = syncHeight; + } + + _lastKnownBlockHeight = syncHeight; + final line = bchHeight - _initialSyncHeight; + final diff = line - (bchHeight - syncHeight); + final ptc = diff <= 0 ? 0.0 : diff / line; + final left = bchHeight - syncHeight; + // 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents; + onNewBlock(syncHeight, left, ptc); + } + + if (newTransactionExist && onNewTransaction != null) { + onNewTransaction(); + } + + if (needToRefresh && onNeedToRefresh != null) { + onNeedToRefresh(); + } + }); + } - if (_lastKnownBlockHeight != syncHeight && syncHeight != null) { - _lastKnownBlockHeight = syncHeight; - await onNewBlock(syncHeight); - } + void stop() => _updateSyncInfoTimer?.cancel(); +} - if (newTransactionExist && onNewTransaction != null) { - await onNewTransaction(); - } +SyncListner setListeners(void Function(int, int, double) onNewBlock, + void Function() onNeedToRefresh, void Function() onNewTransaction) { + final listener = SyncListner( + onNewBlock: onNewBlock, + onNeedToRefresh: onNeedToRefresh, + onNewTransaction: onNewTransaction); - if (needToRefresh && onNeedToRefresh != null) { - await onNeedToRefresh(); - } - }); setListenerNative(); -} -void closeListeners() { - if (_updateSyncInfoTimer != null) { - _updateSyncInfoTimer.cancel(); - } + return listener; } void onStartup() => onStartupNative(); diff --git a/lib/core/auth_service.dart b/lib/core/auth_service.dart new file mode 100644 index 00000000..6589f45c --- /dev/null +++ b/lib/core/auth_service.dart @@ -0,0 +1,21 @@ +import 'package:flutter/foundation.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/core/setup_pin_code_state.dart'; + +part 'auth_service.g.dart'; + +class AuthService = AuthServiceBase with _$AuthService; + +abstract class AuthServiceBase with Store { + @observable + SetupPinCodeState setupPinCodeState; + + Future setupPinCode({@required String pin}) async {} + + Future authenticate({@required String pin}) async { + return false; + } + + void resetSetupPinCodeState() => + setupPinCodeState = InitialSetupPinCodeState(); +} diff --git a/lib/core/bitcoin_transaction_history.dart b/lib/core/bitcoin_transaction_history.dart new file mode 100644 index 00000000..fb5aaaa2 --- /dev/null +++ b/lib/core/bitcoin_transaction_history.dart @@ -0,0 +1,121 @@ +import 'dart:convert'; +import 'package:flutter/foundation.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/core/transaction_history.dart'; +import 'package:cake_wallet/core/bitcoin_wallet.dart'; +import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart'; +import 'package:cake_wallet/bitcoin/electrum.dart'; +import 'package:cake_wallet/src/domain/common/transaction_info.dart'; +import 'package:cake_wallet/bitcoin/file.dart'; + +part 'bitcoin_transaction_history.g.dart'; + +// TODO: Think about another transaction store for bitcoin transaction history.. + +const _transactionsHistoryFileName = 'transactions.json'; + +class BitcoinTransactionHistory = BitcoinTransactionHistoryBase + with _$BitcoinTransactionHistory; + +abstract class BitcoinTransactionHistoryBase + extends TranasctionHistoryBase with Store { + BitcoinTransactionHistoryBase( + {this.eclient, String dirPath, @required String password}) + : path = '$dirPath/$_transactionsHistoryFileName', + _password = password, + _height = 0; + + BitcoinWallet wallet; + final ElectrumClient eclient; + final String path; + final String _password; + int _height; + + Future init() async { + // TODO: throw exeption if wallet is null; + final info = await _read(); + _height = (info['height'] as int) ?? _height; + transactions = info['transactions'] as List; + } + + @override + Future update() async { + await super.update(); + _updateHeight(); + } + + @override + Future> fetchTransactions() async { + final addresses = wallet.getAddresses(); + final histories = + addresses.map((address) => eclient.getHistory(address: address)); + final _historiesWithDetails = await Future.wait(histories) + .then((histories) => histories + .map((h) => h.where((tx) => (tx['height'] as int) > _height)) + .expand((i) => i) + .toList()) + .then((histories) => histories.map((tx) => fetchTransactionInfo( + hash: tx['tx_hash'] as String, height: tx['height'] as int))); + final historiesWithDetails = await Future.wait(_historiesWithDetails); + + return historiesWithDetails + .map((info) => BitcoinTransactionInfo.fromHexAndHeader( + info['raw'] as String, info['header'] as Map, + addresses: addresses)) + .toList(); + } + + Future> fetchTransactionInfo( + {@required String hash, @required int height}) async { + final rawFetching = eclient.getTransactionRaw(hash: hash); + final headerFetching = eclient.getHeader(height: height); + final result = await Future.wait([rawFetching, headerFetching]); + final raw = result.first as String; + final header = result[1] as Map; + + return {'raw': raw, 'header': header}; + } + + Future add(List transactions) async { + this.transactions.addAll(transactions); + await save(); + } + + Future addOne(BitcoinTransactionInfo tx) async { + transactions.add(tx); + await save(); + } + + Future save() async => writeData( + path: path, + password: _password, + data: json.encode({'height': _height, 'transactions': transactions})); + + Future> _read() async { + try { + final content = await read(path: path, password: _password); + final jsoned = json.decode(content) as Map; + final height = jsoned['height'] as int; + final transactions = (jsoned['transactions'] as List) + .map((dynamic row) { + if (row is Map) { + return BitcoinTransactionInfo.fromJson(row); + } + + return null; + }) + .where((el) => el != null) + .toList(); + + return {'transactions': transactions, 'height': height}; + } catch (_) { + return {'transactions': [], 'height': 0}; + } + } + + void _updateHeight() { + final newHeight = transactions.fold( + 0, (int acc, val) => val.height > acc ? val.height : acc); + _height = newHeight > _height ? newHeight : _height; + } +} diff --git a/lib/core/bitcoin_wallet.dart b/lib/core/bitcoin_wallet.dart new file mode 100644 index 00000000..2bf57b96 --- /dev/null +++ b/lib/core/bitcoin_wallet.dart @@ -0,0 +1,149 @@ +import 'dart:convert'; +import 'dart:typed_data'; +import 'package:cake_wallet/core/bitcoin_transaction_history.dart'; +import 'package:cake_wallet/core/transaction_history.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/bitcoin/file.dart'; +import 'package:cake_wallet/src/domain/common/pathForWallet.dart'; +import 'package:cake_wallet/src/domain/common/wallet_type.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 'wallet_base.dart'; + +part 'bitcoin_wallet.g.dart'; + +/* TODO: Save balance to a wallet file. + Load balance from the wallet file in `init` method. +*/ + +class BitcoinWallet = BitcoinWalletBase with _$BitcoinWallet; + +abstract class BitcoinWalletBase extends WalletBase with Store { + static Future load( + {@required String name, @required String password}) async { + final walletDirPath = + await pathForWalletDir(name: name, type: WalletType.bitcoin); + final walletPath = '$walletDirPath/$name'; + final walletJSONRaw = await read(path: walletPath, password: password); + final jsoned = json.decode(walletJSONRaw) as Map; + final mnemonic = jsoned['mnemonic'] as String; + final accountIndex = + (jsoned['account_index'] == "null" || jsoned['account_index'] == null) + ? 0 + : int.parse(jsoned['account_index'] as String); + + return BitcoinWallet.build( + mnemonic: mnemonic, + password: password, + name: name, + accountIndex: accountIndex); + } + + factory BitcoinWalletBase.build( + {@required String mnemonic, + @required String password, + @required String name, + @required String dirPath, + int accountIndex = 0}) { + final walletPath = '$dirPath/$name'; + final eclient = ElectrumClient(); + final history = BitcoinTransactionHistory( + eclient: eclient, dirPath: dirPath, password: password); + + return BitcoinWallet._internal( + eclient: eclient, + path: walletPath, + mnemonic: mnemonic, + password: password, + accountIndex: accountIndex, + transactionHistory: history); + } + + BitcoinWalletBase._internal( + {@required this.eclient, + @required this.path, + @required String password, + int accountIndex = 0, + this.transactionHistory, + this.mnemonic}) { + hd = bitcoin.HDWallet.fromSeed(bip39.mnemonicToSeed(mnemonic), + network: bitcoin.bitcoin); + _password = password; + _accountIndex = accountIndex; + } + + final BitcoinTransactionHistory transactionHistory; + final String path; + bitcoin.HDWallet hd; + final ElectrumClient eclient; + final String mnemonic; + int _accountIndex; + String _password; + + @override + String get name => path.split('/').last ?? ''; + + @override + String get filename => hd.address; + + String get xpub => hd.base58; + + List getAddresses() => _accountIndex == 0 + ? [address] + : List.generate( + _accountIndex, (i) => _getAddress(hd: hd, index: i)); + + Future init() async { + await transactionHistory.init(); + } + + Future newAddress() async { + _accountIndex += 1; + final address = _getAddress(hd: hd, index: _accountIndex); + await save(); + + return address; + } + + @override + Future startSync() async {} + + @override + Future connectToNode({@required Node node}) async {} + + @override + Future createTransaction(Object credentials) async {} + + @override + Future save() async => await write( + path: path, + password: _password, + obj: {'mnemonic': mnemonic, 'account_index': _accountIndex.toString()}); + + String _getAddress({bitcoin.HDWallet hd, int index}) => bitcoin + .P2PKH( + data: PaymentData( + pubkey: Uint8List.fromList(hd.derive(index).pubKey.codeUnits))) + .data + .address; + + Future> _fetchBalances() async { + final balances = await Future.wait( + getAddresses().map((address) => eclient.getBalance(address: address))); + final balance = balances.fold({}, (Map acc, val) { + acc['confirmed'] = + (val['confirmed'] as int ?? 0) + (acc['confirmed'] ?? 0); + acc['unconfirmed'] = + (val['unconfirmed'] as int ?? 0) + (acc['unconfirmed'] ?? 0); + + return acc; + }); + + return balance; + } +} diff --git a/lib/core/bitcoin_wallet_list_service.dart b/lib/core/bitcoin_wallet_list_service.dart new file mode 100644 index 00000000..5bd19e9a --- /dev/null +++ b/lib/core/bitcoin_wallet_list_service.dart @@ -0,0 +1,103 @@ +import 'dart:io'; +import 'package:bip39/bip39.dart' as bip39; +import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart'; +import 'package:cake_wallet/core/wallet_credentials.dart'; +import 'package:cake_wallet/core/wallet_list_service.dart'; +import 'package:cake_wallet/core/bitcoin_wallet.dart'; +import 'package:cake_wallet/src/domain/common/pathForWallet.dart'; +import 'package:cake_wallet/src/domain/common/wallet.dart'; +import 'package:cake_wallet/src/domain/common/wallet_description.dart'; +import 'package:cake_wallet/src/domain/common/wallet_type.dart'; +import 'package:cake_wallet/src/domain/common/wallets_manager.dart'; +/* +* +* BitcoinRestoreWalletFromSeedCredentials +* +* */ + +class BitcoinNewWalletCredentials extends WalletCredentials {} + +/* +* +* BitcoinRestoreWalletFromSeedCredentials +* +* */ + +class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials { + const BitcoinRestoreWalletFromSeedCredentials( + {String name, String password, this.mnemonic}) + : super(name: name, password: password); + + final String mnemonic; +} + +/* +* +* BitcoinRestoreWalletFromWIFCredentials +* +* */ + +class BitcoinRestoreWalletFromWIFCredentials extends WalletCredentials { + const BitcoinRestoreWalletFromWIFCredentials( + {String name, String password, this.wif}) + : super(name: name, password: password); + + final String wif; +} + +/* +* +* BitcoinWalletListService +* +* */ + +class BitcoinWalletListService extends WalletListService< + BitcoinNewWalletCredentials, + BitcoinRestoreWalletFromSeedCredentials, + BitcoinRestoreWalletFromWIFCredentials> { + @override + Future create(BitcoinNewWalletCredentials credentials) async { + final wallet = await BitcoinWalletBase.build( + mnemonic: bip39.generateMnemonic(), + password: credentials.password, + name: credentials.name); + await wallet.save(); + + return wallet; + } + + @override + Future isWalletExit(String name) async => + File(await pathForWallet(name: name, type: WalletType.bitcoin)) + .existsSync(); + + @override + Future openWallet(String name, String password) async { + // TODO: implement openWallet + throw UnimplementedError(); + } + + Future remove(String wallet) { + // TODO: implement remove + throw UnimplementedError(); + } + + @override + Future restoreFromKeys( + BitcoinRestoreWalletFromWIFCredentials credentials) async { + // TODO: implement restoreFromKeys + throw UnimplementedError(); + } + + @override + Future restoreFromSeed( + BitcoinRestoreWalletFromSeedCredentials credentials) async { + final wallet = await BitcoinWalletBase.build( + name: credentials.name, + password: credentials.password, + mnemonic: credentials.mnemonic); + await wallet.save(); + + return wallet; + } +} diff --git a/lib/core/monero_balance.dart b/lib/core/monero_balance.dart new file mode 100644 index 00000000..6496e347 --- /dev/null +++ b/lib/core/monero_balance.dart @@ -0,0 +1,20 @@ +import 'package:flutter/foundation.dart'; +import 'package:cake_wallet/src/domain/monero/monero_amount_format.dart'; + +class MoneroBalance { + MoneroBalance({@required this.fullBalance, @required this.unlockedBalance}) + : formattedFullBalance = moneroAmountToString(amount: fullBalance), + formattedUnlockedBalance = + moneroAmountToString(amount: unlockedBalance); + + MoneroBalance.fromString( + {@required this.formattedFullBalance, + @required this.formattedUnlockedBalance}) + : fullBalance = moneroParseAmount(amount: formattedFullBalance), + unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance); + + final int fullBalance; + final int unlockedBalance; + final String formattedFullBalance; + final String formattedUnlockedBalance; +} \ No newline at end of file diff --git a/lib/core/monero_transaction_history.dart b/lib/core/monero_transaction_history.dart new file mode 100644 index 00000000..03b48324 --- /dev/null +++ b/lib/core/monero_transaction_history.dart @@ -0,0 +1,27 @@ +import 'dart:core'; +import 'package:mobx/mobx.dart'; +import 'package:cw_monero/transaction_history.dart' + as monero_transaction_history; +import 'package:cake_wallet/core/transaction_history.dart'; +import 'package:cake_wallet/src/domain/common/transaction_info.dart'; +import 'package:cake_wallet/src/domain/monero/monero_transaction_info.dart'; + +part 'monero_transaction_history.g.dart'; + +List _getAllTransactions(dynamic _) => + monero_transaction_history + .getAllTransations() + .map((row) => MoneroTransactionInfo.fromRow(row)) + .toList(); + +class MoneroTransactionHistory = MoneroTransactionHistoryBase + with _$MoneroTransactionHistory; + +abstract class MoneroTransactionHistoryBase + extends TranasctionHistoryBase with Store { + @override + Future> fetchTransactions() async { + monero_transaction_history.refreshTransactions(); + return _getAllTransactions(null); + } +} diff --git a/lib/core/monero_wallet.dart b/lib/core/monero_wallet.dart new file mode 100644 index 00000000..1b3fcd5a --- /dev/null +++ b/lib/core/monero_wallet.dart @@ -0,0 +1,186 @@ +import 'package:cake_wallet/core/monero_balance.dart'; +import 'package:cake_wallet/core/monero_transaction_history.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/monero/subaddress_list.dart'; +import 'package:cw_monero/wallet.dart'; +import 'package:flutter/foundation.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/src/domain/common/node.dart'; +import 'package:cw_monero/wallet.dart' as monero_wallet; +import 'wallet_base.dart'; + +part 'monero_wallet.g.dart'; + +class MoneroWallet = MoneroWalletBase with _$MoneroWallet; + +abstract class MoneroWalletBase extends WalletBase with Store { + MoneroWalletBase({String filename, this.isRecovery = false}) { + transactionHistory = MoneroTransactionHistory(); + _filename = filename; + accountList = AccountList(); + subaddressList = SubaddressList(); + balance = MoneroBalance( + fullBalance: monero_wallet.getFullBalance(accountIndex: 0), + unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0)); + } + + MoneroTransactionHistory transactionHistory; + SubaddressList subaddressList; + AccountList accountList; + + @observable + Account account; + + @observable + Subaddress subaddress; + + @observable + SyncStatus syncStatus; + + @override + String get name => filename.split('/').last; + + @override + String get filename => _filename; + + String _filename; + + bool isRecovery; + + SyncListner _listner; + + void init() { + account = accountList.getAll().first; + subaddressList.refresh(accountIndex: account.id ?? 0); + subaddress = subaddressList.getAll().first; + balance = MoneroBalance( + fullBalance: monero_wallet.getFullBalance(accountIndex: account.id), + unlockedBalance: + monero_wallet.getFullBalance(accountIndex: account.id)); + _setListeners(); + } + + void close() { + _listner?.stop(); + } + + @override + Future connectToNode({@required Node node}) async { + try { + syncStatus = ConnectingSyncStatus(); + await monero_wallet.setupNode( + address: node.uri, + login: node.login, + password: node.password, + useSSL: false, + // FIXME: hardcoded value + isLightWallet: false); // FIXME: hardcoded value + syncStatus = ConnectedSyncStatus(); + } catch (e) { + syncStatus = FailedSyncStatus(); + print(e); + } + } + + @override + Future startSync() async { + try { + syncStatus = StartingSyncStatus(); + monero_wallet.startRefresh(); + } catch (e) { + syncStatus = FailedSyncStatus(); + print(e); + rethrow; + } + } + + @override + Future createTransaction(Object credentials) async { +// final _credentials = credentials as MoneroTransactionCreationCredentials; +// final transactionDescription = await transaction_history.createTransaction( +// address: _credentials.address, +// paymentId: _credentials.paymentId, +// amount: _credentials.amount, +// priorityRaw: _credentials.priority.serialize(), +// accountIndex: _account.value.id); +// +// return PendingTransaction.fromTransactionDescription( +// transactionDescription); + } + + @override + Future save() async { +// if (_isSaving) { +// return; +// } + + try { +// _isSaving = true; + await monero_wallet.store(); +// _isSaving = false; + } catch (e) { + print(e); +// _isSaving = false; + rethrow; + } + } + + Future getNodeHeight() async => monero_wallet.getNodeHeight(); + + Future isConnected() async => monero_wallet.isConnected(); + + void _setListeners() { + _listner?.stop(); + _listner = monero_wallet.setListeners( + _onNewBlock, _onNeedToRefresh, _onNewTransaction); + } + + void _askForUpdateBalance() { + final fullBalance = _getFullBalance(); + final unlockedBalance = _getUnlockedBalance(); + + if (balance.fullBalance != fullBalance || + balance.unlockedBalance != unlockedBalance) { + balance = MoneroBalance( + fullBalance: fullBalance, unlockedBalance: unlockedBalance); + } + } + + void _askForUpdateTransactionHistory() => + null; // await getHistory().update(); + + int _getFullBalance() => + monero_wallet.getFullBalance(accountIndex: account.id); + + int _getUnlockedBalance() => + monero_wallet.getUnlockedBalance(accountIndex: account.id); + + void _onNewBlock(int height, int blocksLeft, double ptc) => + syncStatus = SyncingSyncStatus(blocksLeft, ptc); + + Future _onNeedToRefresh() async { + if (syncStatus is FailedSyncStatus) { + return; + } + + syncStatus = SyncedSyncStatus(); + + if (isRecovery) { + _askForUpdateTransactionHistory(); + } + +// if (isRecovery && (nodeHeight - currentHeight < moneroBlockSize)) { +// await setAsRecovered(); +// } + + await save(); + } + + void _onNewTransaction() { + _askForUpdateBalance(); + _askForUpdateTransactionHistory(); + } +} diff --git a/lib/core/monero_wallet_list_service.dart b/lib/core/monero_wallet_list_service.dart new file mode 100644 index 00000000..c87cd75a --- /dev/null +++ b/lib/core/monero_wallet_list_service.dart @@ -0,0 +1,146 @@ +import 'package:cake_wallet/core/monero_wallet.dart'; +import 'package:cake_wallet/core/wallet_credentials.dart'; +import 'package:cake_wallet/core/wallet_list_service.dart'; +import 'package:cake_wallet/src/domain/common/pathForWallet.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 { + const MoneroNewWalletCredentials( + {String name, String password, this.language}) + : super(name: name, password: password); + + final String language; +} + +class MoneroRestoreWalletFromSeedCredentials extends WalletCredentials { + const MoneroRestoreWalletFromSeedCredentials( + {String name, String password, this.mnemonic, this.height}) + : super(name: name, password: password); + + final String mnemonic; + final int height; +} + +class MoneroRestoreWalletFromKeysCredentials extends WalletCredentials { + const MoneroRestoreWalletFromKeysCredentials( + {String name, + String password, + this.language, + this.address, + this.viewKey, + this.spendKey, + this.height}) + : super(name: name, password: password); + + final String language; + final String address; + final String viewKey; + final String spendKey; + final int height; +} + +class MoneroWalletListService extends WalletListService< + MoneroNewWalletCredentials, + MoneroRestoreWalletFromSeedCredentials, + MoneroRestoreWalletFromKeysCredentials> { + @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); + + return MoneroWallet(filename: monero_wallet.getFilename())..init(); + } catch (e) { + // TODO: Implement Exception fop wallet list service. + print('MoneroWalletsManager Error: $e'); + rethrow; + } + } + + @override + Future isWalletExit(String name) async { + try { + final path = await pathForWallet(name: name, type: WalletType.monero); + return monero_wallet_manager.isWalletExist(path: path); + } catch (e) { + // TODO: Implement Exception fop wallet list service. + print('MoneroWalletsManager Error: $e'); + rethrow; + } + } + + @override + Future openWallet(String name, String password) async { + try { + final path = await pathForWallet(name: name, type: WalletType.monero); + monero_wallet_manager.openWallet(path: path, password: password); + +// final id = walletTypeToString(WalletType.monero).toLowerCase() + '_' + name; +// final walletInfo = walletInfoSource.values +// .firstWhere((info) => info.id == id, orElse: () => null); + + return MoneroWallet(filename: monero_wallet.getFilename())..init(); + } catch (e) { + // TODO: Implement Exception fop wallet list service. + print('MoneroWalletsManager Error: $e'); + rethrow; + } + } + + Future remove(String wallet) async { + // TODO: implement remove + throw UnimplementedError(); + } + + @override + Future restoreFromKeys( + MoneroRestoreWalletFromKeysCredentials credentials) async { + try { + final path = + await pathForWallet(name: credentials.name, type: WalletType.monero); + + await monero_wallet_manager.restoreFromKeys( + path: path, + password: credentials.password, + language: credentials.language, + restoreHeight: credentials.height, + address: credentials.address, + viewKey: credentials.viewKey, + spendKey: credentials.spendKey); + + return MoneroWallet(filename: monero_wallet.getFilename())..init(); + } catch (e) { + // TODO: Implement Exception fop wallet list service. + print('MoneroWalletsManager Error: $e'); + rethrow; + } + } + + @override + Future restoreFromSeed( + MoneroRestoreWalletFromSeedCredentials credentials) async { + 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); + + return MoneroWallet(filename: monero_wallet.getFilename())..init(); + } catch (e) { + // TODO: Implement Exception fop wallet list service. + print('MoneroWalletsManager Error: $e'); + rethrow; + } + } +} diff --git a/lib/core/monero_wallet_store.dart b/lib/core/monero_wallet_store.dart deleted file mode 100644 index b0527d65..00000000 --- a/lib/core/monero_wallet_store.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'dart:async'; -import 'package:cake_wallet/src/domain/common/node.dart'; -import 'package:cake_wallet/src/domain/common/wallet_type.dart'; -import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/src/domain/common/wallet.dart'; -import 'package:cake_wallet/src/domain/monero/account.dart'; -import 'package:cake_wallet/src/domain/monero/monero_wallet.dart'; -import 'package:cake_wallet/src/domain/monero/subaddress.dart'; -import 'package:cake_wallet/src/domain/services/wallet_service.dart'; -import 'package:cake_wallet/src/domain/common/crypto_currency.dart'; -import 'package:cake_wallet/src/stores/settings/settings_store.dart'; -import 'package:cake_wallet/generated/i18n.dart'; - -part 'monero_wallet_store.g.dart'; - -class MoneroWalletStore = MoneroWalletStoreBase with _$MoneroWalletStore; - -abstract class MoneroWalletStoreBase with Store { - -} \ No newline at end of file diff --git a/lib/core/setup_pin_code_state.dart b/lib/core/setup_pin_code_state.dart new file mode 100644 index 00000000..1d254c97 --- /dev/null +++ b/lib/core/setup_pin_code_state.dart @@ -0,0 +1,15 @@ +import 'package:flutter/foundation.dart'; + +abstract class SetupPinCodeState {} + +class InitialSetupPinCodeState extends SetupPinCodeState {} + +class SetupPinCodeInProgress extends SetupPinCodeState {} + +class SetupPinCodeFinishedSuccessfully extends SetupPinCodeState {} + +class SetupPinCodeFinishedFailure extends SetupPinCodeState { + SetupPinCodeFinishedFailure({@required this.error}); + + final String error; +} \ No newline at end of file diff --git a/lib/core/sign_up_store.dart b/lib/core/sign_up_store.dart deleted file mode 100644 index 3040efc1..00000000 --- a/lib/core/sign_up_store.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/src/domain/common/wallet_type.dart'; - -part 'sign_up_store.g.dart'; - -class SignUpStore = SignUpStoreBase with _$SignUpStore; - - -abstract class SignUpStoreBase with Store { - -} \ No newline at end of file diff --git a/lib/core/transaction_history.dart b/lib/core/transaction_history.dart new file mode 100644 index 00000000..7a9e6c53 --- /dev/null +++ b/lib/core/transaction_history.dart @@ -0,0 +1,27 @@ +import 'package:mobx/mobx.dart'; + +abstract class TranasctionHistoryBase { + TranasctionHistoryBase() : _isUpdating = false; + + @observable + List transactions; + + bool _isUpdating; + + Future update() async { + if (_isUpdating) { + return; + } + + try { + _isUpdating = false; + transactions = await fetchTransactions(); + _isUpdating = true; + } catch (e) { + _isUpdating = false; + rethrow; + } + } + + Future> fetchTransactions(); +} \ No newline at end of file diff --git a/lib/core/wallet_base.dart b/lib/core/wallet_base.dart new file mode 100644 index 00000000..d1c14c70 --- /dev/null +++ b/lib/core/wallet_base.dart @@ -0,0 +1,20 @@ +import 'package:flutter/foundation.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/src/domain/common/node.dart'; + +abstract class WalletBase { + String get name; + + String get filename; + + @observable + String address; + + @observable + BalaceType balance; + + Future connectToNode({@required Node node}); + Future startSync(); + Future createTransaction(Object credentials); + Future save(); +} \ No newline at end of file diff --git a/lib/core/wallet_creation_service.dart b/lib/core/wallet_creation_service.dart new file mode 100644 index 00000000..123acd8d --- /dev/null +++ b/lib/core/wallet_creation_service.dart @@ -0,0 +1,63 @@ +import 'package:cake_wallet/core/wallet_creation_state.dart'; +import 'package:flutter/foundation.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/core/wallet_credentials.dart'; +import 'package:cake_wallet/core/bitcoin_wallet_list_service.dart'; +import 'package:cake_wallet/core/monero_wallet_list_service.dart'; +import 'package:cake_wallet/core/wallet_list_service.dart'; +import 'package:cake_wallet/src/domain/common/wallet_type.dart'; + +part 'wallet_creation_service.g.dart'; + +class WalletCreationService = WalletCreationServiceBase + with _$WalletCreationService; + +abstract class WalletCreationServiceBase with Store { + @observable + WalletCreationState state; + + WalletListService _service; + + void changeWalletType({@required WalletType type}) { + switch (type) { + case WalletType.monero: + _service = MoneroWalletListService(); + break; + case WalletType.bitcoin: + _service = BitcoinWalletListService(); + break; + default: + break; + } + } + + Future create(WalletCredentials credentials) async { + try { + state = WalletCreating(); + await _service.create(credentials); + state = WalletCreatedSuccessfully(); + } catch (e) { + state = WalletCreationFailure(error: e.toString()); + } + } + + Future restoreFromKeys(WalletCredentials credentials) async { + try { + state = WalletCreating(); + await _service.restoreFromKeys(credentials); + state = WalletCreatedSuccessfully(); + } catch (e) { + state = WalletCreationFailure(error: e.toString()); + } + } + + Future restoreFromSeed(WalletCredentials credentials) async { + try { + state = WalletCreating(); + await _service.restoreFromSeed(credentials); + state = WalletCreatedSuccessfully(); + } catch (e) { + state = WalletCreationFailure(error: e.toString()); + } + } +} diff --git a/lib/core/wallet_creation_state.dart b/lib/core/wallet_creation_state.dart new file mode 100644 index 00000000..c732a189 --- /dev/null +++ b/lib/core/wallet_creation_state.dart @@ -0,0 +1,13 @@ +import 'package:flutter/foundation.dart'; + +abstract class WalletCreationState {} + +class WalletCreating extends WalletCreationState {} + +class WalletCreatedSuccessfully extends WalletCreationState {} + +class WalletCreationFailure extends WalletCreationState { + WalletCreationFailure({@required this.error}); + + final String error; +} \ No newline at end of file diff --git a/lib/core/wallet_credentials.dart b/lib/core/wallet_credentials.dart new file mode 100644 index 00000000..e43acf9e --- /dev/null +++ b/lib/core/wallet_credentials.dart @@ -0,0 +1,6 @@ +abstract class WalletCredentials { + const WalletCredentials({this.name, this.password}); + + final String name; + final String password; +} \ No newline at end of file diff --git a/lib/core/wallet_list_service.dart b/lib/core/wallet_list_service.dart index cb0443ed..7015545a 100644 --- a/lib/core/wallet_list_service.dart +++ b/lib/core/wallet_list_service.dart @@ -1,24 +1,4 @@ -import 'package:cake_wallet/src/domain/common/wallet_type.dart'; -import 'package:flutter/foundation.dart'; - -/* -* -* WalletCredentials -* -* */ - -abstract class WalletCredentials { - const WalletCredentials({this.name, this.password}); - - final String name; - final String password; -} - -/* -* -* WalletListService -* -* */ +import 'package:cake_wallet/core/wallet_credentials.dart'; abstract class WalletListService { @@ -34,264 +14,3 @@ abstract class WalletListService remove(String wallet); } - -/* -* -* BitcoinRestoreWalletFromSeedCredentials -* -* */ - -class BitcoinNewWalletCredentials extends WalletCredentials {} - -/* -* -* BitcoinRestoreWalletFromSeedCredentials -* -* */ - -class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials { - const BitcoinRestoreWalletFromSeedCredentials( - {String name, String password, this.mnemonic}) - : super(name: name, password: password); - - final String mnemonic; -} - -/* -* -* BitcoinRestoreWalletFromWIFCredentials -* -* */ - -class BitcoinRestoreWalletFromWIFCredentials extends WalletCredentials { - const BitcoinRestoreWalletFromWIFCredentials( - {String name, String password, this.wif}) - : super(name: name, password: password); - - final String wif; -} - -/* -* -* BitcoinWalletListService -* -* */ - -class BitcoinWalletListService extends WalletListService< - BitcoinNewWalletCredentials, - BitcoinRestoreWalletFromSeedCredentials, - BitcoinRestoreWalletFromWIFCredentials> { - @override - Future create(BitcoinNewWalletCredentials credentials) async { - // TODO: implement create - throw UnimplementedError(); - } - - @override - Future isWalletExit(String name) async { - // TODO: implement isWalletExit - throw UnimplementedError(); - } - - @override - Future openWallet(String name, String password) async { - // TODO: implement openWallet - throw UnimplementedError(); - } - - Future remove(String wallet) { - // TODO: implement remove - throw UnimplementedError(); - } - - @override - Future restoreFromKeys( - BitcoinRestoreWalletFromWIFCredentials credentials) async { - // TODO: implement restoreFromKeys - throw UnimplementedError(); - } - - @override - Future restoreFromSeed( - BitcoinRestoreWalletFromSeedCredentials credentials) async { - // TODO: implement restoreFromSeed - throw UnimplementedError(); - } -} - -/* -* -* BitcoinWalletListService -* -* */ - -class MoneroWalletListService extends WalletListService< - BitcoinNewWalletCredentials, - BitcoinRestoreWalletFromSeedCredentials, - BitcoinRestoreWalletFromWIFCredentials> { - @override - Future create(BitcoinNewWalletCredentials credentials) async { - // TODO: implement create - throw UnimplementedError(); - } - - @override - Future isWalletExit(String name) async { - // TODO: implement isWalletExit - throw UnimplementedError(); - } - - @override - Future openWallet(String name, String password) async { - // TODO: implement openWallet - throw UnimplementedError(); - } - - Future remove(String wallet) { - // TODO: implement remove - throw UnimplementedError(); - } - - @override - Future restoreFromKeys( - BitcoinRestoreWalletFromWIFCredentials credentials) async { - // TODO: implement restoreFromKeys - throw UnimplementedError(); - } - - @override - Future restoreFromSeed( - BitcoinRestoreWalletFromSeedCredentials credentials) async { - // TODO: implement restoreFromSeed - throw UnimplementedError(); - } -} - -/* -* -* SignUpState -* -* */ - -abstract class WalletCreationState {} - -class WalletCreating extends WalletCreationState {} - -class WalletCreatedSuccessfully extends WalletCreationState {} - -class WalletCreationFailure extends WalletCreationState { - WalletCreationFailure({@required this.error}); - - final String error; -} - -/* -* -* WalletCreationService -* -* */ - -class WalletCreationService { - WalletCreationState state; - WalletListService _service; - - void changeWalletType({@required WalletType type}) { - switch (type) { - case WalletType.monero: - _service = MoneroWalletListService(); - break; - case WalletType.bitcoin: - _service = BitcoinWalletListService(); - break; - default: - break; - } - } - - Future create(WalletCredentials credentials) async { - try { - state = WalletCreating(); - await _service.create(credentials); - state = WalletCreatedSuccessfully(); - } catch (e) { - state = WalletCreationFailure(error: e.toString()); - } - } - - Future restoreFromKeys(WalletCredentials credentials) async { - try { - state = WalletCreating(); - await _service.create(credentials); - state = WalletCreatedSuccessfully(); - } catch (e) { - state = WalletCreationFailure(error: e.toString()); - } - } - - Future restoreFromSeed(WalletCredentials credentials) async { - try { - state = WalletCreating(); - await _service.create(credentials); - state = WalletCreatedSuccessfully(); - } catch (e) { - state = WalletCreationFailure(error: e.toString()); - } - } -} - -/* -* -* AuthService -* -* */ - -//abstract class LoginState {} - -abstract class SetupPinCodeState {} - -class InitialSetupPinCodeState extends SetupPinCodeState {} - -class SetupPinCodeInProgress extends SetupPinCodeState {} - -class SetupPinCodeFinishedSuccessfully extends SetupPinCodeState {} - -class SetupPinCodeFinishedFailure extends SetupPinCodeState { - SetupPinCodeFinishedFailure({@required this.error}); - - final String error; -} - -class AuthService { - SetupPinCodeState setupPinCodeState; - - Future setupPinCode({@required String pin}) async {} - - Future authenticate({@required String pin}) async { - return false; - } - - void resetSetupPinCodeState() => - setupPinCodeState = InitialSetupPinCodeState(); -} - -/* -* -* SignUpService -* -* */ - -class SignUpService { - SignUpService( - {@required this.walletCreationService, @required this.authService}); - - WalletCreationService walletCreationService; - AuthService authService; -} - -/* -* -* AppService -* -* */ - -class AppService {} diff --git a/lib/src/domain/common/sync_status.dart b/lib/src/domain/common/sync_status.dart index e83ce6f9..3e2eae4a 100644 --- a/lib/src/domain/common/sync_status.dart +++ b/lib/src/domain/common/sync_status.dart @@ -9,24 +9,19 @@ abstract class SyncStatus { } class SyncingSyncStatus extends SyncStatus { - SyncingSyncStatus(this.height, this.blockchainHeight, this.refreshHeight); + SyncingSyncStatus(this.blocksLeft, this.ptc); - final int height; - final int blockchainHeight; - final int refreshHeight; + final double ptc; + final int blocksLeft; @override - double progress() { - final line = blockchainHeight - refreshHeight; - final diff = line - (blockchainHeight - height); - return diff <= 0 ? 0.0 : diff / line; - } + double progress() => ptc; @override String title() => S.current.sync_status_syncronizing; @override - String toString() => '${blockchainHeight - height}'; + String toString() => '$blocksLeft'; } class SyncedSyncStatus extends SyncStatus { diff --git a/lib/src/domain/monero/monero_amount_format.dart b/lib/src/domain/monero/monero_amount_format.dart index 7dfb7142..baf1a81d 100644 --- a/lib/src/domain/monero/monero_amount_format.dart +++ b/lib/src/domain/monero/monero_amount_format.dart @@ -11,3 +11,5 @@ String moneroAmountToString({int amount}) => moneroAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider)); double moneroAmountToDouble({int amount}) => cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider); + +int moneroParseAmount({String amount}) => moneroAmountFormat.parse(amount).toInt(); \ No newline at end of file diff --git a/lib/src/domain/monero/monero_wallet.dart b/lib/src/domain/monero/monero_wallet.dart index 19c48525..66e46a6f 100644 --- a/lib/src/domain/monero/monero_wallet.dart +++ b/lib/src/domain/monero/monero_wallet.dart @@ -139,11 +139,10 @@ class MoneroWallet extends Wallet { @override Future updateInfo() async { _name.value = await getName(); - final acccountList = getAccountList(); - acccountList.refresh(); + final acccountList = getAccountList()..refresh(); _account.value = acccountList.getAll().first; final subaddressList = getSubaddress(); - await subaddressList.refresh( + subaddressList.refresh( accountIndex: _account.value != null ? _account.value.id : 0); final subaddresses = subaddressList.getAll(); _subaddress.value = subaddresses.first; @@ -218,7 +217,7 @@ class MoneroWallet extends Wallet { @override Future close() async { - monero_wallet.closeListeners(); +// monero_wallet.closeListeners(); monero_wallet.closeCurrentWallet(); await _name.close(); await _address.close(); @@ -330,11 +329,8 @@ class MoneroWallet extends Wallet { void changeAccount(Account account) { _account.add(account); - - getSubaddress() - .refresh(accountIndex: account.id) - .then((dynamic _) => getSubaddress().getAll()) - .then((subaddresses) => _subaddress.value = subaddresses[0]); + final subaddress = getSubaddress()..refresh(accountIndex: account.id); + _subaddress.value = subaddress.getAll().first; } Future store() async { @@ -353,77 +349,72 @@ class MoneroWallet extends Wallet { } } - void setListeners() => monero_wallet.setListeners( - _onNewBlock, _onNeedToRefresh, _onNewTransaction); - - Future _onNewBlock(int height) async { - try { - final nodeHeight = await getNodeHeightOrUpdate(height); - - if (isRecovery && _refreshHeight <= 0) { - _refreshHeight = height; - } - - if (isRecovery && - (_lastSyncHeight == 0 || - (height - _lastSyncHeight) > moneroBlockSize)) { - _lastSyncHeight = height; - await askForUpdateBalance(); - await askForUpdateTransactionHistory(); - } - - if (height > 0 && ((nodeHeight - height) < moneroBlockSize)) { - _syncStatus.add(SyncedSyncStatus()); - } else { - _syncStatus.add(SyncingSyncStatus(height, nodeHeight, _refreshHeight)); - } - } catch (e) { - print(e); - } - } - - Future _onNeedToRefresh() async { - try { - final currentHeight = await getCurrentHeight(); - final nodeHeight = await getNodeHeightOrUpdate(currentHeight); - - // no blocks - maybe we're not connected to the node ? - if (currentHeight <= 1 || nodeHeight == 0) { - return; - } - - if (_syncStatus.value is FailedSyncStatus) { - return; - } - - await askForUpdateBalance(); - - _syncStatus.add(SyncedSyncStatus()); - - if (isRecovery) { - await askForUpdateTransactionHistory(); - } - - if (isRecovery && (nodeHeight - currentHeight < moneroBlockSize)) { - await setAsRecovered(); - } - - final now = DateTime.now().millisecondsSinceEpoch; - final diff = now - _lastRefreshTime; - - if (diff >= 0 && diff < 60000) { - return; - } - - await store(); - _lastRefreshTime = now; - } catch (e) { - print(e); - } - } - - Future _onNewTransaction() async { - await askForUpdateBalance(); - await askForUpdateTransactionHistory(); - } + void setListeners() => null; +// monero_wallet.setListeners( +// _onNewBlock, _onNeedToRefresh, _onNewTransaction); + +// Future _onNewBlock(int height) async { +// try { +// final nodeHeight = await getNodeHeightOrUpdate(height); +// +// if (isRecovery && _refreshHeight <= 0) { +// _refreshHeight = height; +// } +// +// if (isRecovery && +// (_lastSyncHeight == 0 || +// (height - _lastSyncHeight) > moneroBlockSize)) { +// _lastSyncHeight = height; +// await askForUpdateBalance(); +// await askForUpdateTransactionHistory(); +// } +// +// if (height > 0 && ((nodeHeight - height) < moneroBlockSize)) { +// _syncStatus.add(SyncedSyncStatus()); +// } else { +// _syncStatus.add(SyncingSyncStatus(height, nodeHeight, _refreshHeight)); +// } +// } catch (e) { +// print(e); +// } +// } + +// Future _onNeedToRefresh() async { +// try { +// +// +// if (_syncStatus.value is FailedSyncStatus) { +// return; +// } +// +// await askForUpdateBalance(); +// +// _syncStatus.add(SyncedSyncStatus()); +// +// if (isRecovery) { +// await askForUpdateTransactionHistory(); +// } +// +//// if (isRecovery && (nodeHeight - currentHeight < moneroBlockSize)) { +//// await setAsRecovered(); +//// } +// +// final now = DateTime.now().millisecondsSinceEpoch; +// final diff = now - _lastRefreshTime; +// +// if (diff >= 0 && diff < 60000) { +// return; +// } +// +// await store(); +// _lastRefreshTime = now; +// } catch (e) { +// print(e); +// } +// } + +// Future _onNewTransaction() async { +// await askForUpdateBalance(); +// await askForUpdateTransactionHistory(); +// } } diff --git a/lib/src/domain/monero/subaddress_list.dart b/lib/src/domain/monero/subaddress_list.dart index 88af9374..55dc1b7c 100644 --- a/lib/src/domain/monero/subaddress_list.dart +++ b/lib/src/domain/monero/subaddress_list.dart @@ -16,16 +16,15 @@ class SubaddressList { bool _isRefreshing; bool _isUpdating; - Future update({int accountIndex}) async { + void update({int accountIndex}) { if (_isUpdating) { return; } try { _isUpdating = true; - await refresh(accountIndex: accountIndex); - final subaddresses = getAll(); - _subaddress.add(subaddresses); + refresh(accountIndex: accountIndex); + _subaddress.add(getAll()); _isUpdating = false; } catch (e) { _isUpdating = false; @@ -53,7 +52,7 @@ class SubaddressList { await update(); } - Future refresh({int accountIndex}) async { + void refresh({int accountIndex}) { if (_isRefreshing) { return; }