mirror of
https://github.com/sparrowwallet/drongo.git
synced 2024-12-26 18:16:45 +00:00
programmatic psbt creation
This commit is contained in:
parent
f00754b157
commit
9b117cd7f9
7 changed files with 178 additions and 41 deletions
|
@ -413,7 +413,7 @@ public class Transaction extends ChildMessage {
|
||||||
for (int i = 0; i < tx.inputs.size(); i++) {
|
for (int i = 0; i < tx.inputs.size(); i++) {
|
||||||
TransactionInput input = tx.inputs.get(i);
|
TransactionInput input = tx.inputs.get(i);
|
||||||
input.clearScriptBytes();
|
input.clearScriptBytes();
|
||||||
input.setWitness(null);
|
input.clearWitness();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This step has no purpose beyond being synchronized with Bitcoin Core's bugs. OP_CODESEPARATOR
|
// This step has no purpose beyond being synchronized with Bitcoin Core's bugs. OP_CODESEPARATOR
|
||||||
|
|
|
@ -96,10 +96,20 @@ public class TransactionInput extends ChildMessage {
|
||||||
return witness;
|
return witness;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWitness(TransactionWitness witness) {
|
void setWitness(TransactionWitness witness) {
|
||||||
this.witness = witness;
|
this.witness = witness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clearWitness() {
|
||||||
|
TransactionWitness witness = getWitness();
|
||||||
|
if(witness != null) {
|
||||||
|
if(getParent() != null) {
|
||||||
|
getParent().adjustLength(-witness.getLength());
|
||||||
|
}
|
||||||
|
setWitness(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasWitness() {
|
public boolean hasWitness() {
|
||||||
return witness != null && witness.getPushCount() != 0;
|
return witness != null && witness.getPushCount() != 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,9 @@ package com.sparrowwallet.drongo.psbt;
|
||||||
import com.sparrowwallet.drongo.ExtendedKey;
|
import com.sparrowwallet.drongo.ExtendedKey;
|
||||||
import com.sparrowwallet.drongo.KeyDerivation;
|
import com.sparrowwallet.drongo.KeyDerivation;
|
||||||
import com.sparrowwallet.drongo.Utils;
|
import com.sparrowwallet.drongo.Utils;
|
||||||
|
import com.sparrowwallet.drongo.crypto.ECKey;
|
||||||
import com.sparrowwallet.drongo.protocol.*;
|
import com.sparrowwallet.drongo.protocol.*;
|
||||||
|
import com.sparrowwallet.drongo.wallet.*;
|
||||||
import org.bouncycastle.util.encoders.Base64;
|
import org.bouncycastle.util.encoders.Base64;
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
import org.bouncycastle.util.encoders.Hex;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -39,14 +41,93 @@ public class PSBT {
|
||||||
|
|
||||||
private Transaction transaction = null;
|
private Transaction transaction = null;
|
||||||
private Integer version = null;
|
private Integer version = null;
|
||||||
private Map<ExtendedKey, KeyDerivation> extendedPublicKeys = new LinkedHashMap<>();
|
private final Map<ExtendedKey, KeyDerivation> extendedPublicKeys = new LinkedHashMap<>();
|
||||||
private Map<String, String> globalProprietary = new LinkedHashMap<>();
|
private final Map<String, String> globalProprietary = new LinkedHashMap<>();
|
||||||
|
|
||||||
private List<PSBTInput> psbtInputs = new ArrayList<>();
|
private final List<PSBTInput> psbtInputs = new ArrayList<>();
|
||||||
private List<PSBTOutput> psbtOutputs = new ArrayList<>();
|
private final List<PSBTOutput> psbtOutputs = new ArrayList<>();
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(PSBT.class);
|
private static final Logger log = LoggerFactory.getLogger(PSBT.class);
|
||||||
|
|
||||||
|
public PSBT(WalletTransaction walletTransaction) {
|
||||||
|
Wallet wallet = walletTransaction.getWallet();
|
||||||
|
|
||||||
|
transaction = new Transaction(walletTransaction.getTransaction().bitcoinSerialize());
|
||||||
|
for(TransactionInput input : transaction.getInputs()) {
|
||||||
|
input.clearScriptBytes();
|
||||||
|
input.clearWitness();
|
||||||
|
}
|
||||||
|
for(Keystore keystore : walletTransaction.getWallet().getKeystores()) {
|
||||||
|
extendedPublicKeys.put(keystore.getExtendedPublicKey(), keystore.getKeyDerivation());
|
||||||
|
}
|
||||||
|
version = 0;
|
||||||
|
|
||||||
|
int inputIndex = 0;
|
||||||
|
for(Iterator<Map.Entry<BlockTransactionHashIndex, WalletNode>> iter = walletTransaction.getSelectedUtxos().entrySet().iterator(); iter.hasNext(); inputIndex++) {
|
||||||
|
Map.Entry<BlockTransactionHashIndex, WalletNode> utxoEntry = iter.next();
|
||||||
|
Transaction utxo = wallet.getTransactions().get(utxoEntry.getKey().getHash()).getTransaction();
|
||||||
|
int utxoIndex = (int)utxoEntry.getKey().getIndex();
|
||||||
|
TransactionOutput utxoOutput = utxo.getOutputs().get(utxoIndex);
|
||||||
|
|
||||||
|
TransactionInput txInput = walletTransaction.getTransaction().getInputs().get(inputIndex);
|
||||||
|
|
||||||
|
Script redeemScript = null;
|
||||||
|
if(ScriptType.P2SH.isScriptType(utxoOutput.getScript())) {
|
||||||
|
redeemScript = txInput.getScriptSig().getFirstNestedScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
Script witnessScript = null;
|
||||||
|
if(txInput.getWitness() != null) {
|
||||||
|
witnessScript = txInput.getWitness().getWitnessScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<ECKey, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>();
|
||||||
|
for(Keystore keystore : wallet.getKeystores()) {
|
||||||
|
WalletNode walletNode = utxoEntry.getValue();
|
||||||
|
derivedPublicKeys.put(keystore.getKey(walletNode.getKeyPurpose(), walletNode.getIndex()), keystore.getKeyDerivation());
|
||||||
|
}
|
||||||
|
|
||||||
|
PSBTInput psbtInput = new PSBTInput(wallet.getScriptType(), transaction, inputIndex, utxo, utxoIndex, redeemScript, witnessScript, derivedPublicKeys, Collections.emptyMap());
|
||||||
|
psbtInputs.add(psbtInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<WalletNode> outputNodes = new ArrayList<>();
|
||||||
|
outputNodes.add(wallet.getWalletAddresses().getOrDefault(walletTransaction.getRecipientAddress(), null));
|
||||||
|
outputNodes.add(walletTransaction.getChangeNode());
|
||||||
|
|
||||||
|
for(int outputIndex = 0; outputIndex < outputNodes.size(); outputIndex++) {
|
||||||
|
WalletNode outputNode = outputNodes.get(outputIndex);
|
||||||
|
if(outputNode == null) {
|
||||||
|
PSBTOutput externalRecipientOutput = new PSBTOutput(null, null, Collections.emptyMap(), Collections.emptyMap());
|
||||||
|
psbtOutputs.add(externalRecipientOutput);
|
||||||
|
} else {
|
||||||
|
TransactionOutput txOutput = walletTransaction.getTransaction().getOutputs().get(outputIndex);
|
||||||
|
|
||||||
|
//Construct dummy transaction to spend the UTXO created by this wallet's txOutput
|
||||||
|
Transaction transaction = new Transaction();
|
||||||
|
TransactionInput spendingInput = wallet.addDummySpendingInput(transaction, outputNode, txOutput);
|
||||||
|
|
||||||
|
Script redeemScript = null;
|
||||||
|
if(ScriptType.P2SH.isScriptType(txOutput.getScript())) {
|
||||||
|
redeemScript = spendingInput.getScriptSig().getFirstNestedScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
Script witnessScript = null;
|
||||||
|
if(spendingInput.getWitness() != null) {
|
||||||
|
witnessScript = spendingInput.getWitness().getWitnessScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<ECKey, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>();
|
||||||
|
for(Keystore keystore : wallet.getKeystores()) {
|
||||||
|
derivedPublicKeys.put(keystore.getKey(outputNode.getKeyPurpose(), outputNode.getIndex()), keystore.getKeyDerivation());
|
||||||
|
}
|
||||||
|
|
||||||
|
PSBTOutput walletOutput = new PSBTOutput(redeemScript, witnessScript, derivedPublicKeys, Collections.emptyMap());
|
||||||
|
psbtOutputs.add(walletOutput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public PSBT(byte[] psbt) throws PSBTParseException {
|
public PSBT(byte[] psbt) throws PSBTParseException {
|
||||||
this.psbtBytes = psbt;
|
this.psbtBytes = psbt;
|
||||||
parse();
|
parse();
|
||||||
|
@ -390,6 +471,10 @@ public class PSBT {
|
||||||
return new ArrayList<ExtendedKey>(extendedPublicKeys.keySet());
|
return new ArrayList<ExtendedKey>(extendedPublicKeys.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getGlobalProprietary() {
|
||||||
|
return globalProprietary;
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
try {
|
try {
|
||||||
return Hex.toHexString(serialize());
|
return Hex.toHexString(serialize());
|
||||||
|
|
|
@ -29,21 +29,39 @@ public class PSBTInput {
|
||||||
|
|
||||||
private Transaction nonWitnessUtxo;
|
private Transaction nonWitnessUtxo;
|
||||||
private TransactionOutput witnessUtxo;
|
private TransactionOutput witnessUtxo;
|
||||||
private Map<ECKey, TransactionSignature> partialSignatures = new LinkedHashMap<>();
|
private final Map<ECKey, TransactionSignature> partialSignatures = new LinkedHashMap<>();
|
||||||
private Transaction.SigHash sigHash;
|
private Transaction.SigHash sigHash;
|
||||||
private Script redeemScript;
|
private Script redeemScript;
|
||||||
private Script witnessScript;
|
private Script witnessScript;
|
||||||
private Map<ECKey, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>();
|
private final Map<ECKey, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>();
|
||||||
private Script finalScriptSig;
|
private Script finalScriptSig;
|
||||||
private TransactionWitness finalScriptWitness;
|
private TransactionWitness finalScriptWitness;
|
||||||
private String porCommitment;
|
private String porCommitment;
|
||||||
private Map<String, String> proprietary = new LinkedHashMap<>();
|
private final Map<String, String> proprietary = new LinkedHashMap<>();
|
||||||
|
|
||||||
private Transaction transaction;
|
private final Transaction transaction;
|
||||||
private int index;
|
private final int index;
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(PSBTInput.class);
|
private static final Logger log = LoggerFactory.getLogger(PSBTInput.class);
|
||||||
|
|
||||||
|
PSBTInput(ScriptType scriptType, Transaction transaction, int index, Transaction utxo, int utxoIndex, Script redeemScript, Script witnessScript, Map<ECKey, KeyDerivation> derivedPublicKeys, Map<String, String> proprietary) {
|
||||||
|
this.transaction = transaction;
|
||||||
|
this.index = index;
|
||||||
|
sigHash = Transaction.SigHash.ALL;
|
||||||
|
|
||||||
|
if(Arrays.asList(ScriptType.WITNESS_TYPES).contains(scriptType)) {
|
||||||
|
this.witnessUtxo = utxo.getOutputs().get(utxoIndex);
|
||||||
|
} else {
|
||||||
|
this.nonWitnessUtxo = utxo;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.redeemScript = redeemScript;
|
||||||
|
this.witnessScript = witnessScript;
|
||||||
|
|
||||||
|
this.derivedPublicKeys.putAll(derivedPublicKeys);
|
||||||
|
this.proprietary.putAll(proprietary);
|
||||||
|
}
|
||||||
|
|
||||||
PSBTInput(List<PSBTEntry> inputEntries, Transaction transaction, int index) throws PSBTParseException {
|
PSBTInput(List<PSBTEntry> inputEntries, Transaction transaction, int index) throws PSBTParseException {
|
||||||
for(PSBTEntry entry : inputEntries) {
|
for(PSBTEntry entry : inputEntries) {
|
||||||
switch(entry.getKeyType()) {
|
switch(entry.getKeyType()) {
|
||||||
|
@ -226,11 +244,9 @@ public class PSBTInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ECKey getKeyForSignature(TransactionSignature signature) {
|
public ECKey getKeyForSignature(TransactionSignature signature) {
|
||||||
if(partialSignatures != null) {
|
for(Map.Entry<ECKey, TransactionSignature> entry : partialSignatures.entrySet()) {
|
||||||
for(Map.Entry<ECKey, TransactionSignature> entry : partialSignatures.entrySet()) {
|
if(entry.getValue().equals(signature)) {
|
||||||
if(entry.getValue().equals(signature)) {
|
return entry.getKey();
|
||||||
return entry.getKey();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.sparrowwallet.drongo.psbt;
|
||||||
|
|
||||||
import com.sparrowwallet.drongo.KeyDerivation;
|
import com.sparrowwallet.drongo.KeyDerivation;
|
||||||
import com.sparrowwallet.drongo.crypto.ECKey;
|
import com.sparrowwallet.drongo.crypto.ECKey;
|
||||||
import com.sparrowwallet.drongo.crypto.LazyECPoint;
|
|
||||||
import com.sparrowwallet.drongo.protocol.Script;
|
import com.sparrowwallet.drongo.protocol.Script;
|
||||||
import org.bouncycastle.util.encoders.Hex;
|
import org.bouncycastle.util.encoders.Hex;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -12,6 +11,8 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.sparrowwallet.drongo.psbt.PSBTEntry.parseKeyDerivation;
|
||||||
|
|
||||||
public class PSBTOutput {
|
public class PSBTOutput {
|
||||||
public static final byte PSBT_OUT_REDEEM_SCRIPT = 0x00;
|
public static final byte PSBT_OUT_REDEEM_SCRIPT = 0x00;
|
||||||
public static final byte PSBT_OUT_WITNESS_SCRIPT = 0x01;
|
public static final byte PSBT_OUT_WITNESS_SCRIPT = 0x01;
|
||||||
|
@ -20,11 +21,18 @@ public class PSBTOutput {
|
||||||
|
|
||||||
private Script redeemScript;
|
private Script redeemScript;
|
||||||
private Script witnessScript;
|
private Script witnessScript;
|
||||||
private Map<LazyECPoint, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>();
|
private final Map<ECKey, KeyDerivation> derivedPublicKeys = new LinkedHashMap<>();
|
||||||
private Map<String, String> proprietary = new LinkedHashMap<>();
|
private final Map<String, String> proprietary = new LinkedHashMap<>();
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(PSBTOutput.class);
|
private static final Logger log = LoggerFactory.getLogger(PSBTOutput.class);
|
||||||
|
|
||||||
|
PSBTOutput(Script redeemScript, Script witnessScript, Map<ECKey, KeyDerivation> derivedPublicKeys, Map<String, String> proprietary) {
|
||||||
|
this.redeemScript = redeemScript;
|
||||||
|
this.witnessScript = witnessScript;
|
||||||
|
this.derivedPublicKeys.putAll(derivedPublicKeys);
|
||||||
|
this.proprietary.putAll(proprietary);
|
||||||
|
}
|
||||||
|
|
||||||
PSBTOutput(List<PSBTEntry> outputEntries) throws PSBTParseException {
|
PSBTOutput(List<PSBTEntry> outputEntries) throws PSBTParseException {
|
||||||
for(PSBTEntry entry : outputEntries) {
|
for(PSBTEntry entry : outputEntries) {
|
||||||
switch (entry.getKeyType()) {
|
switch (entry.getKeyType()) {
|
||||||
|
@ -42,10 +50,10 @@ public class PSBTOutput {
|
||||||
break;
|
break;
|
||||||
case PSBT_OUT_BIP32_DERIVATION:
|
case PSBT_OUT_BIP32_DERIVATION:
|
||||||
entry.checkOneBytePlusPubKey();
|
entry.checkOneBytePlusPubKey();
|
||||||
LazyECPoint publicKey = new LazyECPoint(ECKey.CURVE.getCurve(), entry.getKeyData());
|
ECKey derivedPublicKey = ECKey.fromPublicOnly(entry.getKeyData());
|
||||||
KeyDerivation keyDerivation = PSBTEntry.parseKeyDerivation(entry.getData());
|
KeyDerivation keyDerivation = parseKeyDerivation(entry.getData());
|
||||||
this.derivedPublicKeys.put(publicKey, keyDerivation);
|
this.derivedPublicKeys.put(derivedPublicKey, keyDerivation);
|
||||||
log.debug("Found output bip32_derivation with master fingerprint " + keyDerivation.getMasterFingerprint() + " at path " + keyDerivation.getDerivationPath() + " public key " + publicKey);
|
log.debug("Found output bip32_derivation with master fingerprint " + keyDerivation.getMasterFingerprint() + " at path " + keyDerivation.getDerivationPath() + " public key " + derivedPublicKey);
|
||||||
break;
|
break;
|
||||||
case PSBT_OUT_PROPRIETARY:
|
case PSBT_OUT_PROPRIETARY:
|
||||||
proprietary.put(Hex.toHexString(entry.getKeyData()), Hex.toHexString(entry.getData()));
|
proprietary.put(Hex.toHexString(entry.getKeyData()), Hex.toHexString(entry.getData()));
|
||||||
|
@ -65,11 +73,11 @@ public class PSBTOutput {
|
||||||
return witnessScript;
|
return witnessScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyDerivation getKeyDerivation(LazyECPoint publicKey) {
|
public KeyDerivation getKeyDerivation(ECKey publicKey) {
|
||||||
return derivedPublicKeys.get(publicKey);
|
return derivedPublicKeys.get(publicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<LazyECPoint, KeyDerivation> getDerivedPublicKeys() {
|
public Map<ECKey, KeyDerivation> getDerivedPublicKeys() {
|
||||||
return derivedPublicKeys;
|
return derivedPublicKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import com.sparrowwallet.drongo.protocol.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
import static com.sparrowwallet.drongo.protocol.Transaction.WITNESS_SCALE_FACTOR;
|
import static com.sparrowwallet.drongo.protocol.Transaction.WITNESS_SCALE_FACTOR;
|
||||||
|
|
||||||
|
@ -233,6 +234,23 @@ public class Wallet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isWalletAddress(Address address) {
|
||||||
|
return getWalletAddresses().containsKey(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Address, WalletNode> getWalletAddresses() {
|
||||||
|
Map<Address, WalletNode> walletAddresses = new LinkedHashMap<>();
|
||||||
|
getWalletAddresses(walletAddresses, getNode(KeyPurpose.RECEIVE));
|
||||||
|
getWalletAddresses(walletAddresses, getNode(KeyPurpose.CHANGE));
|
||||||
|
return walletAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getWalletAddresses(Map<Address, WalletNode> walletAddresses, WalletNode purposeNode) {
|
||||||
|
for(WalletNode addressNode : purposeNode.getChildren()) {
|
||||||
|
walletAddresses.put(getAddress(addressNode), addressNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isWalletTxo(BlockTransactionHashIndex txo) {
|
public boolean isWalletTxo(BlockTransactionHashIndex txo) {
|
||||||
return getWalletTxos().containsKey(txo);
|
return getWalletTxos().containsKey(txo);
|
||||||
}
|
}
|
||||||
|
@ -386,20 +404,7 @@ public class Wallet {
|
||||||
for(Map.Entry<BlockTransactionHashIndex, WalletNode> selectedUtxo : selectedUtxos.entrySet()) {
|
for(Map.Entry<BlockTransactionHashIndex, WalletNode> selectedUtxo : selectedUtxos.entrySet()) {
|
||||||
Transaction prevTx = getTransactions().get(selectedUtxo.getKey().getHash()).getTransaction();
|
Transaction prevTx = getTransactions().get(selectedUtxo.getKey().getHash()).getTransaction();
|
||||||
TransactionOutput prevTxOut = prevTx.getOutputs().get((int)selectedUtxo.getKey().getIndex());
|
TransactionOutput prevTxOut = prevTx.getOutputs().get((int)selectedUtxo.getKey().getIndex());
|
||||||
|
addDummySpendingInput(transaction, selectedUtxo.getValue(), prevTxOut);
|
||||||
if(getPolicyType().equals(PolicyType.SINGLE)) {
|
|
||||||
ECKey pubKey = getPubKey(selectedUtxo.getValue());
|
|
||||||
TransactionSignature signature = TransactionSignature.dummy();
|
|
||||||
getScriptType().addSpendingInput(transaction, prevTxOut, pubKey, signature);
|
|
||||||
} else if(getPolicyType().equals(PolicyType.MULTI)) {
|
|
||||||
List<ECKey> pubKeys = getPubKeys(selectedUtxo.getValue());
|
|
||||||
int threshold = getDefaultPolicy().getNumSignaturesRequired();
|
|
||||||
List<TransactionSignature> signatures = new ArrayList<>(threshold);
|
|
||||||
for(int i = 0; i < threshold; i++) {
|
|
||||||
signatures.add(TransactionSignature.dummy());
|
|
||||||
}
|
|
||||||
getScriptType().addMultisigSpendingInput(transaction, prevTxOut, threshold, pubKeys, signatures);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add recipient output
|
//Add recipient output
|
||||||
|
@ -451,6 +456,20 @@ public class Wallet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TransactionInput addDummySpendingInput(Transaction transaction, WalletNode walletNode, TransactionOutput prevTxOut) {
|
||||||
|
if(getPolicyType().equals(PolicyType.SINGLE)) {
|
||||||
|
ECKey pubKey = getPubKey(walletNode);
|
||||||
|
return getScriptType().addSpendingInput(transaction, prevTxOut, pubKey, TransactionSignature.dummy());
|
||||||
|
} else if(getPolicyType().equals(PolicyType.MULTI)) {
|
||||||
|
List<ECKey> pubKeys = getPubKeys(walletNode);
|
||||||
|
int threshold = getDefaultPolicy().getNumSignaturesRequired();
|
||||||
|
List<TransactionSignature> signatures = IntStream.range(0, threshold).mapToObj(i -> TransactionSignature.dummy()).collect(Collectors.toList());
|
||||||
|
return getScriptType().addMultisigSpendingInput(transaction, prevTxOut, threshold, pubKeys, signatures);
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("Cannot create transaction for policy type " + getPolicyType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Map<BlockTransactionHashIndex, WalletNode> selectInputs(List<UtxoSelector> utxoSelectors, Long targetValue, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeMempoolChange) throws InsufficientFundsException {
|
private Map<BlockTransactionHashIndex, WalletNode> selectInputs(List<UtxoSelector> utxoSelectors, Long targetValue, double feeRate, double longTermFeeRate, boolean groupByAddress, boolean includeMempoolChange) throws InsufficientFundsException {
|
||||||
List<OutputGroup> utxoPool = getGroupedUtxos(feeRate, longTermFeeRate, groupByAddress);
|
List<OutputGroup> utxoPool = getGroupedUtxos(feeRate, longTermFeeRate, groupByAddress);
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,7 @@ public class WalletTransaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
public PSBT createPSBT() {
|
public PSBT createPSBT() {
|
||||||
//TODO: Create PSBT
|
return new PSBT(this);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Wallet getWallet() {
|
public Wallet getWallet() {
|
||||||
|
|
Loading…
Reference in a new issue