mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2025-11-05 11:56:37 +00:00
- Added code to create coinjoin PSBT
This commit is contained in:
parent
055bc65bff
commit
550df1d91a
6 changed files with 85 additions and 88 deletions
|
|
@ -556,7 +556,7 @@ public class AppController implements Initializable {
|
|||
stage.initOwner(tabs.getScene().getWindow());
|
||||
|
||||
JoinstrController controller = loader.getController();
|
||||
JoinstrForm joinstrForm = new JoinstrForm(getSelectedWalletForm().getStorage(), getSelectedWalletForm().getWallet());
|
||||
JoinstrForm joinstrForm = new JoinstrForm(getSelectedWalletForm());
|
||||
controller.setJoinstrForm(joinstrForm);
|
||||
|
||||
Scene scene = new Scene(root);
|
||||
|
|
|
|||
|
|
@ -57,26 +57,21 @@ public class JoinstrController extends JoinstrFormController {
|
|||
}
|
||||
|
||||
try {
|
||||
URL url = AppServices.class.getResource("joinstr/" + display.toString().toLowerCase(Locale.ROOT) + ".fxml");
|
||||
if(url == null) {
|
||||
throw new IllegalStateException("Cannot find joinstr/" + display.toString().toLowerCase(Locale.ROOT) + ".fxml");
|
||||
}
|
||||
|
||||
FXMLLoader displayLoader = new FXMLLoader(url);
|
||||
Node joinstrDisplay = displayLoader.load();
|
||||
|
||||
if(!existing) {
|
||||
|
||||
joinstrDisplay.setUserData(display);
|
||||
joinstrDisplay.setViewOrder(1);
|
||||
|
||||
joinstrPane.getChildren().add(joinstrDisplay);
|
||||
}
|
||||
|
||||
JoinstrFormController controller = displayLoader.getController();
|
||||
JoinstrForm joinstrForm = getJoinstrForm();
|
||||
controller.setJoinstrForm(joinstrForm);
|
||||
controller.initializeView();
|
||||
URL url = AppServices.class.getResource("joinstr/" + display.toString().toLowerCase(Locale.ROOT) + ".fxml");
|
||||
if(url == null) {
|
||||
throw new IllegalStateException("Cannot find joinstr/" + display.toString().toLowerCase(Locale.ROOT) + ".fxml");
|
||||
}
|
||||
FXMLLoader displayLoader = new FXMLLoader(url);
|
||||
Node joinstrDisplay = displayLoader.load();
|
||||
if(!existing) {
|
||||
joinstrDisplay.setUserData(display);
|
||||
joinstrDisplay.setViewOrder(1);
|
||||
joinstrPane.getChildren().add(joinstrDisplay);
|
||||
}
|
||||
JoinstrFormController controller = displayLoader.getController();
|
||||
JoinstrForm joinstrForm = getJoinstrForm();
|
||||
controller.setJoinstrForm(joinstrForm);
|
||||
controller.initializeView();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Can't find pane", e);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.sparrowwallet.sparrow.joinstr;
|
|||
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.sparrow.io.Storage;
|
||||
import com.sparrowwallet.sparrow.wallet.WalletForm;
|
||||
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
|
|
@ -10,20 +11,22 @@ public class JoinstrForm {
|
|||
|
||||
private final BooleanProperty lockedProperty = new SimpleBooleanProperty(false);
|
||||
|
||||
private final Storage storage;
|
||||
protected Wallet wallet;
|
||||
private final WalletForm walletForm;
|
||||
|
||||
public JoinstrForm(Storage storage, Wallet currentWallet) {
|
||||
this.storage = storage;
|
||||
this.wallet = currentWallet;
|
||||
public JoinstrForm(WalletForm walletForm) {
|
||||
this.walletForm = walletForm;
|
||||
}
|
||||
|
||||
public WalletForm getWalletForm() {
|
||||
return walletForm;
|
||||
}
|
||||
|
||||
public Wallet getWallet() {
|
||||
return wallet;
|
||||
return walletForm.getWallet();
|
||||
}
|
||||
|
||||
public Storage getStorage() {
|
||||
return storage;
|
||||
return walletForm.getStorage();
|
||||
}
|
||||
|
||||
public BooleanProperty lockedProperty() {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
package com.sparrowwallet.sparrow.joinstr;
|
||||
|
||||
import com.sparrowwallet.sparrow.BaseController;
|
||||
import com.sparrowwallet.sparrow.wallet.WalletForm;
|
||||
|
||||
public abstract class JoinstrFormController extends BaseController {
|
||||
|
||||
public JoinstrForm joinstrForm;
|
||||
private JoinstrForm joinstrForm;
|
||||
|
||||
public WalletForm getWalletForm() {
|
||||
return joinstrForm.getWalletForm();
|
||||
}
|
||||
|
||||
public JoinstrForm getJoinstrForm() {
|
||||
return joinstrForm;
|
||||
|
|
|
|||
|
|
@ -3,20 +3,32 @@ package com.sparrowwallet.sparrow.joinstr;
|
|||
import com.sparrowwallet.drongo.KeyPurpose;
|
||||
import com.sparrowwallet.drongo.address.Address;
|
||||
import com.sparrowwallet.drongo.protocol.Transaction;
|
||||
import com.sparrowwallet.drongo.protocol.TransactionOutput;
|
||||
import com.sparrowwallet.drongo.psbt.PSBT;
|
||||
import com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex;
|
||||
import com.sparrowwallet.drongo.wallet.BnBUtxoSelector;
|
||||
import com.sparrowwallet.drongo.wallet.CoinbaseTxoFilter;
|
||||
import com.sparrowwallet.drongo.wallet.FrozenTxoFilter;
|
||||
import com.sparrowwallet.drongo.wallet.InsufficientFundsException;
|
||||
import com.sparrowwallet.drongo.wallet.KnapsackUtxoSelector;
|
||||
import com.sparrowwallet.drongo.wallet.Payment;
|
||||
import com.sparrowwallet.drongo.wallet.SpentTxoFilter;
|
||||
import com.sparrowwallet.drongo.wallet.StonewallUtxoSelector;
|
||||
import com.sparrowwallet.drongo.wallet.TxoFilter;
|
||||
import com.sparrowwallet.drongo.wallet.UtxoSelector;
|
||||
import com.sparrowwallet.drongo.wallet.Wallet;
|
||||
import com.sparrowwallet.drongo.wallet.WalletNode;
|
||||
import com.sparrowwallet.drongo.wallet.WalletTransaction;
|
||||
import com.sparrowwallet.sparrow.AppServices;
|
||||
import com.sparrowwallet.sparrow.control.QRScanDialog;
|
||||
import com.sparrowwallet.sparrow.io.WalletTransactions;
|
||||
import com.sparrowwallet.sparrow.net.Tor;
|
||||
import com.sparrowwallet.sparrow.wallet.Entry;
|
||||
import com.sparrowwallet.sparrow.wallet.NodeEntry;
|
||||
import com.sparrowwallet.sparrow.wallet.OptimizationStrategy;
|
||||
import com.sparrowwallet.sparrow.wallet.UtxoEntry;
|
||||
import com.sparrowwallet.sparrow.wallet.WalletForm;
|
||||
import com.sparrowwallet.sparrow.wallet.WalletUtxosEntry;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
|
@ -66,21 +78,7 @@ public class JoinstrPool {
|
|||
return freshNodeEntry.getAddress();
|
||||
}
|
||||
|
||||
public void createPSBT() {
|
||||
|
||||
Address sendAddress = getNewSendAddress();
|
||||
|
||||
/* String to byte[]
|
||||
|
||||
if(Utils.isBase64(string) && !Utils.isHex(string)) {
|
||||
addTransactionTab(name, file, Base64.getDecoder().decode(string));
|
||||
} else if(Utils.isHex(string)) {
|
||||
addTransactionTab(name, file, Utils.hexToBytes(string));
|
||||
} else {
|
||||
throw new ParseException("Input is not base64 or hex", 0);
|
||||
}
|
||||
|
||||
*/
|
||||
public void createPSBT() throws InsufficientFundsException {
|
||||
|
||||
/* PSBT from byte[]
|
||||
|
||||
|
|
@ -102,61 +100,51 @@ public class JoinstrPool {
|
|||
result.psbt;
|
||||
*/
|
||||
|
||||
/* PSBT from TransactionData
|
||||
TransactionData txdata;
|
||||
/// TODO fill txdata
|
||||
psbt = txdata.getPsbt();
|
||||
*/
|
||||
|
||||
// PSBT from WalletTransaction
|
||||
|
||||
List<UtxoSelector> utxoSelectors;
|
||||
/// TODO select UTXO for transaction
|
||||
Address sendAddress = getNewSendAddress();
|
||||
Wallet wallet = walletForm.getWallet();
|
||||
double feeRate = 1.0;
|
||||
double longTermFeeRate = 10.0;
|
||||
long fee = 10L;
|
||||
long dustThreshold = getRecipientDustThreshold(sendAddress);
|
||||
long amount = wallet.getWalletTxos().keySet().stream().mapToLong(BlockTransactionHashIndex::getValue).sum();
|
||||
long satsLeft = amount;
|
||||
|
||||
SpentTxoFilter spentTxoFilter = new SpentTxoFilter(null);
|
||||
List<TxoFilter> txoFilters = List.of(spentTxoFilter, new FrozenTxoFilter(), new CoinbaseTxoFilter(walletForm.getWallet()));
|
||||
String paymentLabel = "coinjoin";
|
||||
|
||||
long satsLeft = 0L;
|
||||
Payment coinjoinPayment = new Payment(sendAddress, "coinjoin", denomination, false);
|
||||
/// TODO create multiple coinjoin payments for selected UTXO
|
||||
Payment changePayment = new Payment(sendAddress, "change", satsLeft, false);
|
||||
List<Payment> payments = List.of(coinjoinPayment, changePayment);
|
||||
ArrayList<Payment> payments = new ArrayList<Payment>();
|
||||
while(satsLeft > denomination + dustThreshold) {
|
||||
Payment payment = new Payment(sendAddress, paymentLabel, denomination, false);
|
||||
satsLeft -= denomination;
|
||||
payment.setType(Payment.Type.COINJOIN);
|
||||
payments.add(payment);
|
||||
}
|
||||
|
||||
List<byte[]> opReturns = null;
|
||||
List<UtxoSelector> selectors = new ArrayList<>();
|
||||
long noInputsFee = wallet.getNoInputsFee(payments, feeRate);
|
||||
long costOfChange = wallet.getCostOfChange(feeRate, longTermFeeRate);
|
||||
selectors.addAll(List.of(new BnBUtxoSelector(noInputsFee, costOfChange), new KnapsackUtxoSelector(noInputsFee)));
|
||||
|
||||
Set<WalletNode> excludedChangeNodes;
|
||||
/// TODO fill excludedChangeNodes
|
||||
SpentTxoFilter spentTxoFilter = new SpentTxoFilter(null);
|
||||
List<TxoFilter> txoFilters = List.of(spentTxoFilter, new FrozenTxoFilter(), new CoinbaseTxoFilter(walletForm.getWallet()));
|
||||
|
||||
double feeRate = 10.0;
|
||||
double longTermFeeRate = 10.0;
|
||||
Long fee = 10L;
|
||||
Integer currentBlockHeight = AppServices.getCurrentBlockHeight();
|
||||
boolean groupByAddress = false;
|
||||
boolean includeMempoolOutputs = false;
|
||||
ArrayList<byte[]> opReturns = new ArrayList<>();
|
||||
TreeSet<WalletNode> excludedChangeNodes = new TreeSet<>();
|
||||
|
||||
WalletTransaction toSign = walletForm.getWallet().createWalletTransaction(utxoSelectors, txoFilters, payments, opReturns, excludedChangeNodes, feeRate, longTermFeeRate, fee, currentBlockHeight, groupByAddress, includeMempoolOutputs);
|
||||
PSBT psbt = toSign.createPSBT();
|
||||
Integer currentBlockHeight = AppServices.getCurrentBlockHeight();
|
||||
boolean groupByAddress = false;
|
||||
boolean includeMempoolOutputs = false;
|
||||
|
||||
// decryptedWallet.sign(psbt);
|
||||
// decryptedWallet.finalise(psbt);
|
||||
// Transaction transaction = psbt.extractTransaction();
|
||||
WalletTransaction walletTransaction = walletForm.getWallet().createWalletTransaction(selectors, txoFilters, payments, opReturns, excludedChangeNodes, feeRate, longTermFeeRate, fee, currentBlockHeight, groupByAddress, includeMempoolOutputs);
|
||||
PSBT psbt = walletTransaction.createPSBT();
|
||||
|
||||
/* PSBT from Transaction
|
||||
|
||||
|
||||
PSBT psbt = new PSBT(toSign);
|
||||
PSBTInput psbtInput = psbt.getPsbtInputs().get(0);
|
||||
|
||||
Transaction toSpend;
|
||||
/// TODO fill toSpend
|
||||
TransactionOutput utxoOutput = toSpend.getOutputs().get(0);
|
||||
psbtInput.setWitnessUtxo(utxoOutput);
|
||||
|
||||
psbtInput.setSigHash(SigHash.ALL);
|
||||
psbtInput.sign(scriptType.getOutputKey(privKey));
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
private long getRecipientDustThreshold(Address address) {
|
||||
TransactionOutput txOutput = new TransactionOutput(new Transaction(), 1L, address.getOutputScript());
|
||||
return address.getScriptType().getDustThreshold(txOutput, Transaction.DUST_RELAY_TX_FEE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.sparrowwallet.sparrow.joinstr;
|
||||
|
||||
import com.sparrowwallet.sparrow.io.Config;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.Alert;
|
||||
|
|
@ -19,6 +20,7 @@ public class NewPoolController extends JoinstrFormController {
|
|||
@FXML
|
||||
private void handleCreateButton() {
|
||||
try {
|
||||
|
||||
String denomination = denominationField.getText().trim();
|
||||
String peers = peersField.getText().trim();
|
||||
|
||||
|
|
@ -49,7 +51,11 @@ public class NewPoolController extends JoinstrFormController {
|
|||
return;
|
||||
}
|
||||
|
||||
long denominationSats = Long.valueOf((long) (Double.parseDouble(denomination)*100000000.0D));
|
||||
|
||||
// TODO: Implement pool creation logic here
|
||||
JoinstrPool pool = new JoinstrPool(getWalletForm(), Config.get().getNostrRelay(),9999, "pubkey", denominationSats);
|
||||
pool.createPSBT();
|
||||
|
||||
/*
|
||||
Alert alert = new Alert(AlertType.INFORMATION);
|
||||
|
|
|
|||
Loading…
Reference in a new issue