wownero
M 4 years ago
parent b605a98811
commit 957ca8cd58

@ -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();
}

@ -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<int> 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();

@ -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<void> setupPinCode({@required String pin}) async {}
Future<bool> authenticate({@required String pin}) async {
return false;
}
void resetSetupPinCodeState() =>
setupPinCodeState = InitialSetupPinCodeState();
}

@ -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<BitcoinTransactionInfo> 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<void> init() async {
// TODO: throw exeption if wallet is null;
final info = await _read();
_height = (info['height'] as int) ?? _height;
transactions = info['transactions'] as List<BitcoinTransactionInfo>;
}
@override
Future update() async {
await super.update();
_updateHeight();
}
@override
Future<List<BitcoinTransactionInfo>> 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<String, Object>,
addresses: addresses))
.toList();
}
Future<Map<String, Object>> 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<String, Object>;
return {'raw': raw, 'header': header};
}
Future<void> add(List<BitcoinTransactionInfo> transactions) async {
this.transactions.addAll(transactions);
await save();
}
Future<void> addOne(BitcoinTransactionInfo tx) async {
transactions.add(tx);
await save();
}
Future<void> save() async => writeData(
path: path,
password: _password,
data: json.encode({'height': _height, 'transactions': transactions}));
Future<Map<String, Object>> _read() async {
try {
final content = await read(path: path, password: _password);
final jsoned = json.decode(content) as Map<String, Object>;
final height = jsoned['height'] as int;
final transactions = (jsoned['transactions'] as List<dynamic>)
.map((dynamic row) {
if (row is Map<String, Object>) {
return BitcoinTransactionInfo.fromJson(row);
}
return null;
})
.where((el) => el != null)
.toList();
return {'transactions': transactions, 'height': height};
} catch (_) {
return {'transactions': <TransactionInfo>[], 'height': 0};
}
}
void _updateHeight() {
final newHeight = transactions.fold(
0, (int acc, val) => val.height > acc ? val.height : acc);
_height = newHeight > _height ? newHeight : _height;
}
}

@ -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<BitcoinBalance> with Store {
static Future<BitcoinWallet> 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<String, Object>;
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<String> getAddresses() => _accountIndex == 0
? [address]
: List<String>.generate(
_accountIndex, (i) => _getAddress(hd: hd, index: i));
Future<void> init() async {
await transactionHistory.init();
}
Future<String> newAddress() async {
_accountIndex += 1;
final address = _getAddress(hd: hd, index: _accountIndex);
await save();
return address;
}
@override
Future<void> startSync() async {}
@override
Future<void> connectToNode({@required Node node}) async {}
@override
Future<void> createTransaction(Object credentials) async {}
@override
Future<void> 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<Map<String, int>> _fetchBalances() async {
final balances = await Future.wait(
getAddresses().map((address) => eclient.getBalance(address: address)));
final balance = balances.fold(<String, int>{}, (Map<String, int> 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;
}
}

@ -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<void> 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<bool> isWalletExit(String name) async =>
File(await pathForWallet(name: name, type: WalletType.bitcoin))
.existsSync();
@override
Future<void> openWallet(String name, String password) async {
// TODO: implement openWallet
throw UnimplementedError();
}
Future<void> remove(String wallet) {
// TODO: implement remove
throw UnimplementedError();
}
@override
Future<void> restoreFromKeys(
BitcoinRestoreWalletFromWIFCredentials credentials) async {
// TODO: implement restoreFromKeys
throw UnimplementedError();
}
@override
Future<void> restoreFromSeed(
BitcoinRestoreWalletFromSeedCredentials credentials) async {
final wallet = await BitcoinWalletBase.build(
name: credentials.name,
password: credentials.password,
mnemonic: credentials.mnemonic);
await wallet.save();
return wallet;
}
}

@ -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;
}

@ -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<TransactionInfo> _getAllTransactions(dynamic _) =>
monero_transaction_history
.getAllTransations()
.map((row) => MoneroTransactionInfo.fromRow(row))
.toList();
class MoneroTransactionHistory = MoneroTransactionHistoryBase
with _$MoneroTransactionHistory;
abstract class MoneroTransactionHistoryBase
extends TranasctionHistoryBase<TransactionInfo> with Store {
@override
Future<List<TransactionInfo>> fetchTransactions() async {
monero_transaction_history.refreshTransactions();
return _getAllTransactions(null);
}
}

@ -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<MoneroBalance> 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<void> 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<void> startSync() async {
try {
syncStatus = StartingSyncStatus();
monero_wallet.startRefresh();
} catch (e) {
syncStatus = FailedSyncStatus();
print(e);
rethrow;
}
}
@override
Future<void> 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<void> save() async {
// if (_isSaving) {
// return;
// }
try {
// _isSaving = true;
await monero_wallet.store();
// _isSaving = false;
} catch (e) {
print(e);
// _isSaving = false;
rethrow;
}
}
Future<int> getNodeHeight() async => monero_wallet.getNodeHeight();
Future<bool> 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();
}
}

@ -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<void> 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<bool> 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<void> 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<void> remove(String wallet) async {
// TODO: implement remove
throw UnimplementedError();
}
@override
Future<void> 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<void> 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;
}
}
}

@ -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 {
}

@ -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;
}

@ -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 {
}

@ -0,0 +1,27 @@
import 'package:mobx/mobx.dart';
abstract class TranasctionHistoryBase<TransactionType> {
TranasctionHistoryBase() : _isUpdating = false;
@observable
List<TransactionType> transactions;
bool _isUpdating;
Future<void> update() async {
if (_isUpdating) {
return;
}
try {
_isUpdating = false;
transactions = await fetchTransactions();
_isUpdating = true;
} catch (e) {
_isUpdating = false;
rethrow;
}
}
Future<List<TransactionType>> fetchTransactions();
}

@ -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<BalaceType> {
String get name;
String get filename;
@observable
String address;
@observable
BalaceType balance;
Future<void> connectToNode({@required Node node});
Future<void> startSync();
Future<void> createTransaction(Object credentials);
Future<void> save();
}

@ -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<void> create(WalletCredentials credentials) async {
try {
state = WalletCreating();
await _service.create(credentials);
state = WalletCreatedSuccessfully();
} catch (e) {
state = WalletCreationFailure(error: e.toString());
}
}
Future<void> restoreFromKeys(WalletCredentials credentials) async {
try {
state = WalletCreating();
await _service.restoreFromKeys(credentials);
state = WalletCreatedSuccessfully();
} catch (e) {
state = WalletCreationFailure(error: e.toString());
}
}
Future<void> restoreFromSeed(WalletCredentials credentials) async {
try {
state = WalletCreating();
await _service.restoreFromSeed(credentials);
state = WalletCreatedSuccessfully();
} catch (e) {
state = WalletCreationFailure(error: e.toString());
}
}
}

@ -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;
}

@ -0,0 +1,6 @@
abstract class WalletCredentials {
const WalletCredentials({this.name, this.password});
final String name;
final String password;
}

@ -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<N extends WalletCredentials,
RFS extends WalletCredentials, RFK extends WalletCredentials> {
@ -34,264 +14,3 @@ abstract class WalletListService<N extends WalletCredentials,
Future<void> 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<void> create(BitcoinNewWalletCredentials credentials) async {
// TODO: implement create
throw UnimplementedError();
}
@override
Future<bool> isWalletExit(String name) async {
// TODO: implement isWalletExit
throw UnimplementedError();
}
@override
Future<void> openWallet(String name, String password) async {
// TODO: implement openWallet
throw UnimplementedError();
}
Future<void> remove(String wallet) {
// TODO: implement remove
throw UnimplementedError();
}
@override
Future<void> restoreFromKeys(
BitcoinRestoreWalletFromWIFCredentials credentials) async {
// TODO: implement restoreFromKeys
throw UnimplementedError();
}
@override
Future<void> restoreFromSeed(
BitcoinRestoreWalletFromSeedCredentials credentials) async {
// TODO: implement restoreFromSeed
throw UnimplementedError();
}
}
/*
*
* BitcoinWalletListService
*
* */
class MoneroWalletListService extends WalletListService<
BitcoinNewWalletCredentials,
BitcoinRestoreWalletFromSeedCredentials,
BitcoinRestoreWalletFromWIFCredentials> {
@override
Future<void> create(BitcoinNewWalletCredentials credentials) async {
// TODO: implement create
throw UnimplementedError();
}
@override
Future<bool> isWalletExit(String name) async {
// TODO: implement isWalletExit
throw UnimplementedError();
}
@override
Future<void> openWallet(String name, String password) async {
// TODO: implement openWallet
throw UnimplementedError();
}
Future<void> remove(String wallet) {
// TODO: implement remove
throw UnimplementedError();
}
@override
Future<void> restoreFromKeys(
BitcoinRestoreWalletFromWIFCredentials credentials) async {
// TODO: implement restoreFromKeys
throw UnimplementedError();
}
@override
Future<void> 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<void> create(WalletCredentials credentials) async {
try {
state = WalletCreating();
await _service.create(credentials);
state = WalletCreatedSuccessfully();
} catch (e) {
state = WalletCreationFailure(error: e.toString());
}
}
Future<void> restoreFromKeys(WalletCredentials credentials) async {
try {
state = WalletCreating();
await _service.create(credentials);
state = WalletCreatedSuccessfully();
} catch (e) {
state = WalletCreationFailure(error: e.toString());
}
}
Future<void> 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<void> setupPinCode({@required String pin}) async {}
Future<bool> 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 {}

@ -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 {

@ -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();

@ -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();
// }
}

@ -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;
}

Loading…
Cancel
Save