Merge remote-tracking branch 'origin/testing' into tor

This commit is contained in:
sneurlax 2024-04-18 15:28:36 -05:00
commit 6afe034dc4
9 changed files with 450 additions and 273 deletions

View file

@ -8,10 +8,7 @@
*
*/
import 'dart:typed_data';
import 'package:bitcoindart/bitcoindart.dart';
// import 'package:coinlib_flutter/coinlib_flutter.dart';
import 'package:coinlib_flutter/coinlib_flutter.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
@ -19,49 +16,19 @@ class SigningData {
SigningData({
required this.derivePathType,
required this.utxo,
this.output,
this.keyPair,
this.redeemScript,
});
final DerivePathType derivePathType;
final UTXO utxo;
Uint8List? output;
ECPair? keyPair;
Uint8List? redeemScript;
HDPrivateKey? keyPair;
@override
String toString() {
return "SigningData{\n"
" derivePathType: $derivePathType,\n"
" utxo: $utxo,\n"
" output: $output,\n"
" keyPair: $keyPair,\n"
" redeemScript: $redeemScript,\n"
"}";
}
}
// class SigningData {
// SigningData({
// required this.derivePathType,
// required this.utxo,
// this.keyPair,
// this.redeemScript,
// });
//
// final DerivePathType derivePathType;
// final UTXO utxo;
// ({ECPrivateKey privateKey, ECPublicKey publicKey})? keyPair;
// Uint8List? redeemScript;
//
// @override
// String toString() {
// return "SigningData{\n"
// " derivePathType: $derivePathType,\n"
// " utxo: $utxo,\n"
// " keyPair: $keyPair,\n"
// " redeemScript: $redeemScript,\n"
// "}";
// }
// }

View file

@ -10,8 +10,6 @@
import 'dart:convert';
import 'package:bitcoindart/bitcoindart.dart';
import 'package:crypto/crypto.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/wallets/crypto_currency/coins/banano.dart';
@ -38,34 +36,6 @@ class AddressUtils {
return '${address.substring(0, 5)}...${address.substring(address.length - 5)}';
}
/// attempts to convert a string to a valid scripthash
///
/// Returns the scripthash or throws an exception on invalid firo address
static String convertToScriptHash(
String address,
NetworkType network, [
String overridePrefix = "",
]) {
try {
final output =
Address.addressToOutputScript(address, network, overridePrefix);
final hash = sha256.convert(output.toList(growable: false)).toString();
final chars = hash.split("");
final reversedPairs = <String>[];
// TODO find a better/faster way to do this?
var i = chars.length - 1;
while (i > 0) {
reversedPairs.add(chars[i - 1]);
reversedPairs.add(chars[i]);
i -= 2;
}
return reversedPairs.join("");
} catch (e) {
rethrow;
}
}
static bool validateAddress(String address, Coin coin) {
//This calls the validate address for each crypto coin, validateAddress is
//only used in 2 places, so I just replaced the old functionality here

View file

@ -10,7 +10,6 @@
import 'package:bip32/bip32.dart' as bip32;
import 'package:bip39/bip39.dart' as bip39;
import 'package:bitcoindart/bitcoindart.dart';
import 'package:flutter/foundation.dart';
import 'package:tuple/tuple.dart';
@ -19,25 +18,17 @@ abstract class Bip32Utils {
static bip32.BIP32 getBip32RootSync(
String mnemonic,
String mnemonicPassphrase,
NetworkType networkType,
bip32.NetworkType networkType,
) {
final seed = bip39.mnemonicToSeed(mnemonic, passphrase: mnemonicPassphrase);
final _networkType = bip32.NetworkType(
wif: networkType.wif,
bip32: bip32.Bip32Type(
public: networkType.bip32.public,
private: networkType.bip32.private,
),
);
final root = bip32.BIP32.fromSeed(seed, _networkType);
final root = bip32.BIP32.fromSeed(seed, networkType);
return root;
}
static Future<bip32.BIP32> getBip32Root(
String mnemonic,
String mnemonicPassphrase,
NetworkType networkType,
bip32.NetworkType networkType,
) async {
final root = await compute(
_getBip32RootWrapper,
@ -52,7 +43,7 @@ abstract class Bip32Utils {
/// wrapper for compute()
static bip32.BIP32 _getBip32RootWrapper(
Tuple3<String, String, NetworkType> args,
Tuple3<String, String, bip32.NetworkType> args,
) {
return getBip32RootSync(
args.item1,
@ -97,7 +88,7 @@ abstract class Bip32Utils {
static bip32.BIP32 getBip32NodeSync(
String mnemonic,
String mnemonicPassphrase,
NetworkType network,
bip32.NetworkType network,
String derivePath,
) {
final root = getBip32RootSync(mnemonic, mnemonicPassphrase, network);
@ -109,7 +100,7 @@ abstract class Bip32Utils {
static Future<bip32.BIP32> getBip32Node(
String mnemonic,
String mnemonicPassphrase,
NetworkType networkType,
bip32.NetworkType networkType,
String derivePath,
) async {
final node = await compute(
@ -126,7 +117,7 @@ abstract class Bip32Utils {
/// wrapper for compute()
static bip32.BIP32 _getBip32NodeWrapper(
Tuple4<String, String, NetworkType, String> args,
Tuple4<String, String, bip32.NetworkType, String> args,
) {
return getBip32NodeSync(
args.item1,

View file

@ -1,3 +1,5 @@
import 'dart:typed_data';
import 'package:bitcoindart/bitcoindart.dart' as bitcoindart;
import 'package:isar/isar.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
@ -7,6 +9,7 @@ import 'package:stackwallet/models/isar/models/blockchain_data/v2/output_v2.dart
import 'package:stackwallet/models/isar/models/blockchain_data/v2/transaction_v2.dart';
import 'package:stackwallet/models/signing_data.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
import 'package:stackwallet/utilities/extensions/impl/uint8_list.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/wallets/crypto_currency/coins/particl.dart';
@ -340,20 +343,92 @@ class ParticlWallet extends Bip39HDWallet
Logging.instance.log("Starting Particl buildTransaction ----------",
level: LogLevel.Info);
// TODO: use coinlib
// TODO: use coinlib (For this we need coinlib to support particl)
final convertedNetwork = bitcoindart.NetworkType(
messagePrefix: cryptoCurrency.networkParams.messagePrefix,
bech32: cryptoCurrency.networkParams.bech32Hrp,
bip32: bitcoindart.Bip32Type(
public: cryptoCurrency.networkParams.pubHDPrefix,
private: cryptoCurrency.networkParams.privHDPrefix,
),
pubKeyHash: cryptoCurrency.networkParams.p2pkhPrefix,
scriptHash: cryptoCurrency.networkParams.p2shPrefix,
wif: cryptoCurrency.networkParams.wifPrefix,
);
final List<({Uint8List? output, Uint8List? redeem})> extraData = [];
for (int i = 0; i < utxoSigningData.length; i++) {
final sd = utxoSigningData[i];
final pubKey = sd.keyPair!.publicKey.data;
final bitcoindart.PaymentData? data;
Uint8List? redeem, output;
switch (sd.derivePathType) {
case DerivePathType.bip44:
data = bitcoindart
.P2PKH(
data: bitcoindart.PaymentData(
pubkey: pubKey,
),
network: convertedNetwork,
)
.data;
break;
case DerivePathType.bip49:
final p2wpkh = bitcoindart
.P2WPKH(
data: bitcoindart.PaymentData(
pubkey: pubKey,
),
network: convertedNetwork,
)
.data;
redeem = p2wpkh.output;
data = bitcoindart
.P2SH(
data: bitcoindart.PaymentData(redeem: p2wpkh),
network: convertedNetwork,
)
.data;
break;
case DerivePathType.bip84:
// input = coinlib.P2WPKHInput(
// prevOut: coinlib.OutPoint.fromHex(sd.utxo.txid, sd.utxo.vout),
// publicKey: keys.publicKey,
// );
data = bitcoindart
.P2WPKH(
data: bitcoindart.PaymentData(
pubkey: pubKey,
),
network: convertedNetwork,
)
.data;
break;
case DerivePathType.bip86:
data = null;
break;
default:
throw Exception("DerivePathType unsupported");
}
// sd.output = input.script!.compiled;
if (sd.derivePathType != DerivePathType.bip86) {
output = data!.output!;
}
extraData.add((output: output, redeem: redeem));
}
final txb = bitcoindart.TransactionBuilder(
network: bitcoindart.NetworkType(
messagePrefix: cryptoCurrency.networkParams.messagePrefix,
bech32: cryptoCurrency.networkParams.bech32Hrp,
bip32: bitcoindart.Bip32Type(
public: cryptoCurrency.networkParams.pubHDPrefix,
private: cryptoCurrency.networkParams.privHDPrefix,
),
pubKeyHash: cryptoCurrency.networkParams.p2pkhPrefix,
scriptHash: cryptoCurrency.networkParams.p2shPrefix,
wif: cryptoCurrency.networkParams.wifPrefix,
),
network: convertedNetwork,
);
const version = 160; // buildTransaction overridden for Particl to set this.
// TODO: [prio=low] refactor overridden buildTransaction to use eg. cryptocurrency.networkParams.txVersion.
@ -370,7 +445,7 @@ class ParticlWallet extends Bip39HDWallet
txid,
utxoSigningData[i].utxo.vout,
null,
utxoSigningData[i].output!,
extraData[i].output!,
cryptoCurrency.networkParams.bech32Hrp,
);
@ -427,9 +502,13 @@ class ParticlWallet extends Bip39HDWallet
for (var i = 0; i < utxoSigningData.length; i++) {
txb.sign(
vin: i,
keyPair: utxoSigningData[i].keyPair!,
keyPair: bitcoindart.ECPair.fromPrivateKey(
utxoSigningData[i].keyPair!.privateKey.data,
network: convertedNetwork,
compressed: utxoSigningData[i].keyPair!.privateKey.compressed,
),
witnessValue: utxoSigningData[i].utxo.value,
redeemScript: utxoSigningData[i].redeemScript,
redeemScript: extraData[i].redeem,
overridePrefix: cryptoCurrency.networkParams.bech32Hrp,
);
}

View file

@ -1,4 +1,5 @@
import 'package:bitbox/bitbox.dart' as bitbox;
import 'package:bitbox/src/utils/network.dart' as bitbox_utils;
import 'package:isar/isar.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/v2/input_v2.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/v2/output_v2.dart';
@ -89,8 +90,17 @@ mixin BCashInterface on Bip39HDWallet, ElectrumXInterface {
try {
// Sign the transaction accordingly
for (int i = 0; i < utxoSigningData.length; i++) {
final bitboxEC = bitbox.ECPair.fromWIF(
utxoSigningData[i].keyPair!.toWIF(),
final bitboxEC = bitbox.ECPair.fromPrivateKey(
utxoSigningData[i].keyPair!.privateKey.data,
network: bitbox_utils.Network(
cryptoCurrency.networkParams.privHDPrefix,
cryptoCurrency.networkParams.pubHDPrefix,
cryptoCurrency.network == CryptoCurrencyNetwork.test,
cryptoCurrency.networkParams.p2pkhPrefix,
cryptoCurrency.networkParams.wifPrefix,
cryptoCurrency.networkParams.p2pkhPrefix,
),
compressed: utxoSigningData[i].keyPair!.privateKey.compressed,
);
builder.sign(

View file

@ -2,8 +2,6 @@ import 'dart:async';
import 'dart:math';
import 'dart:typed_data';
import 'package:bip47/src/util.dart';
import 'package:bitcoindart/bitcoindart.dart' as bitcoindart;
import 'package:coinlib_flutter/coinlib_flutter.dart' as coinlib;
import 'package:electrum_adapter/electrum_adapter.dart' as electrum_adapter;
import 'package:electrum_adapter/electrum_adapter.dart';
@ -22,6 +20,7 @@ import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
import 'package:stackwallet/utilities/extensions/extensions.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/paynym_is_api.dart';
import 'package:stackwallet/utilities/prefs.dart';
@ -545,18 +544,6 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
);
}
final convertedNetwork = bitcoindart.NetworkType(
messagePrefix: cryptoCurrency.networkParams.messagePrefix,
bech32: cryptoCurrency.networkParams.bech32Hrp,
bip32: bitcoindart.Bip32Type(
public: cryptoCurrency.networkParams.pubHDPrefix,
private: cryptoCurrency.networkParams.privHDPrefix,
),
pubKeyHash: cryptoCurrency.networkParams.p2pkhPrefix,
scriptHash: cryptoCurrency.networkParams.p2shPrefix,
wif: cryptoCurrency.networkParams.wifPrefix,
);
final root = await getRootHDNode();
for (final sd in signingData) {
@ -597,80 +584,7 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
"Failed to fetch signing data. Local db corrupt. Rescan wallet.");
}
// final coinlib.Input input;
final pubKey = keys.publicKey.data;
final bitcoindart.PaymentData? data;
switch (sd.derivePathType) {
case DerivePathType.bip44:
// input = coinlib.P2PKHInput(
// prevOut: coinlib.OutPoint.fromHex(sd.utxo.txid, sd.utxo.vout),
// publicKey: keys.publicKey,
// );
data = bitcoindart
.P2PKH(
data: bitcoindart.PaymentData(
pubkey: pubKey,
),
network: convertedNetwork,
)
.data;
break;
case DerivePathType.bip49:
final p2wpkh = bitcoindart
.P2WPKH(
data: bitcoindart.PaymentData(
pubkey: pubKey,
),
network: convertedNetwork,
)
.data;
sd.redeemScript = p2wpkh.output;
data = bitcoindart
.P2SH(
data: bitcoindart.PaymentData(redeem: p2wpkh),
network: convertedNetwork,
)
.data;
break;
case DerivePathType.bip84:
// input = coinlib.P2WPKHInput(
// prevOut: coinlib.OutPoint.fromHex(sd.utxo.txid, sd.utxo.vout),
// publicKey: keys.publicKey,
// );
data = bitcoindart
.P2WPKH(
data: bitcoindart.PaymentData(
pubkey: pubKey,
),
network: convertedNetwork,
)
.data;
break;
case DerivePathType.bip86:
data = null;
break;
default:
throw Exception("DerivePathType unsupported");
}
// sd.output = input.script!.compiled;
if (sd.derivePathType != DerivePathType.bip86) {
sd.output = data!.output!;
}
sd.keyPair = bitcoindart.ECPair.fromPrivateKey(
keys.privateKey.data,
compressed: keys.privateKey.compressed,
network: convertedNetwork,
);
sd.keyPair = keys;
}
return signingData;
@ -705,7 +619,9 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
for (var i = 0; i < utxoSigningData.length; i++) {
final txid = utxoSigningData[i].utxo.txid;
final hash = Uint8List.fromList(txid.fromHex.reversed.toList());
final hash = Uint8List.fromList(
txid.toUint8ListFromHex.reversed.toList(),
);
final prevOutpoint = coinlib.OutPoint(
hash,
@ -729,30 +645,25 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
case DerivePathType.bch44:
input = coinlib.P2PKHInput(
prevOut: prevOutpoint,
// publicKey: utxoSigningData[i].keyPair!.publicKey,
publicKey: coinlib.ECPublicKey(
utxoSigningData[i].keyPair!.publicKey,
),
publicKey: utxoSigningData[i].keyPair!.publicKey,
sequence: 0xffffffff - 1,
);
// TODO: fix this as it is (probably) wrong!
case DerivePathType.bip49:
input = coinlib.P2SHMultisigInput(
prevOut: prevOutpoint,
program: coinlib.MultisigProgram.decompile(
utxoSigningData[i].redeemScript!,
),
sequence: 0xffffffff - 1,
);
throw Exception("TODO p2sh");
// input = coinlib.P2SHMultisigInput(
// prevOut: prevOutpoint,
// program: coinlib.MultisigProgram.decompile(
// utxoSigningData[i].redeemScript!,
// ),
// sequence: 0xffffffff - 1,
// );
case DerivePathType.bip84:
input = coinlib.P2WPKHInput(
prevOut: prevOutpoint,
// publicKey: utxoSigningData[i].keyPair!.publicKey,
publicKey: coinlib.ECPublicKey(
utxoSigningData[i].keyPair!.publicKey,
),
publicKey: utxoSigningData[i].keyPair!.publicKey,
sequence: 0xffffffff - 1,
);
@ -825,16 +736,11 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
// Sign the transaction accordingly
for (var i = 0; i < utxoSigningData.length; i++) {
final value = BigInt.from(utxoSigningData[i].utxo.value);
coinlib.ECPrivateKey key = coinlib.ECPrivateKey(
utxoSigningData[i].keyPair!.privateKey!,
compressed: utxoSigningData[i].keyPair!.compressed,
);
coinlib.ECPrivateKey key = utxoSigningData[i].keyPair!.privateKey;
if (clTx.inputs[i] is coinlib.TaprootKeyInput) {
final taproot = coinlib.Taproot(
internalKey: coinlib.ECPublicKey(
utxoSigningData[i].keyPair!.publicKey,
),
internalKey: utxoSigningData[i].keyPair!.publicKey,
);
key = taproot.tweakPrivateKey(key);
@ -843,18 +749,9 @@ mixin ElectrumXInterface<T extends Bip39HDCurrency> on Bip39HDWallet<T> {
clTx = clTx.sign(
inputN: i,
value: value,
// key: utxoSigningData[i].keyPair!.privateKey,
key: key,
prevOuts: prevOuts,
);
// txb.sign(
// vin: i,
// keyPair: utxoSigningData[i].keyPair!,
// witnessValue: utxoSigningData[i].utxo.value,
// redeemScript: utxoSigningData[i].redeemScript,
// overridePrefix: cryptoCurrency.networkParams.bech32Hrp,
// );
}
} catch (e, s) {
Logging.instance.log("Caught exception while signing transaction: $e\n$s",

View file

@ -742,18 +742,20 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface {
Future<TxData> buildMintTransaction({required TxData txData}) async {
final signingData = await fetchBuildTxData(txData.utxos!.toList());
final txb = bitcoindart.TransactionBuilder(
network: bitcoindart.NetworkType(
messagePrefix: cryptoCurrency.networkParams.messagePrefix,
bech32: cryptoCurrency.networkParams.bech32Hrp,
bip32: bitcoindart.Bip32Type(
public: cryptoCurrency.networkParams.pubHDPrefix,
private: cryptoCurrency.networkParams.privHDPrefix,
),
pubKeyHash: cryptoCurrency.networkParams.p2pkhPrefix,
scriptHash: cryptoCurrency.networkParams.p2shPrefix,
wif: cryptoCurrency.networkParams.wifPrefix,
final convertedNetwork = bitcoindart.NetworkType(
messagePrefix: cryptoCurrency.networkParams.messagePrefix,
bech32: cryptoCurrency.networkParams.bech32Hrp,
bip32: bitcoindart.Bip32Type(
public: cryptoCurrency.networkParams.pubHDPrefix,
private: cryptoCurrency.networkParams.privHDPrefix,
),
pubKeyHash: cryptoCurrency.networkParams.p2pkhPrefix,
scriptHash: cryptoCurrency.networkParams.p2shPrefix,
wif: cryptoCurrency.networkParams.wifPrefix,
);
final txb = bitcoindart.TransactionBuilder(
network: convertedNetwork,
);
txb.setVersion(2);
@ -763,11 +765,62 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface {
int amount = 0;
// Add transaction inputs
for (var i = 0; i < signingData.length; i++) {
final pubKey = signingData[i].keyPair!.publicKey.data;
final bitcoindart.PaymentData? data;
switch (signingData[i].derivePathType) {
case DerivePathType.bip44:
data = bitcoindart
.P2PKH(
data: bitcoindart.PaymentData(
pubkey: pubKey,
),
network: convertedNetwork,
)
.data;
break;
case DerivePathType.bip49:
final p2wpkh = bitcoindart
.P2WPKH(
data: bitcoindart.PaymentData(
pubkey: pubKey,
),
network: convertedNetwork,
)
.data;
data = bitcoindart
.P2SH(
data: bitcoindart.PaymentData(redeem: p2wpkh),
network: convertedNetwork,
)
.data;
break;
case DerivePathType.bip84:
data = bitcoindart
.P2WPKH(
data: bitcoindart.PaymentData(
pubkey: pubKey,
),
network: convertedNetwork,
)
.data;
break;
case DerivePathType.bip86:
data = null;
break;
default:
throw Exception("DerivePathType unsupported");
}
txb.addInput(
signingData[i].utxo.txid,
signingData[i].utxo.vout,
null,
signingData[i].output,
data!.output!,
);
amount += signingData[i].utxo.value;
}
@ -782,7 +835,11 @@ mixin LelantusInterface on Bip39HDWallet, ElectrumXInterface {
for (var i = 0; i < signingData.length; i++) {
txb.sign(
vin: i,
keyPair: signingData[i].keyPair!,
keyPair: bitcoindart.ECPair.fromPrivateKey(
signingData[i].keyPair!.privateKey.data,
network: convertedNetwork,
compressed: signingData[i].keyPair!.privateKey.compressed,
),
witnessValue: signingData[i].utxo.value,
);
}

View file

@ -7,6 +7,7 @@ import 'package:bip47/bip47.dart';
import 'package:bitcoindart/bitcoindart.dart' as btc_dart;
import 'package:bitcoindart/src/utils/constants/op.dart' as op;
import 'package:bitcoindart/src/utils/script.dart' as bscript;
import 'package:coinlib_flutter/coinlib_flutter.dart' as coinlib;
import 'package:isar/isar.dart';
import 'package:pointycastle/digests/sha256.dart';
import 'package:stackwallet/exceptions/wallet/insufficient_balance_exception.dart';
@ -20,6 +21,7 @@ import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/bip32_utils.dart';
import 'package:stackwallet/utilities/bip47_utils.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
import 'package:stackwallet/utilities/extensions/extensions.dart';
import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/logger.dart';
@ -290,7 +292,13 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
return _cachedRootNode ??= await Bip32Utils.getBip32Root(
(await getMnemonic()),
(await getMnemonicPassphrase()),
networkType,
bip32.NetworkType(
wif: networkType.wif,
bip32: bip32.Bip32Type(
public: networkType.bip32.public,
private: networkType.bip32.private,
),
),
);
}
@ -701,7 +709,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
final myKeyPair = utxoSigningData.first.keyPair!;
final S = SecretPoint(
myKeyPair.privateKey!,
myKeyPair.privateKey.data,
targetPaymentCode.notificationPublicKey(),
);
@ -719,63 +727,146 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
]);
// build a notification tx
final txb = btc_dart.TransactionBuilder(network: networkType);
txb.setVersion(1);
txb.addInput(
utxo.txid,
txPointIndex,
null,
utxoSigningData.first.output!,
final List<coinlib.Output> prevOuts = [];
coinlib.Transaction clTx = coinlib.Transaction(
version: 1,
inputs: [],
outputs: [],
);
// add rest of possible inputs
for (var i = 1; i < utxoSigningData.length; i++) {
final utxo = utxoSigningData[i].utxo;
txb.addInput(
utxo.txid,
utxo.vout,
null,
utxoSigningData[i].output!,
for (var i = 0; i < utxoSigningData.length; i++) {
final txid = utxoSigningData[i].utxo.txid;
final hash = Uint8List.fromList(
txid.toUint8ListFromHex.reversed.toList(),
);
final prevOutpoint = coinlib.OutPoint(
hash,
utxoSigningData[i].utxo.vout,
);
final prevOutput = coinlib.Output.fromAddress(
BigInt.from(utxoSigningData[i].utxo.value),
coinlib.Address.fromString(
utxoSigningData[i].utxo.address!,
cryptoCurrency.networkParams,
),
);
prevOuts.add(prevOutput);
final coinlib.Input input;
switch (utxoSigningData[i].derivePathType) {
case DerivePathType.bip44:
case DerivePathType.bch44:
input = coinlib.P2PKHInput(
prevOut: prevOutpoint,
publicKey: utxoSigningData[i].keyPair!.publicKey,
sequence: 0xffffffff - 1,
);
// TODO: fix this as it is (probably) wrong! (unlikely used in paynyms)
case DerivePathType.bip49:
throw Exception("TODO p2sh");
// input = coinlib.P2SHMultisigInput(
// prevOut: prevOutpoint,
// program: coinlib.MultisigProgram.decompile(
// utxoSigningData[i].redeemScript!,
// ),
// sequence: 0xffffffff - 1,
// );
case DerivePathType.bip84:
input = coinlib.P2WPKHInput(
prevOut: prevOutpoint,
publicKey: utxoSigningData[i].keyPair!.publicKey,
sequence: 0xffffffff - 1,
);
case DerivePathType.bip86:
input = coinlib.TaprootKeyInput(prevOut: prevOutpoint);
default:
throw UnsupportedError(
"Unknown derivation path type found: ${utxoSigningData[i].derivePathType}",
);
}
clTx = clTx.addInput(input);
}
final String notificationAddress =
targetPaymentCode.notificationAddressP2PKH();
txb.addOutput(
notificationAddress,
(overrideAmountForTesting ?? cryptoCurrency.dustLimitP2PKH.raw).toInt(),
final address = coinlib.Address.fromString(
normalizeAddress(notificationAddress),
cryptoCurrency.networkParams,
);
final output = coinlib.Output.fromAddress(
overrideAmountForTesting ?? cryptoCurrency.dustLimitP2PKH.raw,
address,
);
clTx = clTx.addOutput(output);
clTx = clTx.addOutput(
coinlib.Output.fromScriptBytes(
BigInt.zero,
opReturnScript,
),
);
txb.addOutput(opReturnScript, 0);
// TODO: add possible change output and mark output as dangerous
if (change > BigInt.zero) {
// generate new change address if current change address has been used
await checkChangeAddressForTransactions();
final String changeAddress = (await getCurrentChangeAddress())!.value;
txb.addOutput(changeAddress, change.toInt());
final output = coinlib.Output.fromAddress(
change,
coinlib.Address.fromString(
normalizeAddress(changeAddress),
cryptoCurrency.networkParams,
),
);
clTx = clTx.addOutput(output);
}
txb.sign(
vin: 0,
keyPair: myKeyPair,
witnessValue: utxo.value,
witnessScript: utxoSigningData.first.redeemScript,
clTx = clTx.sign(
inputN: 0,
value: BigInt.from(utxo.value),
key: myKeyPair.privateKey,
prevOuts: prevOuts,
);
// sign rest of possible inputs
for (var i = 1; i < utxoSigningData.length; i++) {
txb.sign(
vin: i,
keyPair: utxoSigningData[i].keyPair!,
witnessValue: utxoSigningData[i].utxo.value,
witnessScript: utxoSigningData[i].redeemScript,
for (int i = 1; i < utxoSigningData.length; i++) {
final value = BigInt.from(utxoSigningData[i].utxo.value);
coinlib.ECPrivateKey key = utxoSigningData[i].keyPair!.privateKey;
if (clTx.inputs[i] is coinlib.TaprootKeyInput) {
final taproot = coinlib.Taproot(
internalKey: utxoSigningData[i].keyPair!.publicKey,
);
key = taproot.tweakPrivateKey(key);
}
clTx = clTx.sign(
inputN: i,
value: value,
key: key,
prevOuts: prevOuts,
);
}
final builtTx = txb.build();
return Tuple2(builtTx.toHex(), builtTx.virtualSize());
return Tuple2(clTx.toHex(), clTx.size);
} catch (e, s) {
Logging.instance.log(
"_createNotificationTx(): $e\n$s",

View file

@ -13,6 +13,7 @@ import 'package:stackwallet/models/isar/models/blockchain_data/v2/transaction_v2
import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/models/signing_data.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
import 'package:stackwallet/utilities/extensions/extensions.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
@ -1001,13 +1002,64 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface {
for (final sd in setCoins) {
vin.add(sd);
final pubKey = sd.keyPair!.publicKey.data;
final btc.PaymentData? data;
switch (sd.derivePathType) {
case DerivePathType.bip44:
data = btc
.P2PKH(
data: btc.PaymentData(
pubkey: pubKey,
),
network: _bitcoinDartNetwork,
)
.data;
break;
case DerivePathType.bip49:
final p2wpkh = btc
.P2WPKH(
data: btc.PaymentData(
pubkey: pubKey,
),
network: _bitcoinDartNetwork,
)
.data;
data = btc
.P2SH(
data: btc.PaymentData(redeem: p2wpkh),
network: _bitcoinDartNetwork,
)
.data;
break;
case DerivePathType.bip84:
data = btc
.P2WPKH(
data: btc.PaymentData(
pubkey: pubKey,
),
network: _bitcoinDartNetwork,
)
.data;
break;
case DerivePathType.bip86:
data = null;
break;
default:
throw Exception("DerivePathType unsupported");
}
// add to dummy tx
dummyTxb.addInput(
sd.utxo.txid,
sd.utxo.vout,
0xffffffff -
1, // minus 1 is important. 0xffffffff on its own will burn funds
sd.output,
data!.output!,
);
}
@ -1015,9 +1067,15 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface {
for (var i = 0; i < setCoins.length; i++) {
dummyTxb.sign(
vin: i,
keyPair: setCoins[i].keyPair!,
keyPair: btc.ECPair.fromPrivateKey(
setCoins[i].keyPair!.privateKey.data,
network: _bitcoinDartNetwork,
compressed: setCoins[i].keyPair!.privateKey.compressed,
),
witnessValue: setCoins[i].utxo.value,
redeemScript: setCoins[i].redeemScript,
// maybe not needed here as this was originally copied from btc? We'll find out...
// redeemScript: setCoins[i].redeemScript,
);
}
@ -1114,12 +1172,63 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface {
txb.setVersion(txVersion);
txb.setLockTime(lockTime);
for (final input in vin) {
final pubKey = input.keyPair!.publicKey.data;
final btc.PaymentData? data;
switch (input.derivePathType) {
case DerivePathType.bip44:
data = btc
.P2PKH(
data: btc.PaymentData(
pubkey: pubKey,
),
network: _bitcoinDartNetwork,
)
.data;
break;
case DerivePathType.bip49:
final p2wpkh = btc
.P2WPKH(
data: btc.PaymentData(
pubkey: pubKey,
),
network: _bitcoinDartNetwork,
)
.data;
data = btc
.P2SH(
data: btc.PaymentData(redeem: p2wpkh),
network: _bitcoinDartNetwork,
)
.data;
break;
case DerivePathType.bip84:
data = btc
.P2WPKH(
data: btc.PaymentData(
pubkey: pubKey,
),
network: _bitcoinDartNetwork,
)
.data;
break;
case DerivePathType.bip86:
data = null;
break;
default:
throw Exception("DerivePathType unsupported");
}
txb.addInput(
input.utxo.txid,
input.utxo.vout,
0xffffffff -
1, // minus 1 is important. 0xffffffff on its own will burn funds
input.output,
data!.output!,
);
tempInputs.add(
@ -1172,9 +1281,15 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface {
for (var i = 0; i < vin.length; i++) {
txb.sign(
vin: i,
keyPair: vin[i].keyPair!,
keyPair: btc.ECPair.fromPrivateKey(
vin[i].keyPair!.privateKey.data,
network: _bitcoinDartNetwork,
compressed: vin[i].keyPair!.privateKey.compressed,
),
witnessValue: vin[i].utxo.value,
redeemScript: vin[i].redeemScript,
// maybe not needed here as this was originally copied from btc? We'll find out...
// redeemScript: setCoins[i].redeemScript,
);
}
} catch (e, s) {