mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-23 03:59:23 +00:00
Merge pull request #239 from cake-tech/transactions-bug
Transactions bug
This commit is contained in:
commit
751d5066b9
12 changed files with 377 additions and 151 deletions
|
@ -1,14 +1,18 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class BitcoinAddressRecord {
|
class BitcoinAddressRecord {
|
||||||
BitcoinAddressRecord(this.address, {this.index, bool isHidden})
|
BitcoinAddressRecord(this.address,
|
||||||
: _isHidden = isHidden;
|
{this.index, this.isHidden = false, bool isUsed = false})
|
||||||
|
: _isUsed = isUsed;
|
||||||
|
|
||||||
factory BitcoinAddressRecord.fromJSON(String jsonSource) {
|
factory BitcoinAddressRecord.fromJSON(String jsonSource) {
|
||||||
final decoded = json.decode(jsonSource) as Map;
|
final decoded = json.decode(jsonSource) as Map;
|
||||||
|
|
||||||
return BitcoinAddressRecord(decoded['address'] as String,
|
return BitcoinAddressRecord(
|
||||||
index: decoded['index'] as int, isHidden: decoded['isHidden'] as bool);
|
decoded['address'] as String,
|
||||||
|
index: decoded['index'] as int,
|
||||||
|
isHidden: decoded['isHidden'] as bool ?? false,
|
||||||
|
isUsed: decoded['isUsed'] as bool ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -16,13 +20,21 @@ class BitcoinAddressRecord {
|
||||||
o is BitcoinAddressRecord && address == o.address;
|
o is BitcoinAddressRecord && address == o.address;
|
||||||
|
|
||||||
final String address;
|
final String address;
|
||||||
bool get isHidden => _isHidden ?? false;
|
final bool isHidden;
|
||||||
int index;
|
final int index;
|
||||||
final bool _isHidden;
|
bool get isUsed => _isUsed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => address.hashCode;
|
int get hashCode => address.hashCode;
|
||||||
|
|
||||||
|
bool _isUsed;
|
||||||
|
|
||||||
|
void setAsUsed() => _isUsed = true;
|
||||||
|
|
||||||
String toJSON() =>
|
String toJSON() =>
|
||||||
json.encode({'address': address, 'index': index, 'isHidden': isHidden});
|
json.encode({
|
||||||
|
'address': address,
|
||||||
|
'index': index,
|
||||||
|
'isHidden': isHidden,
|
||||||
|
'isUsed': isUsed});
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
@required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
@required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
List<BitcoinAddressRecord> initialAddresses,
|
List<BitcoinAddressRecord> initialAddresses,
|
||||||
ElectrumBalance initialBalance,
|
ElectrumBalance initialBalance,
|
||||||
int accountIndex = 0})
|
int initialRegularAddressIndex = 0,
|
||||||
|
int initialChangeAddressIndex = 0})
|
||||||
: super(
|
: super(
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
password: password,
|
password: password,
|
||||||
|
@ -34,8 +35,10 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
initialBalance: initialBalance) {
|
initialBalance: initialBalance) {
|
||||||
walletAddresses = BitcoinWalletAddresses(
|
walletAddresses = BitcoinWalletAddresses(
|
||||||
walletInfo,
|
walletInfo,
|
||||||
|
electrumClient: electrumClient,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
accountIndex: accountIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
mainHd: hd,
|
mainHd: hd,
|
||||||
sideHd: bitcoin.HDWallet.fromSeed(
|
sideHd: bitcoin.HDWallet.fromSeed(
|
||||||
mnemonicToSeedBytes(mnemonic), network: networkType)
|
mnemonicToSeedBytes(mnemonic), network: networkType)
|
||||||
|
@ -58,6 +61,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
initialAddresses: snp.addresses,
|
initialAddresses: snp.addresses,
|
||||||
initialBalance: snp.balance,
|
initialBalance: snp.balance,
|
||||||
accountIndex: snp.accountIndex);
|
initialRegularAddressIndex: snp.regularAddressIndex,
|
||||||
|
initialChangeAddressIndex: snp.changeAddressIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
|
import 'package:cw_bitcoin/electrum.dart';
|
||||||
import 'package:cw_bitcoin/utils.dart';
|
import 'package:cw_bitcoin/utils.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
||||||
|
@ -16,18 +17,21 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses
|
||||||
BitcoinWalletAddressesBase(
|
BitcoinWalletAddressesBase(
|
||||||
WalletInfo walletInfo,
|
WalletInfo walletInfo,
|
||||||
{@required List<BitcoinAddressRecord> initialAddresses,
|
{@required List<BitcoinAddressRecord> initialAddresses,
|
||||||
int accountIndex = 0,
|
int initialRegularAddressIndex = 0,
|
||||||
|
int initialChangeAddressIndex = 0,
|
||||||
|
ElectrumClient electrumClient,
|
||||||
@required bitcoin.HDWallet mainHd,
|
@required bitcoin.HDWallet mainHd,
|
||||||
@required bitcoin.HDWallet sideHd,
|
@required bitcoin.HDWallet sideHd,
|
||||||
@required this.networkType})
|
@required bitcoin.NetworkType networkType})
|
||||||
: super(
|
: super(
|
||||||
walletInfo,
|
walletInfo,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
accountIndex: accountIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
mainHd: mainHd,
|
mainHd: mainHd,
|
||||||
sideHd: sideHd);
|
sideHd: sideHd,
|
||||||
|
electrumClient: electrumClient,
|
||||||
bitcoin.NetworkType networkType;
|
networkType: networkType);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
|
String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
|
||||||
|
|
|
@ -217,23 +217,16 @@ class ElectrumClient {
|
||||||
return <String, Object>{};
|
return <String, Object>{};
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<Map<String, Object>> getTransactionExpanded(
|
Future<String> getTransactionHex(
|
||||||
{@required String hash}) async {
|
{@required String hash}) async =>
|
||||||
try {
|
call(method: 'blockchain.transaction.get', params: [hash, false])
|
||||||
final originalTx = await getTransactionRaw(hash: hash);
|
.then((dynamic result) {
|
||||||
final vins = originalTx['vin'] as List<Object>;
|
if (result is String) {
|
||||||
|
return result;
|
||||||
for (dynamic vin in vins) {
|
|
||||||
if (vin is Map<String, Object>) {
|
|
||||||
vin['tx'] = await getTransactionRaw(hash: vin['txid'] as String);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return originalTx;
|
return '';
|
||||||
} catch (_) {
|
});
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> broadcastTransaction(
|
Future<String> broadcastTransaction(
|
||||||
{@required String transactionRaw}) async =>
|
{@required String transactionRaw}) async =>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
|
import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
|
||||||
|
@ -8,6 +9,34 @@ import 'package:cw_core/transaction_info.dart';
|
||||||
import 'package:cw_core/format_amount.dart';
|
import 'package:cw_core/format_amount.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
|
String addressFromOutput(Uint8List script) {
|
||||||
|
try {
|
||||||
|
return bitcoin.P2PKH(
|
||||||
|
data: PaymentData(output: script),
|
||||||
|
network: bitcoin.bitcoin)
|
||||||
|
.data
|
||||||
|
.address;
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return bitcoin.P2WPKH(
|
||||||
|
data: PaymentData(output: script),
|
||||||
|
network: bitcoin.bitcoin)
|
||||||
|
.data
|
||||||
|
.address;
|
||||||
|
} catch(_) {}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ElectrumTransactionBundle {
|
||||||
|
ElectrumTransactionBundle(this.originalTransaction, {this.ins, this.time, this.confirmations});
|
||||||
|
final bitcoin.Transaction originalTransaction;
|
||||||
|
final List<bitcoin.Transaction> ins;
|
||||||
|
final int time;
|
||||||
|
final int confirmations;
|
||||||
|
}
|
||||||
|
|
||||||
class ElectrumTransactionInfo extends TransactionInfo {
|
class ElectrumTransactionInfo extends TransactionInfo {
|
||||||
ElectrumTransactionInfo(this.type,
|
ElectrumTransactionInfo(this.type,
|
||||||
{@required String id,
|
{@required String id,
|
||||||
|
@ -84,6 +113,49 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
||||||
confirmations: confirmations);
|
confirmations: confirmations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
factory ElectrumTransactionInfo.fromElectrumBundle(
|
||||||
|
ElectrumTransactionBundle bundle, WalletType type,
|
||||||
|
{@required Set<String> addresses, int height}) {
|
||||||
|
final date = DateTime.fromMillisecondsSinceEpoch(bundle.time * 1000);
|
||||||
|
var direction = TransactionDirection.incoming;
|
||||||
|
var amount = 0;
|
||||||
|
var inputAmount = 0;
|
||||||
|
var totalOutAmount = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < bundle.originalTransaction.ins.length; i++) {
|
||||||
|
final input = bundle.originalTransaction.ins[i];
|
||||||
|
final inputTransaction = bundle.ins[i];
|
||||||
|
final vout = input.index;
|
||||||
|
final outTransaction = inputTransaction.outs[vout];
|
||||||
|
final address = addressFromOutput(outTransaction.script);
|
||||||
|
inputAmount += outTransaction.value;
|
||||||
|
if (addresses.contains(address)) {
|
||||||
|
direction = TransactionDirection.outgoing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final out in bundle.originalTransaction.outs) {
|
||||||
|
totalOutAmount += out.value;
|
||||||
|
final address = addressFromOutput(out.script);
|
||||||
|
final addressExists = addresses.contains(address);
|
||||||
|
if ((direction == TransactionDirection.incoming && addressExists) ||
|
||||||
|
(direction == TransactionDirection.outgoing && !addressExists)) {
|
||||||
|
amount += out.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final fee = inputAmount - totalOutAmount;
|
||||||
|
return ElectrumTransactionInfo(type,
|
||||||
|
id: bundle.originalTransaction.getId(),
|
||||||
|
height: height,
|
||||||
|
isPending: false,
|
||||||
|
fee: fee,
|
||||||
|
direction: direction,
|
||||||
|
amount: amount,
|
||||||
|
date: date,
|
||||||
|
confirmations: bundle.confirmations);
|
||||||
|
}
|
||||||
|
|
||||||
factory ElectrumTransactionInfo.fromHexAndHeader(WalletType type, String hex,
|
factory ElectrumTransactionInfo.fromHexAndHeader(WalletType type, String hex,
|
||||||
{List<String> addresses, int height, int timestamp, int confirmations}) {
|
{List<String> addresses, int height, int timestamp, int confirmations}) {
|
||||||
final tx = bitcoin.Transaction.fromHex(hex);
|
final tx = bitcoin.Transaction.fromHex(hex);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
import 'dart:typed_data';
|
||||||
import 'package:cw_core/unspent_coins_info.dart';
|
import 'package:cw_core/unspent_coins_info.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
||||||
|
@ -31,6 +32,7 @@ import 'package:cw_core/sync_status.dart';
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_bitcoin/electrum.dart';
|
import 'package:cw_bitcoin/electrum.dart';
|
||||||
|
import 'package:hex/hex.dart';
|
||||||
|
|
||||||
part 'electrum_wallet.g.dart';
|
part 'electrum_wallet.g.dart';
|
||||||
|
|
||||||
|
@ -123,6 +125,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
||||||
Future<void> startSync() async {
|
Future<void> startSync() async {
|
||||||
try {
|
try {
|
||||||
syncStatus = StartingSyncStatus();
|
syncStatus = StartingSyncStatus();
|
||||||
|
await walletAddresses.discoverAddresses();
|
||||||
await updateTransactions();
|
await updateTransactions();
|
||||||
_subscribeForUpdates();
|
_subscribeForUpdates();
|
||||||
await _updateBalance();
|
await _updateBalance();
|
||||||
|
@ -204,12 +207,10 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
||||||
}
|
}
|
||||||
|
|
||||||
amount = credentialsAmount;
|
amount = credentialsAmount;
|
||||||
|
|
||||||
fee = calculateEstimatedFee(transactionCredentials.priority, amount,
|
fee = calculateEstimatedFee(transactionCredentials.priority, amount,
|
||||||
outputsCount: outputs.length + 1);
|
outputsCount: outputs.length + 1);
|
||||||
} else {
|
} else {
|
||||||
final output = outputs.first;
|
final output = outputs.first;
|
||||||
|
|
||||||
credentialsAmount = !output.sendAll
|
credentialsAmount = !output.sendAll
|
||||||
? output.formattedCryptoAmount
|
? output.formattedCryptoAmount
|
||||||
: 0;
|
: 0;
|
||||||
|
@ -221,7 +222,6 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
||||||
amount = output.sendAll || allAmount - credentialsAmount < minAmount
|
amount = output.sendAll || allAmount - credentialsAmount < minAmount
|
||||||
? allAmount
|
? allAmount
|
||||||
: credentialsAmount;
|
: credentialsAmount;
|
||||||
|
|
||||||
fee = output.sendAll || amount == allAmount
|
fee = output.sendAll || amount == allAmount
|
||||||
? allAmountFee
|
? allAmountFee
|
||||||
: calculateEstimatedFee(transactionCredentials.priority, amount);
|
: calculateEstimatedFee(transactionCredentials.priority, amount);
|
||||||
|
@ -238,7 +238,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
||||||
}
|
}
|
||||||
|
|
||||||
final txb = bitcoin.TransactionBuilder(network: networkType);
|
final txb = bitcoin.TransactionBuilder(network: networkType);
|
||||||
final changeAddress = walletAddresses.addresses.last.address;
|
final changeAddress = await walletAddresses.getChangeAddress();
|
||||||
var leftAmount = totalAmount;
|
var leftAmount = totalAmount;
|
||||||
var totalInputAmount = 0;
|
var totalInputAmount = 0;
|
||||||
|
|
||||||
|
@ -265,7 +265,6 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
||||||
}
|
}
|
||||||
|
|
||||||
txb.setVersion(1);
|
txb.setVersion(1);
|
||||||
|
|
||||||
inputs.forEach((input) {
|
inputs.forEach((input) {
|
||||||
if (input.isP2wpkh) {
|
if (input.isP2wpkh) {
|
||||||
final p2wpkh = bitcoin
|
final p2wpkh = bitcoin
|
||||||
|
@ -286,11 +285,9 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
||||||
final outputAmount = hasMultiDestination
|
final outputAmount = hasMultiDestination
|
||||||
? item.formattedCryptoAmount
|
? item.formattedCryptoAmount
|
||||||
: amount;
|
: amount;
|
||||||
|
|
||||||
final outputAddress = item.isParsedAddress
|
final outputAddress = item.isParsedAddress
|
||||||
? item.extractedAddress
|
? item.extractedAddress
|
||||||
: item.address;
|
: item.address;
|
||||||
|
|
||||||
txb.addOutput(
|
txb.addOutput(
|
||||||
addressToOutputScript(outputAddress, networkType),
|
addressToOutputScript(outputAddress, networkType),
|
||||||
outputAmount);
|
outputAmount);
|
||||||
|
@ -326,7 +323,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
||||||
|
|
||||||
String toJSON() => json.encode({
|
String toJSON() => json.encode({
|
||||||
'mnemonic': mnemonic,
|
'mnemonic': mnemonic,
|
||||||
'account_index': walletAddresses.accountIndex.toString(),
|
'account_index': walletAddresses.currentReceiveAddressIndex.toString(),
|
||||||
|
'change_address_index': walletAddresses.currentChangeAddressIndex.toString(),
|
||||||
'addresses': walletAddresses.addresses.map((addr) => addr.toJSON()).toList(),
|
'addresses': walletAddresses.addresses.map((addr) => addr.toJSON()).toList(),
|
||||||
'balance': balance?.toJSON()
|
'balance': balance?.toJSON()
|
||||||
});
|
});
|
||||||
|
@ -479,11 +477,35 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<ElectrumTransactionBundle> getTransactionExpanded(
|
||||||
|
{@required String hash, @required int height}) async {
|
||||||
|
final verboseTransaction = await electrumClient.getTransactionRaw(hash: hash);
|
||||||
|
final transactionHex = verboseTransaction['hex'] as String;
|
||||||
|
final original = bitcoin.Transaction.fromHex(transactionHex);
|
||||||
|
final ins = <bitcoin.Transaction>[];
|
||||||
|
final time = verboseTransaction['time'] as int;
|
||||||
|
final confirmations = verboseTransaction['time'] as int;
|
||||||
|
|
||||||
|
for (final vin in original.ins) {
|
||||||
|
final id = HEX.encode(vin.hash.reversed.toList());
|
||||||
|
final txHex = await electrumClient.getTransactionHex(hash: id);
|
||||||
|
final tx = bitcoin.Transaction.fromHex(txHex);
|
||||||
|
ins.add(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ElectrumTransactionBundle(
|
||||||
|
original,
|
||||||
|
ins: ins,
|
||||||
|
time: time,
|
||||||
|
confirmations: confirmations);
|
||||||
|
}
|
||||||
|
|
||||||
Future<ElectrumTransactionInfo> fetchTransactionInfo(
|
Future<ElectrumTransactionInfo> fetchTransactionInfo(
|
||||||
{@required String hash, @required int height}) async {
|
{@required String hash, @required int height}) async {
|
||||||
final tx = await electrumClient.getTransactionExpanded(hash: hash);
|
final tx = await getTransactionExpanded(hash: hash, height: height);
|
||||||
return ElectrumTransactionInfo.fromElectrumVerbose(tx, walletInfo.type,
|
final addresses = walletAddresses.addresses.map((addr) => addr.address).toSet();
|
||||||
height: height, addresses: walletAddresses.addresses);
|
return ElectrumTransactionInfo.fromElectrumBundle(
|
||||||
|
tx,walletInfo.type, addresses: addresses, height: height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -524,7 +546,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
||||||
scriptHashes.forEach((sh) async {
|
scriptHashes.forEach((sh) async {
|
||||||
await _scripthashesUpdateSubject[sh]?.close();
|
await _scripthashesUpdateSubject[sh]?.close();
|
||||||
_scripthashesUpdateSubject[sh] = electrumClient.scripthashUpdate(sh);
|
_scripthashesUpdateSubject[sh] = electrumClient.scripthashUpdate(sh);
|
||||||
_scripthashesUpdateSubject[sh].listen((event) async {
|
_scripthashesUpdateSubject[sh]?.listen((event) async {
|
||||||
try {
|
try {
|
||||||
await _updateBalance();
|
await _updateBalance();
|
||||||
await updateUnspent();
|
await updateUnspent();
|
||||||
|
@ -537,16 +559,34 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ElectrumBalance> _fetchBalances() async {
|
Future<ElectrumBalance> _fetchBalances() async {
|
||||||
final balances = await Future.wait(
|
final addresses = walletAddresses.addresses.toList();
|
||||||
scriptHashes.map((sh) => electrumClient.getBalance(sh)));
|
final balanceFutures = <Future<Map<String, dynamic>>>[];
|
||||||
final balance = balances.fold(
|
|
||||||
ElectrumBalance(confirmed: 0, unconfirmed: 0),
|
|
||||||
(ElectrumBalance acc, val) => ElectrumBalance(
|
|
||||||
confirmed: (val['confirmed'] as int ?? 0) + (acc.confirmed ?? 0),
|
|
||||||
unconfirmed:
|
|
||||||
(val['unconfirmed'] as int ?? 0) + (acc.unconfirmed ?? 0)));
|
|
||||||
|
|
||||||
return balance;
|
for (var i = 0; i < addresses.length; i++) {
|
||||||
|
final addressRecord = addresses[i];
|
||||||
|
final sh = scriptHash(addressRecord.address, networkType: networkType);
|
||||||
|
final balanceFuture = electrumClient.getBalance(sh);
|
||||||
|
balanceFutures.add(balanceFuture);
|
||||||
|
}
|
||||||
|
|
||||||
|
final balances = await Future.wait(balanceFutures);
|
||||||
|
var totalConfirmed = 0;
|
||||||
|
var totalUnconfirmed = 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < balances.length; i++) {
|
||||||
|
final addressRecord = addresses[i];
|
||||||
|
final balance = balances[i];
|
||||||
|
final confirmed = balance['confirmed'] as int ?? 0;
|
||||||
|
final unconfirmed = balance['unconfirmed'] as int ?? 0;
|
||||||
|
totalConfirmed += confirmed;
|
||||||
|
totalUnconfirmed += unconfirmed;
|
||||||
|
|
||||||
|
if (confirmed > 0 || unconfirmed > 0) {
|
||||||
|
addressRecord.setAsUsed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ElectrumBalance(confirmed: totalConfirmed, unconfirmed: totalUnconfirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _updateBalance() async {
|
Future<void> _updateBalance() async {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
|
import 'package:cw_bitcoin/electrum.dart';
|
||||||
|
import 'package:cw_bitcoin/script_hash.dart';
|
||||||
import 'package:cw_core/wallet_addresses.dart';
|
import 'package:cw_core/wallet_addresses.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -14,120 +16,118 @@ class ElectrumWalletAddresses = ElectrumWalletAddressesBase
|
||||||
abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
ElectrumWalletAddressesBase(WalletInfo walletInfo,
|
ElectrumWalletAddressesBase(WalletInfo walletInfo,
|
||||||
{@required List<BitcoinAddressRecord> initialAddresses,
|
{@required List<BitcoinAddressRecord> initialAddresses,
|
||||||
int accountIndex = 0,
|
int initialRegularAddressIndex = 0,
|
||||||
|
int initialChangeAddressIndex = 0,
|
||||||
this.mainHd,
|
this.mainHd,
|
||||||
this.sideHd})
|
this.sideHd,
|
||||||
|
this.electrumClient,
|
||||||
|
this.networkType})
|
||||||
: super(walletInfo) {
|
: super(walletInfo) {
|
||||||
this.accountIndex = accountIndex;
|
currentReceiveAddressIndex = initialRegularAddressIndex;
|
||||||
|
currentChangeAddressIndex = initialChangeAddressIndex;
|
||||||
addresses = ObservableList<BitcoinAddressRecord>.of(
|
addresses = ObservableList<BitcoinAddressRecord>.of(
|
||||||
(initialAddresses ?? []).toSet());
|
(initialAddresses ?? []).toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
static const regularAddressesCount = 22;
|
static const defaultReceiveAddressesCount = 22;
|
||||||
static const hiddenAddressesCount = 17;
|
static const defaultChangeAddressesCount = 17;
|
||||||
|
static const gap = 20;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@observable
|
@observable
|
||||||
String address;
|
String address;
|
||||||
|
|
||||||
|
int currentReceiveAddressIndex;
|
||||||
|
int currentChangeAddressIndex;
|
||||||
|
ElectrumClient electrumClient;
|
||||||
|
bitcoin.NetworkType networkType;
|
||||||
bitcoin.HDWallet mainHd;
|
bitcoin.HDWallet mainHd;
|
||||||
bitcoin.HDWallet sideHd;
|
bitcoin.HDWallet sideHd;
|
||||||
|
|
||||||
ObservableList<BitcoinAddressRecord> addresses;
|
ObservableList<BitcoinAddressRecord> addresses;
|
||||||
|
|
||||||
List<BitcoinAddressRecord> get availableAddresses => addresses
|
List<BitcoinAddressRecord> get receiveAddresses => addresses
|
||||||
.where((addr) => !addr.isHidden)
|
.where((addr) => !addr.isHidden && !addr.isUsed)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
int accountIndex;
|
List<BitcoinAddressRecord> get changeAddresses => addresses
|
||||||
|
.where((addr) => addr.isHidden && !addr.isUsed)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
Future<void> discoverAddresses() async {
|
||||||
|
await _discoverAddresses(mainHd, false);
|
||||||
|
await _discoverAddresses(sideHd, true);
|
||||||
|
await updateAddressesInBox();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
await generateAddresses();
|
await _generateInitialAddresses();
|
||||||
final _availableAddresses = availableAddresses;
|
|
||||||
|
|
||||||
if (accountIndex >= _availableAddresses.length) {
|
if (receiveAddresses.isEmpty) {
|
||||||
accountIndex = 0;
|
final count = currentReceiveAddressIndex + gap;
|
||||||
|
final newAddresses = await _createNewAddresses(
|
||||||
|
count,
|
||||||
|
hd: mainHd,
|
||||||
|
startIndex: currentReceiveAddressIndex,
|
||||||
|
isHidden: false);
|
||||||
|
_addAddresses(newAddresses);
|
||||||
|
} else if (currentReceiveAddressIndex >= receiveAddresses.length) {
|
||||||
|
currentReceiveAddressIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
address = _availableAddresses[accountIndex].address;
|
address = receiveAddresses[currentReceiveAddressIndex].address;
|
||||||
await updateAddressesInBox();
|
await updateAddressesInBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> nextAddress() async {
|
Future<void> nextReceiveAddress() async {
|
||||||
accountIndex += 1;
|
if (receiveAddresses.isEmpty) {
|
||||||
final _availableAddresses = availableAddresses;
|
final count = currentReceiveAddressIndex + gap;
|
||||||
|
final newAddresses = await _createNewAddresses(
|
||||||
if (accountIndex >= _availableAddresses.length) {
|
count,
|
||||||
accountIndex = 0;
|
hd: sideHd,
|
||||||
|
startIndex: currentReceiveAddressIndex,
|
||||||
|
isHidden: false);
|
||||||
|
_addAddresses(newAddresses);
|
||||||
|
} else if (currentReceiveAddressIndex >= receiveAddresses.length) {
|
||||||
|
currentReceiveAddressIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
address = _availableAddresses[accountIndex].address;
|
address = receiveAddresses[currentReceiveAddressIndex].address;
|
||||||
|
currentReceiveAddressIndex += 1;
|
||||||
await updateAddressesInBox();
|
await updateAddressesInBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> generateAddresses() async {
|
@action
|
||||||
final regularAddresses = <BitcoinAddressRecord>[];
|
Future<String> getChangeAddress() async {
|
||||||
final hiddenAddresses = <BitcoinAddressRecord>[];
|
if (changeAddresses.isEmpty) {
|
||||||
|
final count = currentChangeAddressIndex + gap;
|
||||||
addresses.forEach((addr) {
|
final newAddresses = await _createNewAddresses(
|
||||||
if (addr.isHidden) {
|
count,
|
||||||
hiddenAddresses.add(addr);
|
startIndex: currentChangeAddressIndex,
|
||||||
return;
|
isHidden: true);
|
||||||
}
|
_addAddresses(newAddresses);
|
||||||
|
} else if (currentChangeAddressIndex >= changeAddresses.length) {
|
||||||
regularAddresses.add(addr);
|
currentChangeAddressIndex = 0;
|
||||||
});
|
|
||||||
|
|
||||||
if (regularAddresses.length < regularAddressesCount) {
|
|
||||||
final addressesCount = regularAddressesCount - regularAddresses.length;
|
|
||||||
await generateNewAddresses(addressesCount,
|
|
||||||
startIndex: regularAddresses.length, hd: mainHd, isHidden: false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hiddenAddresses.length < hiddenAddressesCount) {
|
|
||||||
final addressesCount = hiddenAddressesCount - hiddenAddresses.length;
|
final address = changeAddresses[currentChangeAddressIndex].address;
|
||||||
await generateNewAddresses(addressesCount,
|
currentChangeAddressIndex += 1;
|
||||||
startIndex: hiddenAddresses.length, hd: sideHd, isHidden: true);
|
return address;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<BitcoinAddressRecord> generateNewAddress(
|
Future<BitcoinAddressRecord> generateNewAddress(
|
||||||
{bool isHidden = false, bitcoin.HDWallet hd}) async {
|
{bool isHidden = false, bitcoin.HDWallet hd}) async {
|
||||||
accountIndex += 1;
|
currentReceiveAddressIndex += 1;
|
||||||
final address = BitcoinAddressRecord(
|
final address = BitcoinAddressRecord(
|
||||||
getAddress(index: accountIndex, hd: hd),
|
getAddress(index: currentReceiveAddressIndex, hd: hd),
|
||||||
index: accountIndex,
|
index: currentReceiveAddressIndex,
|
||||||
isHidden: isHidden);
|
isHidden: isHidden);
|
||||||
addresses.add(address);
|
addresses.add(address);
|
||||||
return 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}) => '';
|
String getAddress({@required int index, @required bitcoin.HDWallet hd}) => '';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -135,7 +135,6 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
try {
|
try {
|
||||||
addressesMap.clear();
|
addressesMap.clear();
|
||||||
addressesMap[address] = '';
|
addressesMap[address] = '';
|
||||||
|
|
||||||
await saveAddressesInBox();
|
await saveAddressesInBox();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e.toString());
|
print(e.toString());
|
||||||
|
@ -155,4 +154,107 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
|
|
||||||
address = availableAddresses[random.nextInt(availableAddresses.length)].address;
|
address = availableAddresses[random.nextInt(availableAddresses.length)].address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _discoverAddresses(bitcoin.HDWallet hd, bool isHidden) async {
|
||||||
|
var hasAddrUse = true;
|
||||||
|
List<BitcoinAddressRecord> addrs;
|
||||||
|
|
||||||
|
if (addresses.isNotEmpty) {
|
||||||
|
addrs = addresses
|
||||||
|
.where((addr) => addr.isHidden == isHidden)
|
||||||
|
.toList();
|
||||||
|
} else {
|
||||||
|
addrs = await _createNewAddresses(
|
||||||
|
isHidden
|
||||||
|
? defaultChangeAddressesCount
|
||||||
|
: defaultReceiveAddressesCount,
|
||||||
|
startIndex: 0,
|
||||||
|
hd: hd,
|
||||||
|
isHidden: isHidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(hasAddrUse) {
|
||||||
|
final addr = addrs.last.address;
|
||||||
|
hasAddrUse = await _validateAddressUsing(addr);
|
||||||
|
|
||||||
|
if (!hasAddrUse) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
final start = addrs.length;
|
||||||
|
final count = start + gap;
|
||||||
|
final batch = await _createNewAddresses(
|
||||||
|
count,
|
||||||
|
startIndex: start,
|
||||||
|
hd: hd,
|
||||||
|
isHidden: isHidden);
|
||||||
|
addrs.addAll(batch);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addresses.length < addrs.length) {
|
||||||
|
_addAddresses(addrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _generateInitialAddresses() async {
|
||||||
|
var countOfReceiveAddresses = 0;
|
||||||
|
var countOfHiddenAddresses = 0;
|
||||||
|
|
||||||
|
addresses.forEach((addr) {
|
||||||
|
if (addr.isHidden) {
|
||||||
|
countOfHiddenAddresses += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
countOfReceiveAddresses += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (countOfReceiveAddresses < defaultReceiveAddressesCount) {
|
||||||
|
final addressesCount = defaultReceiveAddressesCount - countOfReceiveAddresses;
|
||||||
|
final newAddresses = await _createNewAddresses(
|
||||||
|
addressesCount,
|
||||||
|
startIndex: countOfReceiveAddresses,
|
||||||
|
hd: mainHd,
|
||||||
|
isHidden: false);
|
||||||
|
addresses.addAll(newAddresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (countOfHiddenAddresses < defaultChangeAddressesCount) {
|
||||||
|
final addressesCount = defaultChangeAddressesCount - countOfHiddenAddresses;
|
||||||
|
final newAddresses = await _createNewAddresses(
|
||||||
|
addressesCount,
|
||||||
|
startIndex: countOfHiddenAddresses,
|
||||||
|
hd: sideHd,
|
||||||
|
isHidden: true);
|
||||||
|
addresses.addAll(newAddresses);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<BitcoinAddressRecord>> _createNewAddresses(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _addAddresses(Iterable<BitcoinAddressRecord> addresses) {
|
||||||
|
final addressesSet = this.addresses.toSet();
|
||||||
|
addressesSet.addAll(addresses);
|
||||||
|
this.addresses.removeRange(0, this.addresses.length);
|
||||||
|
this.addresses.addAll(addressesSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _validateAddressUsing(String address) async {
|
||||||
|
final sh = scriptHash(address, networkType: networkType);
|
||||||
|
final balance = await electrumClient.getBalance(sh);
|
||||||
|
return balance.isEmpty;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -15,7 +15,8 @@ class ElectrumWallletSnapshot {
|
||||||
String mnemonic;
|
String mnemonic;
|
||||||
List<BitcoinAddressRecord> addresses;
|
List<BitcoinAddressRecord> addresses;
|
||||||
ElectrumBalance balance;
|
ElectrumBalance balance;
|
||||||
int accountIndex;
|
int regularAddressIndex;
|
||||||
|
int changeAddressIndex;
|
||||||
|
|
||||||
Future<void> load() async {
|
Future<void> load() async {
|
||||||
try {
|
try {
|
||||||
|
@ -30,10 +31,12 @@ class ElectrumWallletSnapshot {
|
||||||
.toList();
|
.toList();
|
||||||
balance = ElectrumBalance.fromJSON(data['balance'] as String) ??
|
balance = ElectrumBalance.fromJSON(data['balance'] as String) ??
|
||||||
ElectrumBalance(confirmed: 0, unconfirmed: 0);
|
ElectrumBalance(confirmed: 0, unconfirmed: 0);
|
||||||
accountIndex = 0;
|
regularAddressIndex = 0;
|
||||||
|
changeAddressIndex = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
accountIndex = int.parse(data['account_index'] as String);
|
regularAddressIndex = int.parse(data['account_index'] as String);
|
||||||
|
changeAddressIndex = int.parse(data['change_address_index'] as String);
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
|
|
|
@ -26,7 +26,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
@required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
@required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
List<BitcoinAddressRecord> initialAddresses,
|
List<BitcoinAddressRecord> initialAddresses,
|
||||||
ElectrumBalance initialBalance,
|
ElectrumBalance initialBalance,
|
||||||
int accountIndex = 0})
|
int initialRegularAddressIndex = 0,
|
||||||
|
int initialChangeAddressIndex = 0})
|
||||||
: super(
|
: super(
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
password: password,
|
password: password,
|
||||||
|
@ -37,8 +38,10 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
initialBalance: initialBalance) {
|
initialBalance: initialBalance) {
|
||||||
walletAddresses = LitecoinWalletAddresses(
|
walletAddresses = LitecoinWalletAddresses(
|
||||||
walletInfo,
|
walletInfo,
|
||||||
|
electrumClient: electrumClient,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
accountIndex: accountIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
mainHd: hd,
|
mainHd: hd,
|
||||||
sideHd: bitcoin.HDWallet
|
sideHd: bitcoin.HDWallet
|
||||||
.fromSeed(mnemonicToSeedBytes(mnemonic), network: networkType)
|
.fromSeed(mnemonicToSeedBytes(mnemonic), network: networkType)
|
||||||
|
@ -61,7 +64,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
initialAddresses: snp.addresses,
|
initialAddresses: snp.addresses,
|
||||||
initialBalance: snp.balance,
|
initialBalance: snp.balance,
|
||||||
accountIndex: snp.accountIndex);
|
initialRegularAddressIndex: snp.regularAddressIndex,
|
||||||
|
initialChangeAddressIndex: snp.changeAddressIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||||
|
import 'package:cw_bitcoin/electrum.dart';
|
||||||
import 'package:cw_bitcoin/utils.dart';
|
import 'package:cw_bitcoin/utils.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
||||||
|
@ -16,32 +17,23 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses
|
||||||
LitecoinWalletAddressesBase(
|
LitecoinWalletAddressesBase(
|
||||||
WalletInfo walletInfo,
|
WalletInfo walletInfo,
|
||||||
{@required List<BitcoinAddressRecord> initialAddresses,
|
{@required List<BitcoinAddressRecord> initialAddresses,
|
||||||
int accountIndex = 0,
|
int initialRegularAddressIndex = 0,
|
||||||
|
int initialChangeAddressIndex = 0,
|
||||||
|
ElectrumClient electrumClient,
|
||||||
@required bitcoin.HDWallet mainHd,
|
@required bitcoin.HDWallet mainHd,
|
||||||
@required bitcoin.HDWallet sideHd,
|
@required bitcoin.HDWallet sideHd,
|
||||||
@required this.networkType})
|
@required bitcoin.NetworkType networkType})
|
||||||
: super(
|
: super(
|
||||||
walletInfo,
|
walletInfo,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
accountIndex: accountIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
mainHd: mainHd,
|
mainHd: mainHd,
|
||||||
sideHd: sideHd);
|
sideHd: sideHd,
|
||||||
|
electrumClient: electrumClient,
|
||||||
bitcoin.NetworkType networkType;
|
networkType: networkType);
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
|
String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
|
||||||
generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
|
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: mainHd, startIndex: addresses.length);
|
|
||||||
await generateNewAddresses(11,
|
|
||||||
startIndex: 0, hd: sideHd, isHidden: true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -57,7 +57,7 @@ class CWBitcoin extends Bitcoin {
|
||||||
@override
|
@override
|
||||||
Future<void> nextAddress(Object wallet) {
|
Future<void> nextAddress(Object wallet) {
|
||||||
final bitcoinWallet = wallet as ElectrumWallet;
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
bitcoinWallet.walletAddresses.nextAddress();
|
bitcoinWallet.walletAddresses.nextReceiveAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -17,8 +17,8 @@ MONERO_COM_BUILD_NUMBER=6
|
||||||
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
|
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
|
||||||
|
|
||||||
CAKEWALLET_NAME="Cake Wallet"
|
CAKEWALLET_NAME="Cake Wallet"
|
||||||
CAKEWALLET_VERSION="4.3.1"
|
CAKEWALLET_VERSION="4.3.4"
|
||||||
CAKEWALLET_BUILD_NUMBER=73
|
CAKEWALLET_BUILD_NUMBER=75
|
||||||
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
|
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
|
||||||
|
|
||||||
if ! [[ " ${TYPES[*]} " =~ " ${APP_IOS_TYPE} " ]]; then
|
if ! [[ " ${TYPES[*]} " =~ " ${APP_IOS_TYPE} " ]]; then
|
||||||
|
|
Loading…
Reference in a new issue