mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-20 17:54:41 +00:00
fix: unspents remaining, check spent silent payment during scanning
This commit is contained in:
parent
c472ef0e07
commit
2d9158d552
6 changed files with 165 additions and 133 deletions
|
@ -4,7 +4,9 @@ import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
|
||||||
|
|
||||||
String addressFromOutput(Uint8List script, bitcoin.NetworkType networkType) {
|
String addressFromOutput(Uint8List script, bitcoin.NetworkType networkType) {
|
||||||
try {
|
try {
|
||||||
return bitcoin.P2PKH(data: PaymentData(output: script), network: networkType).data.address!;
|
return bitcoin.P2pkhAddress(
|
||||||
|
scriptPubKey: bitcoin.Script.fromRaw(byteData: script), networkType: networkType)
|
||||||
|
.address;
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
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:cw_bitcoin/address_from_output.dart';
|
import 'package:cw_bitcoin/address_from_output.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
||||||
|
@ -148,9 +147,10 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
||||||
if (addresses != null) {
|
if (addresses != null) {
|
||||||
tx.outs.forEach((out) {
|
tx.outs.forEach((out) {
|
||||||
try {
|
try {
|
||||||
final p2pkh =
|
final p2pkh = bitcoin.P2pkhAddress(
|
||||||
bitcoin.P2PKH(data: PaymentData(output: out.script), network: bitcoin.bitcoin);
|
scriptPubKey: bitcoin.Script.fromRaw(byteData: out.script),
|
||||||
exist = addresses.contains(p2pkh.data.address);
|
networkType: bitcoin.bitcoin);
|
||||||
|
exist = addresses.contains(p2pkh.address);
|
||||||
|
|
||||||
if (exist) {
|
if (exist) {
|
||||||
amount += out.value!;
|
amount += out.value!;
|
||||||
|
@ -236,4 +236,8 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
||||||
m['unspent'] = unspent?.toJson() ?? <String, dynamic>{};
|
m['unspent'] = unspent?.toJson() ?? <String, dynamic>{};
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toString() {
|
||||||
|
return 'ElectrumTransactionInfo(id: $id, height: $height, amount: $amount, fee: $fee, direction: $direction, date: $date, isPending: $isPending, confirmations: $confirmations, to: $to, unspent: $unspent)';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -328,9 +328,7 @@ abstract class ElectrumWalletBase
|
||||||
throw BitcoinTransactionWrongBalanceException(currency);
|
throw BitcoinTransactionWrongBalanceException(currency);
|
||||||
}
|
}
|
||||||
|
|
||||||
amount = output.sendAll || allAmount - credentialsAmount < minAmount
|
amount = output.sendAll ? allAmount : credentialsAmount;
|
||||||
? allAmount
|
|
||||||
: credentialsAmount;
|
|
||||||
|
|
||||||
if (output.sendAll || amount == allAmount) {
|
if (output.sendAll || amount == allAmount) {
|
||||||
fee = allAmountFee;
|
fee = allAmountFee;
|
||||||
|
@ -360,9 +358,8 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
List<bitcoin.PrivateKeyInfo> inputPrivKeys = [];
|
List<bitcoin.PrivateKeyInfo> inputPrivKeys = [];
|
||||||
List<bitcoin.Outpoint> outpoints = [];
|
List<bitcoin.Outpoint> outpoints = [];
|
||||||
|
List<int> amounts = [];
|
||||||
List<int>? amounts;
|
List<Uint8List> scriptPubKeys = [];
|
||||||
List<Uint8List>? scriptPubKeys;
|
|
||||||
|
|
||||||
final curve = bitcoin.getSecp256k1();
|
final curve = bitcoin.getSecp256k1();
|
||||||
|
|
||||||
|
@ -371,41 +368,28 @@ abstract class ElectrumWalletBase
|
||||||
leftAmount = leftAmount - utx.value;
|
leftAmount = leftAmount - utx.value;
|
||||||
totalInputAmount += utx.value;
|
totalInputAmount += utx.value;
|
||||||
|
|
||||||
if (amounts == null) {
|
|
||||||
amounts = [];
|
|
||||||
}
|
|
||||||
amounts.add(utx.value);
|
amounts.add(utx.value);
|
||||||
|
|
||||||
outpoints.add(bitcoin.Outpoint(txid: utx.hash, index: utx.vout));
|
outpoints.add(bitcoin.Outpoint(txid: utx.hash, index: utx.vout));
|
||||||
|
|
||||||
if (utx.bitcoinAddressRecord.silentPaymentTweak != null) {
|
Uint8List? script;
|
||||||
|
bitcoin.ECPair? keyPair;
|
||||||
|
|
||||||
// https://github.com/bitcoin/bips/blob/c55f80c53c98642357712c1839cfdc0551d531c4/bip-0352.mediawiki#user-content-Spending
|
// https://github.com/bitcoin/bips/blob/c55f80c53c98642357712c1839cfdc0551d531c4/bip-0352.mediawiki#user-content-Spending
|
||||||
|
if (utx.bitcoinAddressRecord.silentPaymentTweak != null) {
|
||||||
final d = bitcoin.PrivateKey.fromHex(
|
final d = bitcoin.PrivateKey.fromHex(
|
||||||
curve, walletAddresses.primarySilentAddress!.spendPrivkey.toCompressedHex())
|
curve, walletAddresses.primarySilentAddress!.spendPrivkey.toCompressedHex())
|
||||||
.tweakAdd(utx.bitcoinAddressRecord.silentPaymentTweak!.fromHex.bigint)!;
|
.tweakAdd(utx.bitcoinAddressRecord.silentPaymentTweak!.fromHex.bigint)!;
|
||||||
|
|
||||||
inputPrivKeys.add(bitcoin.PrivateKeyInfo(d, utx.type == bitcoin.AddressType.p2tr));
|
inputPrivKeys.add(bitcoin.PrivateKeyInfo(d, true));
|
||||||
|
|
||||||
final p2tr = bitcoin.P2trAddress(pubkey: d.publicKey.toHex(), network: networkType);
|
keyPair = bitcoin.ECPair.fromPrivateKey(d.toCompressedHex().fromHex,
|
||||||
|
|
||||||
bitcoin.ECPair keyPair = bitcoin.ECPair.fromPrivateKey(d.toCompressedHex().fromHex,
|
|
||||||
compressed: true, network: networkType);
|
compressed: true, network: networkType);
|
||||||
|
script = bitcoin.P2trAddress(pubkey: d.publicKey.toHex(), networkType: networkType)
|
||||||
final script = p2tr.toScriptPubKey().toBytes();
|
.scriptPubkey
|
||||||
|
.toBytes();
|
||||||
txb.addInput(utx.hash, utx.vout, null, script, keyPair, utx.value);
|
} else if ((utx.type == bitcoin.AddressType.p2tr) ||
|
||||||
|
|
||||||
if (scriptPubKeys == null) {
|
|
||||||
scriptPubKeys = [];
|
|
||||||
}
|
|
||||||
scriptPubKeys.add(script);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((utx.type == bitcoin.AddressType.p2tr) ||
|
|
||||||
bitcoin.P2trAddress.REGEX.hasMatch(utx.address)) {
|
bitcoin.P2trAddress.REGEX.hasMatch(utx.address)) {
|
||||||
bitcoin.ECPair keyPair = generateKeyPair(
|
keyPair = generateKeyPair(
|
||||||
hd: utx.bitcoinAddressRecord.isHidden
|
hd: utx.bitcoinAddressRecord.isHidden
|
||||||
? walletAddresses.sideHd
|
? walletAddresses.sideHd
|
||||||
: walletAddresses.mainHd,
|
: walletAddresses.mainHd,
|
||||||
|
@ -413,30 +397,21 @@ abstract class ElectrumWalletBase
|
||||||
network: networkType);
|
network: networkType);
|
||||||
|
|
||||||
inputPrivKeys.add(bitcoin.PrivateKeyInfo(
|
inputPrivKeys.add(bitcoin.PrivateKeyInfo(
|
||||||
bitcoin.PrivateKey.fromHex(curve, keyPair.privateKey!.hex),
|
bitcoin.PrivateKey.fromHex(curve, keyPair.privateKey!.hex), true));
|
||||||
utx.type == bitcoin.AddressType.p2tr));
|
|
||||||
|
|
||||||
final p2tr = bitcoin.P2trAddress(pubkey: keyPair.publicKey.hex, network: networkType);
|
script = bitcoin.P2trAddress(pubkey: keyPair.publicKey.hex, networkType: networkType)
|
||||||
final script = p2tr.toScriptPubKey().toBytes();
|
.scriptPubkey
|
||||||
|
.toBytes();
|
||||||
txb.addInput(utx.hash, utx.vout, null, script, keyPair, utx.value);
|
} else {
|
||||||
|
keyPair = generateKeyPair(
|
||||||
if (scriptPubKeys == null) {
|
hd: utx.bitcoinAddressRecord.isHidden
|
||||||
scriptPubKeys = [];
|
? walletAddresses.sideHd
|
||||||
}
|
: walletAddresses.mainHd,
|
||||||
scriptPubKeys.add(script);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bitcoin.ECPair keyPair = generateKeyPair(
|
|
||||||
hd: utx.bitcoinAddressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd,
|
|
||||||
index: utx.bitcoinAddressRecord.index,
|
index: utx.bitcoinAddressRecord.index,
|
||||||
network: networkType);
|
network: networkType);
|
||||||
|
|
||||||
inputPrivKeys.add(bitcoin.PrivateKeyInfo(
|
inputPrivKeys.add(bitcoin.PrivateKeyInfo(
|
||||||
bitcoin.PrivateKey.fromHex(curve, keyPair.privateKey!.hex),
|
bitcoin.PrivateKey.fromHex(curve, keyPair.privateKey!.hex), false));
|
||||||
utx.type == bitcoin.AddressType.p2tr));
|
|
||||||
|
|
||||||
if (utx.isP2wpkh) {
|
if (utx.isP2wpkh) {
|
||||||
final p2wpkh = bitcoin
|
final p2wpkh = bitcoin
|
||||||
|
@ -449,19 +424,13 @@ abstract class ElectrumWalletBase
|
||||||
network: networkType)
|
network: networkType)
|
||||||
.data;
|
.data;
|
||||||
|
|
||||||
final script = p2wpkh.output;
|
script = p2wpkh.output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
txb.addInput(utx.hash, utx.vout, null, script, keyPair, utx.value);
|
txb.addInput(utx.hash, utx.vout, null, script, keyPair, utx.value);
|
||||||
|
|
||||||
if (scriptPubKeys == null) {
|
|
||||||
scriptPubKeys = [];
|
|
||||||
}
|
|
||||||
if (script != null) scriptPubKeys.add(script);
|
if (script != null) scriptPubKeys.add(script);
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
txb.addInput(utx.hash, utx.vout, null, null, keyPair, utx.value);
|
|
||||||
|
|
||||||
if (leftAmount <= 0) {
|
if (leftAmount <= 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -500,21 +469,21 @@ abstract class ElectrumWalletBase
|
||||||
txb.addOutput(
|
txb.addOutput(
|
||||||
bitcoin.P2trAddress(
|
bitcoin.P2trAddress(
|
||||||
program: bitcoin.ECPublic.fromHex(output.$1.toHex()).toTapPoint(),
|
program: bitcoin.ECPublic.fromHex(output.$1.toHex()).toTapPoint(),
|
||||||
network: networkType)
|
networkType: networkType)
|
||||||
.toScriptPubKey()
|
.scriptPubkey
|
||||||
.toBytes(),
|
.toBytes(),
|
||||||
output.$2);
|
output.$2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
final estimatedSize = estimatedTransactionSize(inputs.length, outputs.length + 1);
|
final estimatedSize = estimatedTransactionSize(txb.inputs.length, outputs.length + 1);
|
||||||
var feeAmount = 0;
|
var feeAmount = 0;
|
||||||
|
|
||||||
if (transactionCredentials.feeRate != null) {
|
if (transactionCredentials.feeRate != null) {
|
||||||
feeAmount = transactionCredentials.feeRate! * estimatedSize;
|
feeAmount = transactionCredentials.feeRate! * estimatedSize;
|
||||||
} else {
|
} else {
|
||||||
feeAmount = feeRate(transactionCredentials.priority!) * estimatedSize;
|
feeAmount = (feeRate(transactionCredentials.priority!) * estimatedSize).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
final changeValue = totalInputAmount - amount - feeAmount;
|
final changeValue = totalInputAmount - amount - feeAmount;
|
||||||
|
@ -523,15 +492,25 @@ abstract class ElectrumWalletBase
|
||||||
txb.addOutput(changeAddress, changeValue);
|
txb.addOutput(changeAddress, changeValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < inputs.length; i++) {
|
for (var i = 0; i < txb.inputs.length; i++) {
|
||||||
txb.sign(vin: i, amounts: amounts, scriptPubKeys: scriptPubKeys, inputs: inputs);
|
txb.sign(vin: i, amounts: amounts, scriptPubKeys: scriptPubKeys, inputs: txb.inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return PendingBitcoinTransaction(txb.build(), type,
|
return PendingBitcoinTransaction(txb.build(), type,
|
||||||
electrumClient: electrumClient, amount: amount, fee: fee, networkType: networkType)
|
electrumClient: electrumClient, amount: amount, fee: fee, networkType: networkType)
|
||||||
..addListener((transaction) async {
|
..addListener((transaction) async {
|
||||||
transactionHistory.addOne(transaction);
|
transactionHistory.addOne(transaction);
|
||||||
|
for (final input in txb.inputs) {
|
||||||
|
final unspent = unspentCoins.firstWhereOrNull((utx) =>
|
||||||
|
utx.hash.contains(HEX.encode(input.hash!.reversed.toList())) &&
|
||||||
|
utx.vout == input.index);
|
||||||
|
if (unspent != null) {
|
||||||
|
unspentCoins.remove(unspent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await updateUnspent();
|
||||||
await updateBalance();
|
await updateBalance();
|
||||||
|
await updateTransactions();
|
||||||
});
|
});
|
||||||
} catch (e, stacktrace) {
|
} catch (e, stacktrace) {
|
||||||
print(stacktrace);
|
print(stacktrace);
|
||||||
|
@ -554,6 +533,10 @@ abstract class ElectrumWalletBase
|
||||||
int feeRate(TransactionPriority priority) {
|
int feeRate(TransactionPriority priority) {
|
||||||
try {
|
try {
|
||||||
if (priority is BitcoinTransactionPriority) {
|
if (priority is BitcoinTransactionPriority) {
|
||||||
|
if (networkType.bech32 == bitcoin.testnet.bech32 &&
|
||||||
|
priority == BitcoinTransactionPriority.fast) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
return _feeRates[priority.raw];
|
return _feeRates[priority.raw];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1121,7 +1104,7 @@ Future<void> startRefresh(ScanData scanData) async {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
print(["Scanning from height:", syncHeight]);
|
// print(["Scanning from height:", syncHeight]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final networkPath =
|
final networkPath =
|
||||||
|
@ -1183,13 +1166,20 @@ Future<void> startRefresh(ScanData scanData) async {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input["witness"].length != 2) {
|
String? pubkey;
|
||||||
|
if (input["witness"].length == 2) {
|
||||||
|
pubkey = input["witness"][1] as String;
|
||||||
|
} else if (input["witness"].length == 1) {
|
||||||
|
pubkey =
|
||||||
|
"03" + (input["prevout"]["scriptpubkey"] as String).fromHex.sublist(2).hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pubkey == null) {
|
||||||
skip = true;
|
skip = true;
|
||||||
// print("Skipping, invalid witness");
|
// print("Skipping, invalid witness");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
final pubkey = input["witness"][1] as String;
|
|
||||||
pubkeys.add(pubkey);
|
pubkeys.add(pubkey);
|
||||||
outpoints.add(
|
outpoints.add(
|
||||||
bitcoin.Outpoint(txid: input["txid"] as String, index: input["vout"] as int));
|
bitcoin.Outpoint(txid: input["txid"] as String, index: input["vout"] as int));
|
||||||
|
@ -1220,8 +1210,9 @@ Future<void> startRefresh(ScanData scanData) async {
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
final p2tr = bitcoin.P2trAddress(program: script.sublist(2).hex);
|
final p2tr = bitcoin.P2trAddress(
|
||||||
final address = p2tr.toAddress(scanData.networkType);
|
program: script.sublist(2).hex, networkType: scanData.networkType);
|
||||||
|
final address = p2tr.address;
|
||||||
|
|
||||||
print(["Verifying taproot address:", address]);
|
print(["Verifying taproot address:", address]);
|
||||||
|
|
||||||
|
@ -1236,13 +1227,9 @@ Future<void> startRefresh(ScanData scanData) async {
|
||||||
|
|
||||||
final outpointHash = bitcoin.SilentPayment.hashOutpoints(outpoints);
|
final outpointHash = bitcoin.SilentPayment.hashOutpoints(outpoints);
|
||||||
|
|
||||||
final curve = bitcoin.getSecp256k1();
|
|
||||||
|
|
||||||
final result = bitcoin.scanOutputs(
|
final result = bitcoin.scanOutputs(
|
||||||
bitcoin.PrivateKey.fromHex(
|
scanData.primarySilentAddress.scanPrivkey,
|
||||||
curve, scanData.primarySilentAddress.scanPrivkey.toCompressedHex()),
|
scanData.primarySilentAddress.spendPubkey,
|
||||||
bitcoin.PublicKey.fromHex(
|
|
||||||
curve, scanData.primarySilentAddress.spendPubkey.toCompressedHex()),
|
|
||||||
bitcoin.getSumInputPubKeys(pubkeys),
|
bitcoin.getSumInputPubKeys(pubkeys),
|
||||||
outpointHash,
|
outpointHash,
|
||||||
outpointsByP2TRpubkey.keys.map((e) => e.fromHex).toList(),
|
outpointsByP2TRpubkey.keys.map((e) => e.fromHex).toList(),
|
||||||
|
@ -1261,7 +1248,7 @@ Future<void> startRefresh(ScanData scanData) async {
|
||||||
}
|
}
|
||||||
print(result);
|
print(result);
|
||||||
|
|
||||||
result.forEach((key, value) {
|
result.forEach((key, value) async {
|
||||||
final outpoint = outpointsByP2TRpubkey[key];
|
final outpoint = outpointsByP2TRpubkey[key];
|
||||||
|
|
||||||
if (outpoint == null) {
|
if (outpoint == null) {
|
||||||
|
@ -1272,10 +1259,73 @@ Future<void> startRefresh(ScanData scanData) async {
|
||||||
String? label;
|
String? label;
|
||||||
if (value.length > 1) label = value[1];
|
if (value.length > 1) label = value[1];
|
||||||
|
|
||||||
|
final txInfo = ElectrumTransactionInfo(
|
||||||
|
WalletType.bitcoin,
|
||||||
|
id: txid,
|
||||||
|
height: syncHeight,
|
||||||
|
amount: outpoint.value!,
|
||||||
|
fee: 0,
|
||||||
|
direction: TransactionDirection.incoming,
|
||||||
|
isPending: false,
|
||||||
|
date: DateTime.fromMillisecondsSinceEpoch((blockJson["timestamp"] as int) * 1000),
|
||||||
|
confirmations: currentChainTip - syncHeight,
|
||||||
|
to: bitcoin.SilentPaymentAddress.createLabeledSilentPaymentAddress(
|
||||||
|
scanData.primarySilentAddress.scanPubkey,
|
||||||
|
scanData.primarySilentAddress.spendPubkey,
|
||||||
|
label != null ? label.fromHex : "0".fromHex,
|
||||||
|
hrp: scanData.primarySilentAddress.hrp,
|
||||||
|
version: scanData.primarySilentAddress.version)
|
||||||
|
.toString(),
|
||||||
|
unspent: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
final status = json.decode((await http
|
||||||
|
.get(Uri.parse("https://blockstream.info/testnet/api/tx/$txid/outspends")))
|
||||||
|
.body) as List<dynamic>;
|
||||||
|
|
||||||
|
bool spent = false;
|
||||||
|
for (final s in status) {
|
||||||
|
if ((s["spent"] as bool) == true) {
|
||||||
|
spent = true;
|
||||||
|
|
||||||
|
scanData.sendPort.send({txid: txInfo});
|
||||||
|
|
||||||
|
final sentTxId = s["txid"] as String;
|
||||||
|
final sentTx = json.decode((await http
|
||||||
|
.get(Uri.parse("https://blockstream.info/testnet/api/tx/$sentTxId")))
|
||||||
|
.body);
|
||||||
|
|
||||||
|
int amount = 0;
|
||||||
|
for (final out in (sentTx["vout"] as List<dynamic>)) {
|
||||||
|
amount += out["value"] as int;
|
||||||
|
}
|
||||||
|
|
||||||
|
final height = s["status"]["block_height"] as int;
|
||||||
|
|
||||||
|
scanData.sendPort.send({
|
||||||
|
sentTxId: ElectrumTransactionInfo(
|
||||||
|
WalletType.bitcoin,
|
||||||
|
id: sentTxId,
|
||||||
|
height: height,
|
||||||
|
amount: amount,
|
||||||
|
fee: 0,
|
||||||
|
direction: TransactionDirection.outgoing,
|
||||||
|
isPending: false,
|
||||||
|
date: DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
(s["status"]["block_time"] as int) * 1000),
|
||||||
|
confirmations: currentChainTip - height,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final unspent = BitcoinUnspent(
|
final unspent = BitcoinUnspent(
|
||||||
BitcoinAddressRecord(
|
BitcoinAddressRecord(
|
||||||
bitcoin.P2trAddress(program: key, network: scanData.networkType)
|
bitcoin.P2trAddress(program: key, networkType: scanData.networkType).address,
|
||||||
.toAddress(scanData.networkType),
|
|
||||||
index: 0,
|
index: 0,
|
||||||
isHidden: true,
|
isHidden: true,
|
||||||
isUsed: true,
|
isUsed: true,
|
||||||
|
@ -1294,28 +1344,8 @@ Future<void> startRefresh(ScanData scanData) async {
|
||||||
scanData.sendPort.send(unspent);
|
scanData.sendPort.send(unspent);
|
||||||
|
|
||||||
// also send tx data for tx history
|
// also send tx data for tx history
|
||||||
scanData.sendPort.send({
|
txInfo.unspent = unspent;
|
||||||
txid: ElectrumTransactionInfo(
|
scanData.sendPort.send({txid: txInfo});
|
||||||
WalletType.bitcoin,
|
|
||||||
id: txid,
|
|
||||||
height: syncHeight,
|
|
||||||
amount: outpoint.value!,
|
|
||||||
fee: 0,
|
|
||||||
direction: TransactionDirection.incoming,
|
|
||||||
isPending: false,
|
|
||||||
date:
|
|
||||||
DateTime.fromMillisecondsSinceEpoch((blockJson["timestamp"] as int) * 1000),
|
|
||||||
confirmations: currentChainTip - syncHeight,
|
|
||||||
to: bitcoin.SilentPaymentAddress.createLabeledSilentPaymentAddress(
|
|
||||||
scanData.primarySilentAddress.scanPubkey,
|
|
||||||
scanData.primarySilentAddress.spendPubkey,
|
|
||||||
label != null ? label.fromHex : "0".fromHex,
|
|
||||||
hrp: scanData.primarySilentAddress.hrp,
|
|
||||||
version: scanData.primarySilentAddress.version)
|
|
||||||
.toString(),
|
|
||||||
unspent: unspent,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
@ -1334,6 +1364,7 @@ Future<void> startRefresh(ScanData scanData) async {
|
||||||
print(stacktrace);
|
print(stacktrace);
|
||||||
print(e.toString());
|
print(e.toString());
|
||||||
|
|
||||||
|
scanData.sendPort.send(SyncResponse(syncHeight, NotConnectedSyncStatus()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,22 +15,16 @@ String generateP2WPKHAddress(
|
||||||
{required bitcoin.HDWallet hd,
|
{required bitcoin.HDWallet hd,
|
||||||
required int index,
|
required int index,
|
||||||
required bitcoin.NetworkType networkType}) =>
|
required bitcoin.NetworkType networkType}) =>
|
||||||
bitcoin.P2wpkhAddress(pubkey: hd.derive(index).pubKey!).toAddress(networkType);
|
bitcoin.P2wpkhAddress(pubkey: hd.derive(index).pubKey!, networkType: networkType).address;
|
||||||
|
|
||||||
String generateP2PKHAddress(
|
String generateP2PKHAddress(
|
||||||
{required bitcoin.HDWallet hd,
|
{required bitcoin.HDWallet hd,
|
||||||
required int index,
|
required int index,
|
||||||
required bitcoin.NetworkType networkType}) =>
|
required bitcoin.NetworkType networkType}) =>
|
||||||
bitcoin
|
bitcoin.P2pkhAddress(pubkey: hd.derive(index).pubKey!, networkType: networkType).address;
|
||||||
.P2PKH(
|
|
||||||
data: PaymentData(pubkey: Uint8List.fromList(HEX.decode(hd.derive(index).pubKey!))),
|
|
||||||
network: networkType)
|
|
||||||
.data
|
|
||||||
.address!;
|
|
||||||
|
|
||||||
String generateP2TRAddress(
|
String generateP2TRAddress(
|
||||||
{required bitcoin.HDWallet hd,
|
{required bitcoin.HDWallet hd,
|
||||||
required int index,
|
required int index,
|
||||||
required bitcoin.NetworkType networkType}) =>
|
required bitcoin.NetworkType networkType}) =>
|
||||||
bitcoin.P2trAddress(pubkey: hd.derive(index).pubKey!, network: networkType)
|
bitcoin.P2trAddress(pubkey: hd.derive(index).pubKey!, networkType: networkType).address;
|
||||||
.toAddress(networkType);
|
|
||||||
|
|
|
@ -296,7 +296,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
state = IsExecutingState();
|
state = IsExecutingState();
|
||||||
pendingTransaction = await wallet.createTransaction(_credentials());
|
pendingTransaction = await wallet.createTransaction(_credentials());
|
||||||
state = ExecutedSuccessfullyState();
|
state = ExecutedSuccessfullyState();
|
||||||
} catch (e) {
|
} catch (e, s) {
|
||||||
|
print(s);
|
||||||
state = FailureState(e.toString());
|
state = FailureState(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -338,7 +339,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
}
|
}
|
||||||
|
|
||||||
state = TransactionCommitted();
|
state = TransactionCommitted();
|
||||||
} catch (e) {
|
} catch (e, s) {
|
||||||
|
print(s);
|
||||||
String translatedError = translateErrorMessage(e.toString(), wallet.type, wallet.currency);
|
String translatedError = translateErrorMessage(e.toString(), wallet.type, wallet.currency);
|
||||||
state = FailureState(translatedError);
|
state = FailureState(translatedError);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,12 +61,11 @@ abstract class UnspentCoinsListViewModelBase with Store {
|
||||||
UnspentCoinsInfo getUnspentCoinInfo(
|
UnspentCoinsInfo getUnspentCoinInfo(
|
||||||
String hash, String address, int value, int vout, String? keyImage) =>
|
String hash, String address, int value, int vout, String? keyImage) =>
|
||||||
_unspentCoinsInfo.values.firstWhere((element) {
|
_unspentCoinsInfo.values.firstWhere((element) {
|
||||||
print([ element.address, address ]);
|
|
||||||
return element.walletId == wallet.id &&
|
return element.walletId == wallet.id &&
|
||||||
element.hash == hash &&
|
element.hash == hash &&
|
||||||
element.address == address &&
|
element.address == address &&
|
||||||
// element.value == value &&
|
element.value == value &&
|
||||||
// element.vout == vout &&
|
element.vout == vout &&
|
||||||
element.keyImage == keyImage;
|
element.keyImage == keyImage;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue