Merge branch 'release-4.2.4' into CAKE-345-batch-sending

# Conflicts:
#	lib/bitcoin/electrum_wallet.dart
#	lib/src/screens/send/send_page.dart
#	lib/src/screens/send/send_template_page.dart
#	lib/view_model/send/send_view_model.dart
#	res/values/strings_de.arb
#	res/values/strings_en.arb
#	res/values/strings_es.arb
#	res/values/strings_hi.arb
#	res/values/strings_hr.arb
#	res/values/strings_it.arb
#	res/values/strings_ja.arb
#	res/values/strings_ko.arb
#	res/values/strings_nl.arb
#	res/values/strings_pl.arb
#	res/values/strings_pt.arb
#	res/values/strings_ru.arb
#	res/values/strings_uk.arb
#	res/values/strings_zh.arb
This commit is contained in:
OleksandrSobol
2021-07-22 17:52:48 +03:00
74 changed files with 1750 additions and 338 deletions
@@ -1,4 +1,10 @@
import 'package:cake_wallet/entities/crypto_currency.dart';
class BitcoinTransactionWrongBalanceException implements Exception {
BitcoinTransactionWrongBalanceException(this.currency);
final CryptoCurrency currency;
@override
String toString() => 'Wrong balance. Not enough BTC on your balance.';
String toString() => 'Wrong balance. Not enough ${currency.title} on your balance.';
}
+7 -1
View File
@@ -1,7 +1,10 @@
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
class BitcoinUnspent {
BitcoinUnspent(this.address, this.hash, this.value, this.vout);
BitcoinUnspent(this.address, this.hash, this.value, this.vout)
: isSending = true,
isFrozen = false,
note = '';
factory BitcoinUnspent.fromJSON(
BitcoinAddressRecord address, Map<String, dynamic> json) =>
@@ -15,4 +18,7 @@ class BitcoinUnspent {
bool get isP2wpkh =>
address.address.startsWith('bc') || address.address.startsWith('ltc');
bool isSending;
bool isFrozen;
String note;
}
+15 -7
View File
@@ -1,12 +1,14 @@
import 'package:cake_wallet/bitcoin/unspent_coins_info.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:flutter/foundation.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:cake_wallet/bitcoin/utils.dart';
import 'package:cake_wallet/bitcoin/electrum_wallet_snapshot.dart';
import 'package:cake_wallet/bitcoin/electrum_wallet.dart';
import 'package:cake_wallet/entities/wallet_info.dart';
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
import 'package:cake_wallet/bitcoin/electrum_balance.dart';
import 'package:cake_wallet/bitcoin/bitcoin_wallet_addresses.dart';
part 'bitcoin_wallet.g.dart';
@@ -17,6 +19,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
{@required String mnemonic,
@required String password,
@required WalletInfo walletInfo,
@required Box<UnspentCoinsInfo> unspentCoinsInfo,
List<BitcoinAddressRecord> initialAddresses,
ElectrumBalance initialBalance,
int accountIndex = 0})
@@ -24,14 +27,22 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
networkType: bitcoin.bitcoin,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
accountIndex: accountIndex);
initialBalance: initialBalance) {
walletAddresses = BitcoinWalletAddresses(
walletInfo,
initialAddresses: initialAddresses,
accountIndex: accountIndex,
hd: hd,
networkType: networkType);
}
static Future<BitcoinWallet> open({
@required String name,
@required WalletInfo walletInfo,
@required Box<UnspentCoinsInfo> unspentCoinsInfo,
@required String password,
}) async {
final snp = ElectrumWallletSnapshot(name, walletInfo.type, password);
@@ -40,12 +51,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
mnemonic: snp.mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp.addresses,
initialBalance: snp.balance,
accountIndex: snp.accountIndex);
}
@override
String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
}
+33
View File
@@ -0,0 +1,33 @@
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:cake_wallet/bitcoin/utils.dart';
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
import 'package:cake_wallet/bitcoin/electrum_wallet_addresses.dart';
import 'package:cake_wallet/entities/wallet_info.dart';
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart';
part 'bitcoin_wallet_addresses.g.dart';
class BitcoinWalletAddresses = BitcoinWalletAddressesBase
with _$BitcoinWalletAddresses;
abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses
with Store {
BitcoinWalletAddressesBase(
WalletInfo walletInfo,
{@required List<BitcoinAddressRecord> initialAddresses,
int accountIndex = 0,
@required bitcoin.HDWallet hd,
@required this.networkType})
: super(
walletInfo,
initialAddresses: initialAddresses,
accountIndex: accountIndex,
hd: hd);
bitcoin.NetworkType networkType;
@override
String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
}
+9 -4
View File
@@ -2,6 +2,7 @@ import 'dart:io';
import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart';
import 'package:cake_wallet/bitcoin/bitcoin_mnemonic_is_incorrect_exception.dart';
import 'package:cake_wallet/bitcoin/bitcoin_wallet_creation_credentials.dart';
import 'package:cake_wallet/bitcoin/unspent_coins_info.dart';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/core/wallet_service.dart';
import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
@@ -14,9 +15,10 @@ class BitcoinWalletService extends WalletService<
BitcoinNewWalletCredentials,
BitcoinRestoreWalletFromSeedCredentials,
BitcoinRestoreWalletFromWIFCredentials> {
BitcoinWalletService(this.walletInfoSource);
BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
@override
WalletType getType() => WalletType.bitcoin;
@@ -26,7 +28,8 @@ class BitcoinWalletService extends WalletService<
final wallet = BitcoinWallet(
mnemonic: await generateMnemonic(),
password: credentials.password,
walletInfo: credentials.walletInfo);
walletInfo: credentials.walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource);
await wallet.save();
await wallet.init();
return wallet;
@@ -42,7 +45,8 @@ class BitcoinWalletService extends WalletService<
(info) => info.id == WalletBase.idFor(name, getType()),
orElse: () => null);
final wallet = await BitcoinWalletBase.open(
password: password, name: name, walletInfo: walletInfo);
password: password, name: name, walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource);
await wallet.init();
return wallet;
}
@@ -67,7 +71,8 @@ class BitcoinWalletService extends WalletService<
final wallet = BitcoinWallet(
password: credentials.password,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo);
walletInfo: credentials.walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource);
await wallet.save();
await wallet.init();
return wallet;
+149 -95
View File
@@ -1,5 +1,8 @@
import 'dart:async';
import 'dart:convert';
import 'package:cake_wallet/bitcoin/unspent_coins_info.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/bitcoin/electrum_wallet_addresses.dart';
import 'package:mobx/mobx.dart';
import 'package:rxdart/subjects.dart';
import 'package:flutter/foundation.dart';
@@ -38,30 +41,28 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
ElectrumWalletBase(
{@required String password,
@required WalletInfo walletInfo,
@required Box<UnspentCoinsInfo> unspentCoinsInfo,
@required List<BitcoinAddressRecord> initialAddresses,
@required this.networkType,
@required this.mnemonic,
ElectrumClient electrumClient,
int accountIndex = 0,
ElectrumBalance initialBalance})
: balance = initialBalance ??
const ElectrumBalance(confirmed: 0, unconfirmed: 0),
hd = bitcoin.HDWallet.fromSeed(mnemonicToSeedBytes(mnemonic),
network: networkType)
.derivePath("m/0'/0"),
addresses = ObservableList<BitcoinAddressRecord>.of(
(initialAddresses ?? []).toSet()),
syncStatus = NotConnectedSyncStatus(),
_password = password,
_accountIndex = accountIndex,
_feeRates = <int>[],
_isTransactionUpdating = false,
super(walletInfo) {
this.electrumClient = electrumClient ?? ElectrumClient();
this.walletInfo = walletInfo;
this.unspentCoinsInfo = unspentCoinsInfo;
transactionHistory =
ElectrumTransactionHistory(walletInfo: walletInfo, password: password);
_unspent = [];
unspentCoins = [];
_scripthashesUpdateSubject = {};
}
@@ -72,10 +73,10 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
final String mnemonic;
ElectrumClient electrumClient;
Box<UnspentCoinsInfo> unspentCoinsInfo;
@override
@observable
String address;
ElectrumWalletAddresses walletAddresses;
@override
@observable
@@ -85,9 +86,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
@observable
SyncStatus syncStatus;
ObservableList<BitcoinAddressRecord> addresses;
List<String> get scriptHashes => addresses
List<String> get scriptHashes => walletAddresses.addresses
.map((addr) => scriptHash(addr.address, networkType: networkType))
.toList();
@@ -103,85 +102,26 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
wif: hd.wif, privateKey: hd.privKey, publicKey: hd.pubKey);
final String _password;
List<BitcoinUnspent> _unspent;
List<BitcoinUnspent> unspentCoins;
List<int> _feeRates;
int _accountIndex;
Map<String, BehaviorSubject<Object>> _scripthashesUpdateSubject;
bool _isTransactionUpdating;
Future<void> init() async {
await generateAddresses();
address = addresses[_accountIndex].address;
await walletAddresses.init();
await transactionHistory.init();
}
@action
Future<void> nextAddress() async {
_accountIndex += 1;
if (_accountIndex >= addresses.length) {
_accountIndex = 0;
}
address = addresses[_accountIndex].address;
await save();
}
Future<void> generateAddresses() async {
if (addresses.length < 33) {
final addressesCount = 33 - addresses.length;
await generateNewAddresses(addressesCount,
startIndex: addresses.length, hd: hd);
}
}
Future<BitcoinAddressRecord> generateNewAddress(
{bool isHidden = false, bitcoin.HDWallet hd}) async {
_accountIndex += 1;
final _hd = hd ?? this.hd;
final address = BitcoinAddressRecord(
getAddress(index: _accountIndex, hd: _hd),
index: _accountIndex,
isHidden: isHidden);
addresses.add(address);
await save();
return address;
}
Future<List<BitcoinAddressRecord>> generateNewAddresses(int count,
{int startIndex = 0, bitcoin.HDWallet hd, bool isHidden = false}) async {
final list = <BitcoinAddressRecord>[];
for (var i = startIndex; i < count + startIndex; i++) {
final address = BitcoinAddressRecord(getAddress(index: i, hd: hd),
index: i, isHidden: isHidden);
list.add(address);
}
addresses.addAll(list);
await save();
return list;
}
Future<void> updateAddress(String address) async {
for (final addr in addresses) {
if (addr.address == address) {
await save();
break;
}
}
}
@action
@override
Future<void> startSync() async {
try {
syncStatus = StartingSyncStatus();
updateTransactions();
await updateTransactions();
_subscribeForUpdates();
await _updateBalance();
await _updateUnspent();
await updateUnspent();
_feeRates = await electrumClient.feeRates();
Timer.periodic(const Duration(minutes: 1),
@@ -219,6 +159,23 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
final transactionCredentials = credentials as BitcoinTransactionCredentials;
final inputs = <BitcoinUnspent>[];
final sendItemList = transactionCredentials.sendItemList;
var allInputsAmount = 0;
if (unspentCoins.isEmpty) {
await updateUnspent();
}
for (final utx in unspentCoins) {
if (utx.isSending) {
allInputsAmount += utx.value;
inputs.add(utx);
}
}
if (inputs.isEmpty) {
throw BitcoinTransactionNoInputsException();
}
final allAmountFee =
calculateEstimatedFee(transactionCredentials.priority, null);
final allAmount = balance.confirmed - allAmountFee;
@@ -280,22 +237,48 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
throw BitcoinTransactionWrongBalanceException();
}
feeAmountForPriority(transactionCredentials.priority, inputs.length, 1);
final allAmount = allInputsAmount - allAmountFee;
final credentialsAmount = transactionCredentials.amount != null
? stringDoubleToBitcoinAmount(transactionCredentials.amount)
: 0;
final amount = transactionCredentials.amount == null ||
allAmount - credentialsAmount < minAmount
? allAmount
: credentialsAmount;
final fee = transactionCredentials.amount == null || amount == allAmount
? allAmountFee
: calculateEstimatedFee(transactionCredentials.priority, amount);
if (fee == 0) {
throw BitcoinTransactionWrongBalanceException(currency);
}
final totalAmount = amount + fee;
if (totalAmount > balance.confirmed || totalAmount > allInputsAmount) {
throw BitcoinTransactionWrongBalanceException(currency);
}
final txb = bitcoin.TransactionBuilder(network: networkType);
final changeAddress = walletAddresses.address;
var leftAmount = totalAmount;
final changeAddress = address;
var leftAmount = totalAmount;
var totalInputAmount = 0;
if (_unspent.isEmpty) {
await _updateUnspent();
}
inputs.clear();
for (final utx in _unspent) {
leftAmount = leftAmount - utx.value;
totalInputAmount += utx.value;
inputs.add(utx);
for (final utx in unspentCoins) {
if (utx.isSending) {
leftAmount = leftAmount - utx.value;
totalInputAmount += utx.value;
inputs.add(utx);
if (leftAmount <= 0) {
break;
if (leftAmount <= 0) {
break;
}
}
}
@@ -303,6 +286,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
throw BitcoinTransactionNoInputsException();
}
if (amount <= 0 || totalInputAmount < totalAmount) {
throw BitcoinTransactionWrongBalanceException(currency);
if (amount <= 0 || totalInputAmount < amount) {
throw BitcoinTransactionWrongBalanceException();
}
@@ -361,8 +346,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
String toJSON() => json.encode({
'mnemonic': mnemonic,
'account_index': _accountIndex.toString(),
'addresses': addresses.map((addr) => addr.toJSON()).toList(),
'account_index': walletAddresses.accountIndex.toString(),
'addresses': walletAddresses.addresses.map((addr) => addr.toJSON()).toList(),
'balance': balance?.toJSON()
});
@@ -387,17 +372,26 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
if (amount != null) {
int totalValue = 0;
for (final input in _unspent) {
for (final input in unspentCoins) {
if (totalValue >= amount) {
break;
}
totalValue += input.value;
inputsCount += 1;
if (input.isSending) {
totalValue += input.value;
inputsCount += 1;
}
}
if (totalValue < amount) return 0;
} else {
inputsCount = _unspent.length;
for (final input in unspentCoins) {
if (input.isSending) {
inputsCount += 1;
}
}
}
// If send all, then we have no change value
final _outputsCount = outputsCount ?? (amount != null ? 2 : 1);
@@ -428,24 +422,84 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
} catch (_) {}
}
String getAddress({@required int index, @required bitcoin.HDWallet hd}) => '';
Future<String> makePath() async =>
pathForWallet(name: walletInfo.name, type: walletInfo.type);
Future<void> _updateUnspent() async {
final unspent = await Future.wait(addresses.map((address) => electrumClient
Future<void> updateUnspent() async {
final unspent = await Future.wait(walletAddresses
.addresses.map((address) => electrumClient
.getListUnspentWithAddress(address.address, networkType)
.then((unspent) => unspent
.map((unspent) => BitcoinUnspent.fromJSON(address, unspent)))));
_unspent = unspent.expand((e) => e).toList();
unspentCoins = unspent.expand((e) => e).toList();
if (unspentCoinsInfo.isEmpty) {
unspentCoins.forEach((coin) => _addCoinInfo(coin));
return;
}
if (unspentCoins.isNotEmpty) {
unspentCoins.forEach((coin) {
final coinInfoList = unspentCoinsInfo.values.where((element) =>
element.walletId.contains(id) && element.hash.contains(coin.hash));
if (coinInfoList.isNotEmpty) {
final coinInfo = coinInfoList.first;
coin.isFrozen = coinInfo.isFrozen;
coin.isSending = coinInfo.isSending;
coin.note = coinInfo.note;
} else {
_addCoinInfo(coin);
}
});
}
await _refreshUnspentCoinsInfo();
}
Future<void> _addCoinInfo(BitcoinUnspent coin) async {
final newInfo = UnspentCoinsInfo(
walletId: id,
hash: coin.hash,
isFrozen: coin.isFrozen,
isSending: coin.isSending,
note: coin.note
);
await unspentCoinsInfo.add(newInfo);
}
Future<void> _refreshUnspentCoinsInfo() async {
try {
final List<dynamic> keys = <dynamic>[];
final currentWalletUnspentCoins = unspentCoinsInfo.values
.where((element) => element.walletId.contains(id));
if (currentWalletUnspentCoins.isNotEmpty) {
currentWalletUnspentCoins.forEach((element) {
final existUnspentCoins = unspentCoins
?.where((coin) => element.hash.contains(coin?.hash));
if (existUnspentCoins?.isEmpty ?? true) {
keys.add(element.key);
}
});
}
if (keys.isNotEmpty) {
await unspentCoinsInfo.deleteAll(keys);
}
} catch (e) {
print(e.toString());
}
}
Future<ElectrumTransactionInfo> fetchTransactionInfo(
{@required String hash, @required int height}) async {
final tx = await electrumClient.getTransactionExpanded(hash: hash);
return ElectrumTransactionInfo.fromElectrumVerbose(tx, walletInfo.type,
height: height, addresses: addresses);
height: height, addresses: walletAddresses.addresses);
}
@override
@@ -489,7 +543,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
_scripthashesUpdateSubject[sh].listen((event) async {
try {
await _updateBalance();
await _updateUnspent();
await updateUnspent();
await updateTransactions();
} catch (e) {
print(e.toString());
+111
View File
@@ -0,0 +1,111 @@
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
import 'package:cake_wallet/entities/wallet_addresses.dart';
import 'package:cake_wallet/entities/wallet_info.dart';
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart';
part 'electrum_wallet_addresses.g.dart';
class ElectrumWalletAddresses = ElectrumWalletAddressesBase
with _$ElectrumWalletAddresses;
abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
ElectrumWalletAddressesBase(WalletInfo walletInfo,
{@required List<BitcoinAddressRecord> initialAddresses,
int accountIndex = 0,
@required bitcoin.HDWallet hd})
: super(walletInfo) {
this.hd = hd;
this.accountIndex = accountIndex;
addresses = ObservableList<BitcoinAddressRecord>.of(
(initialAddresses ?? []).toSet());
}
@override
@observable
String address;
bitcoin.HDWallet hd;
ObservableList<BitcoinAddressRecord> addresses;
int accountIndex;
@override
Future<void> init() async {
await generateAddresses();
address = addresses[accountIndex].address;
await updateAddressesInBox();
}
@action
Future<void> nextAddress() async {
accountIndex += 1;
if (accountIndex >= addresses.length) {
accountIndex = 0;
}
address = addresses[accountIndex].address;
await updateAddressesInBox();
}
Future<void> generateAddresses() async {
if (addresses.length < 33) {
final addressesCount = 33 - addresses.length;
await generateNewAddresses(addressesCount,
startIndex: addresses.length, hd: hd);
}
}
Future<BitcoinAddressRecord> generateNewAddress(
{bool isHidden = false, bitcoin.HDWallet hd}) async {
accountIndex += 1;
final _hd = hd ?? this.hd;
final address = BitcoinAddressRecord(
getAddress(index: accountIndex, hd: _hd),
index: accountIndex,
isHidden: isHidden);
addresses.add(address);
return address;
}
Future<List<BitcoinAddressRecord>> generateNewAddresses(int count,
{int startIndex = 0, bitcoin.HDWallet hd, bool isHidden = false}) async {
final list = <BitcoinAddressRecord>[];
for (var i = startIndex; i < count + startIndex; i++) {
final address = BitcoinAddressRecord(getAddress(index: i, hd: hd),
index: i, isHidden: isHidden);
list.add(address);
}
addresses.addAll(list);
return list;
}
/*Future<void> updateAddress(String address) async {
for (final addr in addresses) {
if (addr.address == address) {
await save();
break;
}
}
}*/
String getAddress({@required int index, @required bitcoin.HDWallet hd}) => '';
@override
Future<void> updateAddressesInBox() async {
try {
addressesMap.clear();
addressesMap[address] = '';
await saveAddressesInBox();
} catch (e) {
print(e.toString());
}
}
}
+16 -26
View File
@@ -1,8 +1,9 @@
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart';
import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
import 'package:cake_wallet/bitcoin/unspent_coins_info.dart';
import 'package:cake_wallet/bitcoin/litecoin_wallet_addresses.dart';
import 'package:cake_wallet/entities/transaction_priority.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/entities/wallet_info.dart';
import 'package:cake_wallet/bitcoin/electrum_wallet_snapshot.dart';
@@ -10,7 +11,6 @@ import 'package:cake_wallet/bitcoin/electrum_wallet.dart';
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
import 'package:cake_wallet/bitcoin/electrum_balance.dart';
import 'package:cake_wallet/bitcoin/litecoin_network.dart';
import 'package:cake_wallet/bitcoin/utils.dart';
part 'litecoin_wallet.g.dart';
@@ -21,6 +21,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
{@required String mnemonic,
@required String password,
@required WalletInfo walletInfo,
@required Box<UnspentCoinsInfo> unspentCoinsInfo,
List<BitcoinAddressRecord> initialAddresses,
ElectrumBalance initialBalance,
int accountIndex = 0})
@@ -28,14 +29,23 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
mnemonic: mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
networkType: litecoinNetwork,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
accountIndex: accountIndex);
initialBalance: initialBalance) {
walletAddresses = LitecoinWalletAddresses(
walletInfo,
initialAddresses: initialAddresses,
accountIndex: accountIndex,
hd: hd,
networkType: networkType,
mnemonic: mnemonic);
}
static Future<LitecoinWallet> open({
@required String name,
@required WalletInfo walletInfo,
@required Box<UnspentCoinsInfo> unspentCoinsInfo,
@required String password,
}) async {
final snp = ElectrumWallletSnapshot(name, walletInfo.type, password);
@@ -44,32 +54,12 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
mnemonic: snp.mnemonic,
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: snp.addresses,
initialBalance: snp.balance,
accountIndex: snp.accountIndex);
}
@override
String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
@override
Future<void> generateAddresses() async {
if (addresses.length < 33) {
final addressesCount = 22 - addresses.length;
await generateNewAddresses(addressesCount,
hd: hd, startIndex: addresses.length);
final changeRoot = bitcoin.HDWallet.fromSeed(
mnemonicToSeedBytes(mnemonic),
network: networkType)
.derivePath("m/0'/1");
await generateNewAddresses(11,
startIndex: 0, hd: changeRoot, isHidden: true);
}
}
@override
int feeRate(TransactionPriority priority) {
if (priority is LitecoinTransactionPriority) {
@@ -0,0 +1,54 @@
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart';
import 'package:cake_wallet/bitcoin/utils.dart';
import 'package:cake_wallet/bitcoin/bitcoin_address_record.dart';
import 'package:cake_wallet/bitcoin/electrum_wallet_addresses.dart';
import 'package:cake_wallet/entities/wallet_info.dart';
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart';
part 'litecoin_wallet_addresses.g.dart';
class LitecoinWalletAddresses = LitecoinWalletAddressesBase
with _$LitecoinWalletAddresses;
abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses
with Store {
LitecoinWalletAddressesBase(
WalletInfo walletInfo,
{@required List<BitcoinAddressRecord> initialAddresses,
int accountIndex = 0,
@required bitcoin.HDWallet hd,
@required this.networkType,
@required this.mnemonic})
: super(
walletInfo,
initialAddresses: initialAddresses,
accountIndex: accountIndex,
hd: hd);
bitcoin.NetworkType networkType;
final String mnemonic;
@override
String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
@override
Future<void> generateAddresses() async {
if (addresses.length < 33) {
final addressesCount = 22 - addresses.length;
await generateNewAddresses(addressesCount,
hd: hd, startIndex: addresses.length);
final changeRoot = bitcoin.HDWallet.fromSeed(
mnemonicToSeedBytes(mnemonic),
network: networkType)
.derivePath("m/0'/1");
await generateNewAddresses(11,
startIndex: 0, hd: changeRoot, isHidden: true);
}
}
}
+9 -4
View File
@@ -1,4 +1,5 @@
import 'dart:io';
import 'package:cake_wallet/bitcoin/unspent_coins_info.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart';
import 'package:cake_wallet/bitcoin/bitcoin_mnemonic_is_incorrect_exception.dart';
@@ -14,9 +15,10 @@ class LitecoinWalletService extends WalletService<
BitcoinNewWalletCredentials,
BitcoinRestoreWalletFromSeedCredentials,
BitcoinRestoreWalletFromWIFCredentials> {
LitecoinWalletService(this.walletInfoSource);
LitecoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
final Box<WalletInfo> walletInfoSource;
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
@override
WalletType getType() => WalletType.litecoin;
@@ -26,7 +28,8 @@ class LitecoinWalletService extends WalletService<
final wallet = LitecoinWallet(
mnemonic: await generateMnemonic(),
password: credentials.password,
walletInfo: credentials.walletInfo);
walletInfo: credentials.walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource);
await wallet.save();
await wallet.init();
@@ -43,7 +46,8 @@ class LitecoinWalletService extends WalletService<
(info) => info.id == WalletBase.idFor(name, getType()),
orElse: () => null);
final wallet = await LitecoinWalletBase.open(
password: password, name: name, walletInfo: walletInfo);
password: password, name: name, walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource);
await wallet.init();
return wallet;
}
@@ -68,7 +72,8 @@ class LitecoinWalletService extends WalletService<
final wallet = LitecoinWallet(
password: credentials.password,
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo);
walletInfo: credentials.walletInfo,
unspentCoinsInfo: unspentCoinsInfoSource);
await wallet.save();
await wallet.init();
return wallet;
+32
View File
@@ -0,0 +1,32 @@
import 'package:hive/hive.dart';
part 'unspent_coins_info.g.dart';
@HiveType(typeId: UnspentCoinsInfo.typeId)
class UnspentCoinsInfo extends HiveObject {
UnspentCoinsInfo({
this.walletId,
this.hash,
this.isFrozen,
this.isSending,
this.note});
static const typeId = 9;
static const boxName = 'Unspent';
static const boxKey = 'unspentBoxKey';
@HiveField(0)
String walletId;
@HiveField(1)
String hash;
@HiveField(2)
bool isFrozen;
@HiveField(3)
bool isSending;
@HiveField(4)
String note;
}