mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-08 19:59:29 +00:00
bitcoin cash sending works for legacy and new addresses bip44
This commit is contained in:
parent
5cbaa597d3
commit
cbb3c3f241
2 changed files with 87 additions and 40 deletions
|
@ -41,6 +41,7 @@ import 'package:stackwallet/utilities/logger.dart';
|
|||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'package:bitbox/bitbox.dart' as Bitbox;
|
||||
|
||||
const int MINIMUM_CONFIRMATIONS = 3;
|
||||
const int DUST_LIMIT = 1000000;
|
||||
|
@ -735,6 +736,9 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
/// Refreshes display data for the wallet
|
||||
@override
|
||||
Future<void> refresh() async {
|
||||
final bchaddr = Bitbox.Address.toCashAddress(await currentReceivingAddress);
|
||||
print("bchaddr: $bchaddr ${await currentReceivingAddress}");
|
||||
|
||||
if (refreshMutex) {
|
||||
Logging.instance.log("$walletId $walletName refreshMutex denied",
|
||||
level: LogLevel.Info);
|
||||
|
@ -1050,7 +1054,14 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
|
||||
@override
|
||||
bool validateAddress(String address) {
|
||||
return Address.validateAddress(address, _network);
|
||||
try {
|
||||
// 0 for bitcoincash: address scheme, 1 for legacy address
|
||||
final format = Bitbox.Address.detectFormat(address);
|
||||
print("format $format");
|
||||
return true;
|
||||
} catch (e, s) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -1947,6 +1958,7 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
List<Map<String, dynamic>> allTransactions = [];
|
||||
|
||||
for (final txHash in allTxHashes) {
|
||||
Logging.instance.log("bch: $txHash", level: LogLevel.Info);
|
||||
final tx = await cachedElectrumXClient.getTransaction(
|
||||
txHash: txHash["tx_hash"] as String,
|
||||
verbose: true,
|
||||
|
@ -2318,8 +2330,8 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
vSize: vSizeForOneOutput,
|
||||
feeRatePerKB: selectedTxFeeRate,
|
||||
);
|
||||
if (feeForOneOutput < (vSizeForOneOutput + 1) * 1000) {
|
||||
feeForOneOutput = (vSizeForOneOutput + 1) * 1000;
|
||||
if (feeForOneOutput < (vSizeForOneOutput + 1)) {
|
||||
feeForOneOutput = (vSizeForOneOutput + 1);
|
||||
}
|
||||
|
||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||
|
@ -2375,11 +2387,11 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
.log("feeForTwoOutputs: $feeForTwoOutputs", level: LogLevel.Info);
|
||||
Logging.instance
|
||||
.log("feeForOneOutput: $feeForOneOutput", level: LogLevel.Info);
|
||||
if (feeForOneOutput < (vSizeForOneOutput + 1) * 1000) {
|
||||
feeForOneOutput = (vSizeForOneOutput + 1) * 1000;
|
||||
if (feeForOneOutput < (vSizeForOneOutput + 1)) {
|
||||
feeForOneOutput = (vSizeForOneOutput + 1);
|
||||
}
|
||||
if (feeForTwoOutputs < ((vSizeForTwoOutPuts + 1) * 1000)) {
|
||||
feeForTwoOutputs = ((vSizeForTwoOutPuts + 1) * 1000);
|
||||
if (feeForTwoOutputs < ((vSizeForTwoOutPuts + 1))) {
|
||||
feeForTwoOutputs = ((vSizeForTwoOutPuts + 1));
|
||||
}
|
||||
|
||||
Logging.instance
|
||||
|
@ -2679,45 +2691,76 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
required List<String> recipients,
|
||||
required List<int> satoshiAmounts,
|
||||
}) async {
|
||||
Logging.instance
|
||||
.log("Starting buildTransaction ----------", level: LogLevel.Info);
|
||||
final builder = Bitbox.Bitbox.transactionBuilder();
|
||||
|
||||
final txb = TransactionBuilder(network: _network);
|
||||
txb.setVersion(1);
|
||||
// retrieve address' utxos from the rest api
|
||||
List<Bitbox.Utxo> _utxos =
|
||||
[]; // await Bitbox.Address.utxo(address) as List<Bitbox.Utxo>;
|
||||
utxosToUse.forEach((element) {
|
||||
_utxos.add(Bitbox.Utxo(
|
||||
element.txid,
|
||||
element.vout,
|
||||
Bitbox.BitcoinCash.fromSatoshi(element.value),
|
||||
element.value,
|
||||
0,
|
||||
MINIMUM_CONFIRMATIONS + 1));
|
||||
});
|
||||
Logger.print("bch utxos: ${_utxos}");
|
||||
|
||||
// Add transaction inputs
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
txb.addInput(txid, utxosToUse[i].vout, null,
|
||||
utxoSigningData[txid]["output"] as Uint8List);
|
||||
// placeholder for input signatures
|
||||
final signatures = <Map>[];
|
||||
|
||||
// placeholder for total input balance
|
||||
int totalBalance = 0;
|
||||
|
||||
// iterate through the list of address _utxos and use them as inputs for the
|
||||
// withdrawal transaction
|
||||
_utxos.forEach((Bitbox.Utxo utxo) {
|
||||
// add the utxo as an input for the transaction
|
||||
builder.addInput(utxo.txid, utxo.vout);
|
||||
final ec = utxoSigningData[utxo.txid]["keyPair"] as ECPair;
|
||||
|
||||
final bitboxEC = Bitbox.ECPair.fromWIF(ec.toWIF());
|
||||
|
||||
// add a signature to the list to be used later
|
||||
signatures.add({
|
||||
"vin": signatures.length,
|
||||
"key_pair": bitboxEC,
|
||||
"original_amount": utxo.satoshis
|
||||
});
|
||||
|
||||
totalBalance += utxo.satoshis;
|
||||
});
|
||||
|
||||
// calculate the fee based on number of inputs and one expected output
|
||||
final fee =
|
||||
Bitbox.BitcoinCash.getByteCount(signatures.length, recipients.length);
|
||||
|
||||
// calculate how much balance will be left over to spend after the fee
|
||||
final sendAmount = totalBalance - fee;
|
||||
|
||||
// add the output based on the address provided in the testing data
|
||||
for (int i = 0; i < recipients.length; i++) {
|
||||
String recipient = recipients[i];
|
||||
int satoshiAmount = satoshiAmounts[i];
|
||||
builder.addOutput(recipient, satoshiAmount);
|
||||
}
|
||||
|
||||
// Add transaction output
|
||||
for (var i = 0; i < recipients.length; i++) {
|
||||
txb.addOutput(recipients[i], satoshiAmounts[i]);
|
||||
}
|
||||
// sign all inputs
|
||||
signatures.forEach((signature) {
|
||||
builder.sign(
|
||||
signature["vin"] as int,
|
||||
signature["key_pair"] as Bitbox.ECPair,
|
||||
signature["original_amount"] as int);
|
||||
});
|
||||
|
||||
try {
|
||||
// Sign the transaction accordingly
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
txb.sign(
|
||||
vin: i,
|
||||
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
||||
witnessValue: utxosToUse[i].value,
|
||||
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?,
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("Caught exception while signing transaction: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
rethrow;
|
||||
}
|
||||
// build the transaction
|
||||
final tx = builder.build();
|
||||
final txHex = tx.toHex();
|
||||
final vSize = tx.virtualSize();
|
||||
Logger.print("bch raw hex: $txHex");
|
||||
|
||||
final builtTx = txb.build();
|
||||
final vSize = builtTx.virtualSize();
|
||||
|
||||
return {"hex": builtTx.toHex(), "vSize": vSize};
|
||||
return {"hex": txHex, "vSize": vSize};
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -69,6 +69,10 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/cypherstack/stack-bip39.git
|
||||
ref: 3bef5acc21340f3cc78df0ad1dce5868a3ed68a5
|
||||
bitbox:
|
||||
git:
|
||||
url: https://github.com/Quppy/bitbox-flutter.git
|
||||
ref: ea65073efbaf395a5557e8cd7bd72f195cd7eb11
|
||||
bip32: ^2.0.0
|
||||
bech32: ^0.2.1
|
||||
bs58check: ^1.0.2
|
||||
|
|
Loading…
Reference in a new issue