This commit is contained in:
M
2020-06-20 10:10:00 +03:00
parent 719842964b
commit 81cee186db
94 changed files with 3786 additions and 3001 deletions
+12
View File
@@ -0,0 +1,12 @@
import 'package:cake_wallet/core/validator.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
class AddressLabelValidator extends TextValidator {
AddressLabelValidator({WalletType type})
: super(
errorMessage: S.current.error_text_subaddress_name,
pattern: '''^[^`,'"]{1,20}\$''',
minLength: 1,
maxLength: 20);
}
+24
View File
@@ -0,0 +1,24 @@
import 'package:cake_wallet/core/validator.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
class AmountValidator extends TextValidator {
AmountValidator({WalletType type})
: super(
errorMessage: S.current.error_text_amount,
pattern: _pattern(type),
minLength: 0,
maxLength: 0);
static String _pattern(WalletType type) {
switch (type) {
case WalletType.monero:
return '^([0-9]+([.][0-9]{0,12})?|[.][0-9]{1,12})\$';
case WalletType.bitcoin:
// FIXME: Incorrect pattern for bitcoin
return '^([0-9]+([.][0-9]{0,12})?|[.][0-9]{1,12})\$';
default:
return '';
}
}
}
-16
View File
@@ -1,16 +0,0 @@
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/core/wallet_creation_service.dart';
part 'app_service.g.dart';
class AppService = AppServiceBase with _$AppService;
abstract class AppServiceBase with Store {
AppServiceBase({this.walletCreationService, this.authService, this.wallet});
WalletCreationService walletCreationService;
AuthService authService;
WalletBase wallet;
}
+33 -13
View File
@@ -1,21 +1,41 @@
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/core/setup_pin_code_state.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/src/domain/common/secret_store_key.dart';
import 'package:cake_wallet/src/domain/common/encrypt.dart';
part 'auth_service.g.dart';
class AuthService with Store {
AuthService({this.secureStorage, this.sharedPreferences});
class AuthService = AuthServiceBase with _$AuthService;
final FlutterSecureStorage secureStorage;
final SharedPreferences sharedPreferences;
abstract class AuthServiceBase with Store {
@observable
SetupPinCodeState setupPinCodeState;
Future<void> setupPinCode({@required String pin}) async {}
Future<bool> authenticate({@required String pin}) async {
return false;
Future setPassword(String password) async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final encodedPassword = encodedPinCode(pin: password);
await secureStorage.write(key: key, value: encodedPassword);
}
void resetSetupPinCodeState() =>
setupPinCodeState = InitialSetupPinCodeState();
Future<bool> canAuthenticate() async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final walletName = sharedPreferences.getString('current_wallet_name') ?? '';
var password = '';
try {
password = await secureStorage.read(key: key);
} catch (e) {
print(e);
}
return walletName.isNotEmpty && password.isNotEmpty;
}
Future<bool> authenticate(String pin) async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final encodedPin = await secureStorage.read(key: key);
final decodedPin = decodedPinCode(pin: encodedPin);
return decodedPin == pin;
}
}
+20
View File
@@ -0,0 +1,20 @@
abstract class AuthState {}
class AuthenticationStateInitial extends AuthState {}
class AuthenticationInProgress extends AuthState {}
class AuthenticatedSuccessfully extends AuthState {}
class AuthenticationFailure extends AuthState {
AuthenticationFailure({this.error});
final String error;
}
class AuthenticationBanned extends AuthState {
AuthenticationBanned({this.error});
final String error;
}
-121
View File
@@ -1,121 +0,0 @@
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;
}
}
-149
View File
@@ -1,149 +0,0 @@
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<BitcoinWalletBase> 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 BitcoinWalletBase.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;
}
}
-103
View File
@@ -1,103 +0,0 @@
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;
}
}
+12
View File
@@ -0,0 +1,12 @@
import 'package:uuid/uuid.dart';
import 'package:cake_wallet/bitcoin/key.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
String generateWalletPassword(WalletType type) {
switch (type) {
case WalletType.bitcoin:
return generateKey();
default:
return Uuid().v4();
}
}
+17
View File
@@ -0,0 +1,17 @@
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
const bitcoinMnemonicLength = 12;
const moneroMnemonicLength = 25;
int mnemonicLength(WalletType type) {
// TODO: need to have only one place for get(set) mnemonic string lenth;
switch (type) {
case WalletType.monero:
return moneroMnemonicLength;
case WalletType.bitcoin:
return bitcoinMnemonicLength;
default:
return 0;
}
}
-20
View File
@@ -1,20 +0,0 @@
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;
}
-27
View File
@@ -1,27 +0,0 @@
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);
}
}
-186
View File
@@ -1,186 +0,0 @@
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();
}
}
-146
View File
@@ -1,146 +0,0 @@
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;
}
}
}
+73
View File
@@ -0,0 +1,73 @@
import 'package:bip39/src/wordlists/english.dart' as bitcoin_english;
import 'package:cake_wallet/core/validator.dart';
import 'package:cake_wallet/src/domain/common/mnemonic_item.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/src/domain/monero/mnemonics/chinese_simplified.dart';
import 'package:cake_wallet/src/domain/monero/mnemonics/dutch.dart';
import 'package:cake_wallet/src/domain/monero/mnemonics/english.dart';
import 'package:cake_wallet/src/domain/monero/mnemonics/german.dart';
import 'package:cake_wallet/src/domain/monero/mnemonics/japanese.dart';
import 'package:cake_wallet/src/domain/monero/mnemonics/portuguese.dart';
import 'package:cake_wallet/src/domain/monero/mnemonics/russian.dart';
import 'package:cake_wallet/src/domain/monero/mnemonics/spanish.dart';
class SeedValidator extends Validator<MnemonicItem> {
SeedValidator({this.type, this.language})
: _words = getWordList(type: type, language: language);
final WalletType type;
final String language;
final List<String> _words;
static List<String> getWordList({WalletType type, String language}) {
switch (type) {
case WalletType.bitcoin:
return getBitcoinWordList(language);
case WalletType.monero:
return getMoneroWordList(language);
default:
return [];
}
}
static List<String> getMoneroWordList(String language) {
// FIXME: Unnamed constants; Need to be sure that string are in same case;
switch (language) {
case 'English':
return EnglishMnemonics.words;
break;
case 'Chinese (simplified)':
return ChineseSimplifiedMnemonics.words;
break;
case 'Dutch':
return DutchMnemonics.words;
break;
case 'German':
return GermanMnemonics.words;
break;
case 'Japanese':
return JapaneseMnemonics.words;
break;
case 'Portuguese':
return PortugueseMnemonics.words;
break;
case 'Russian':
return RussianMnemonics.words;
break;
case 'Spanish':
return SpanishMnemonics.words;
break;
default:
return EnglishMnemonics.words;
}
}
static List<String> getBitcoinWordList(String language) {
assert(language.toLowerCase() == 'english');
return bitcoin_english.WORDLIST;
}
@override
bool isValid(MnemonicItem value) => _words.contains(value.text);
}
-15
View File
@@ -1,15 +0,0 @@
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;
}
+5 -4
View File
@@ -1,10 +1,11 @@
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/src/domain/common/transaction_info.dart';
abstract class TranasctionHistoryBase<TransactionType> {
TranasctionHistoryBase() : _isUpdating = false;
abstract class TransactionHistoryBase<TransactionType extends TransactionInfo> {
TransactionHistoryBase() : _isUpdating = false;
@observable
List<TransactionType> transactions;
ObservableList<TransactionType> transactions;
bool _isUpdating;
@@ -15,7 +16,7 @@ abstract class TranasctionHistoryBase<TransactionType> {
try {
_isUpdating = false;
transactions = await fetchTransactions();
transactions.addAll(await fetchTransactions());
_isUpdating = true;
} catch (e) {
_isUpdating = false;
+39
View File
@@ -0,0 +1,39 @@
import 'package:flutter/foundation.dart';
abstract class Validator<T> {
Validator({@required this.errorMessage});
final String errorMessage;
bool isValid(T value);
String call(T value) => !isValid(value) ? errorMessage : null;
}
class TextValidator extends Validator<String> {
TextValidator(
{this.minLength, this.maxLength, this.pattern, String errorMessage})
: super(errorMessage: errorMessage);
final int minLength;
final int maxLength;
String pattern;
@override
bool isValid(String value) {
if (value == null || value.isEmpty) {
return true;
}
return value.length > minLength &&
(maxLength > 0 ? (value.length <= maxLength) : true) &&
(pattern != null ? match(value) : true);
}
bool match(String value) => RegExp(pattern).hasMatch(value);
}
class WalletNameValidator extends TextValidator {
WalletNameValidator()
: super(minLength: 1, maxLength: 15, pattern: '^[a-zA-Z0-9_]\$');
}
+10 -6
View File
@@ -1,20 +1,24 @@
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/core/transaction_history.dart';
import 'package:cake_wallet/src/domain/common/node.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
abstract class WalletBase<BalaceType> {
WalletType type;
String get name;
String get filename;
@observable
String address;
@observable
BalaceType balance;
TransactionHistoryBase transactionHistory;
Future<void> connectToNode({@required Node node});
Future<void> startSync();
Future<void> createTransaction(Object credentials);
Future<void> save();
}
}
+63 -37
View File
@@ -1,34 +1,47 @@
import 'package:cake_wallet/core/wallet_creation_state.dart';
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';
import 'package:cake_wallet/core/generate_wallet_password.dart';
import 'package:cake_wallet/store/app_store.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/bitcoin/bitcoin_wallet_service.dart';
import 'package:cake_wallet/monero/monero_wallet_service.dart';
import 'package:cake_wallet/core/wallet_service.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';
part 'wallet_creation_service.g.dart';
class WalletCreationService = WalletCreationServiceBase
with _$WalletCreationService;
abstract class WalletCreationServiceBase with Store {
@observable
WalletCreationState state;
class WalletCreationService {
WalletCreationService(
{WalletType initialType,
this.appStore,
this.secureStorage,
this.sharedPreferences})
: type = initialType {
if (type != null) {
changeWalletType(type: type);
}
}
WalletType type;
final AppStore appStore;
final FlutterSecureStorage secureStorage;
final SharedPreferences sharedPreferences;
WalletListService _service;
// final WalletService walletService;
// final Box<WalletInfo> walletInfoSource;
WalletService _service;
void changeWalletType({@required WalletType type}) {
this.type = type;
switch (type) {
case WalletType.monero:
_service = MoneroWalletListService();
_service = MoneroWalletService();
break;
case WalletType.bitcoin:
_service = BitcoinWalletListService();
_service = BitcoinWalletService();
break;
default:
break;
@@ -36,32 +49,45 @@ abstract class WalletCreationServiceBase with Store {
}
Future<void> create(WalletCredentials credentials) async {
try {
state = WalletCreating();
await _service.create(credentials);
state = WalletCreatedSuccessfully();
} catch (e) {
state = WalletCreationFailure(error: e.toString());
}
final password = generateWalletPassword(type);
credentials.password = password;
await saveWalletPassword(password: password, walletName: credentials.name);
final wallet = await _service.create(credentials);
appStore.wallet = wallet;
appStore.authenticationStore.allowed();
}
Future<void> restoreFromKeys(WalletCredentials credentials) async {
try {
state = WalletCreating();
await _service.restoreFromKeys(credentials);
state = WalletCreatedSuccessfully();
} catch (e) {
state = WalletCreationFailure(error: e.toString());
}
final password = generateWalletPassword(type);
credentials.password = password;
await saveWalletPassword(password: password, walletName: credentials.name);
final wallet = await _service.restoreFromKeys(credentials);
appStore.wallet = wallet;
appStore.authenticationStore.allowed();
}
Future<void> restoreFromSeed(WalletCredentials credentials) async {
try {
state = WalletCreating();
await _service.restoreFromSeed(credentials);
state = WalletCreatedSuccessfully();
} catch (e) {
state = WalletCreationFailure(error: e.toString());
}
final password = generateWalletPassword(type);
credentials.password = password;
await saveWalletPassword(password: password, walletName: credentials.name);
final wallet = await _service.restoreFromSeed(credentials);
appStore.wallet = wallet;
appStore.authenticationStore.allowed();
}
Future<String> getWalletPassword({String walletName}) async {
final key = generateStoreKeyFor(
key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
final encodedPassword = await secureStorage.read(key: key);
return decodeWalletPassword(password: encodedPassword);
}
Future<void> saveWalletPassword({String walletName, String password}) async {
final key = generateStoreKeyFor(
key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
final encodedPassword = encodeWalletPassword(password: password);
await secureStorage.write(key: key, value: encodedPassword);
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
abstract class WalletCredentials {
const WalletCredentials({this.name, this.password});
WalletCredentials({this.name, this.password});
final String name;
final String password;
String password;
}
-16
View File
@@ -1,16 +0,0 @@
import 'package:cake_wallet/core/wallet_credentials.dart';
abstract class WalletListService<N extends WalletCredentials,
RFS extends WalletCredentials, RFK extends WalletCredentials> {
Future<void> create(N credentials);
Future<void> restoreFromSeed(RFS credentials);
Future<void> restoreFromKeys(RFK credentials);
Future<void> openWallet(String name, String password);
Future<bool> isWalletExit(String name);
Future<void> remove(String wallet);
}
+17
View File
@@ -0,0 +1,17 @@
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/core/wallet_credentials.dart';
abstract class WalletService<N extends WalletCredentials,
RFS extends WalletCredentials, RFK extends WalletCredentials> {
Future<WalletBase> create(N credentials);
Future<WalletBase> restoreFromSeed(RFS credentials);
Future<WalletBase> restoreFromKeys(RFK credentials);
Future<WalletBase> openWallet(String name, String password);
Future<bool> isWalletExit(String name);
Future<void> remove(String wallet);
}