mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-06 19:09:30 +00:00
TMP 1
This commit is contained in:
parent
b605a98811
commit
957ca8cd58
23 changed files with 1082 additions and 440 deletions
cw_monero
lib
core
auth_service.dartbitcoin_transaction_history.dartbitcoin_wallet.dartbitcoin_wallet_list_service.dartmonero_balance.dartmonero_transaction_history.dartmonero_wallet.dartmonero_wallet_list_service.dartmonero_wallet_store.dartsetup_pin_code_state.dartsign_up_store.darttransaction_history.dartwallet_base.dartwallet_creation_service.dartwallet_creation_state.dartwallet_credentials.dartwallet_list_service.dart
src/domain
|
@ -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 != m_last_known_wallet_height)
|
||||
{
|
||||
m_last_known_wallet_height = _height;
|
||||
if (height <= 1 || node_height <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _height;
|
||||
if (height != m_last_known_wallet_height)
|
||||
{
|
||||
m_last_known_wallet_height = 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) {
|
||||
_lastKnownBlockHeight = syncHeight;
|
||||
await onNewBlock(syncHeight);
|
||||
}
|
||||
if (_lastKnownBlockHeight != syncHeight && syncHeight != null) {
|
||||
if (_initialSyncHeight <= 0) {
|
||||
_initialSyncHeight = syncHeight;
|
||||
}
|
||||
|
||||
if (newTransactionExist && onNewTransaction != null) {
|
||||
await onNewTransaction();
|
||||
}
|
||||
_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 (needToRefresh && onNeedToRefresh != null) {
|
||||
await onNeedToRefresh();
|
||||
}
|
||||
});
|
||||
setListenerNative();
|
||||
if (newTransactionExist && onNewTransaction != null) {
|
||||
onNewTransaction();
|
||||
}
|
||||
|
||||
if (needToRefresh && onNeedToRefresh != null) {
|
||||
onNeedToRefresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void stop() => _updateSyncInfoTimer?.cancel();
|
||||
}
|
||||
|
||||
void closeListeners() {
|
||||
if (_updateSyncInfoTimer != null) {
|
||||
_updateSyncInfoTimer.cancel();
|
||||
}
|
||||
SyncListner setListeners(void Function(int, int, double) onNewBlock,
|
||||
void Function() onNeedToRefresh, void Function() onNewTransaction) {
|
||||
final listener = SyncListner(
|
||||
onNewBlock: onNewBlock,
|
||||
onNeedToRefresh: onNeedToRefresh,
|
||||
onNewTransaction: onNewTransaction);
|
||||
|
||||
setListenerNative();
|
||||
|
||||
return listener;
|
||||
}
|
||||
|
||||
void onStartup() => onStartupNative();
|
||||
|
|
21
lib/core/auth_service.dart
Normal file
21
lib/core/auth_service.dart
Normal file
|
@ -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();
|
||||
}
|
121
lib/core/bitcoin_transaction_history.dart
Normal file
121
lib/core/bitcoin_transaction_history.dart
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
149
lib/core/bitcoin_wallet.dart
Normal file
149
lib/core/bitcoin_wallet.dart
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
103
lib/core/bitcoin_wallet_list_service.dart
Normal file
103
lib/core/bitcoin_wallet_list_service.dart
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
20
lib/core/monero_balance.dart
Normal file
20
lib/core/monero_balance.dart
Normal file
|
@ -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;
|
||||
}
|
27
lib/core/monero_transaction_history.dart
Normal file
27
lib/core/monero_transaction_history.dart
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
186
lib/core/monero_wallet.dart
Normal file
186
lib/core/monero_wallet.dart
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
146
lib/core/monero_wallet_list_service.dart
Normal file
146
lib/core/monero_wallet_list_service.dart
Normal file
|
@ -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 {
|
||||
|
||||
}
|
15
lib/core/setup_pin_code_state.dart
Normal file
15
lib/core/setup_pin_code_state.dart
Normal file
|
@ -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 {
|
||||
|
||||
}
|
27
lib/core/transaction_history.dart
Normal file
27
lib/core/transaction_history.dart
Normal file
|
@ -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();
|
||||
}
|
20
lib/core/wallet_base.dart
Normal file
20
lib/core/wallet_base.dart
Normal file
|
@ -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();
|
||||
}
|
63
lib/core/wallet_creation_service.dart
Normal file
63
lib/core/wallet_creation_service.dart
Normal file
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
13
lib/core/wallet_creation_state.dart
Normal file
13
lib/core/wallet_creation_state.dart
Normal file
|
@ -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;
|
||||
}
|
6
lib/core/wallet_credentials.dart
Normal file
6
lib/core/wallet_credentials.dart
Normal file
|
@ -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);
|
||||
void setListeners() => null;
|
||||
// monero_wallet.setListeners(
|
||||
// _onNewBlock, _onNeedToRefresh, _onNewTransaction);
|
||||
|
||||
Future _onNewBlock(int height) async {
|
||||
try {
|
||||
final nodeHeight = await getNodeHeightOrUpdate(height);
|
||||
// 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);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (isRecovery && _refreshHeight <= 0) {
|
||||
_refreshHeight = height;
|
||||
}
|
||||
// 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);
|
||||
// }
|
||||
// }
|
||||
|
||||
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();
|
||||
}
|
||||
// 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…
Reference in a new issue