Search in sources :

Example 6 with Transaction

use of com.sparrowwallet.drongo.protocol.Transaction in project sparrow by sparrowwallet.

the class Payjoin method checkProposal.

private void checkProposal(PSBT original, PSBT proposal, int changeOutputIndex, long maxAdditionalFeeContribution, boolean allowOutputSubstitution) throws PayjoinReceiverException {
    Queue<Map.Entry<TransactionInput, PSBTInput>> originalInputs = new ArrayDeque<>();
    for (int i = 0; i < original.getPsbtInputs().size(); i++) {
        originalInputs.add(Map.entry(original.getTransaction().getInputs().get(i), original.getPsbtInputs().get(i)));
    }
    Queue<Map.Entry<TransactionOutput, PSBTOutput>> originalOutputs = new ArrayDeque<>();
    for (int i = 0; i < original.getPsbtOutputs().size(); i++) {
        originalOutputs.add(Map.entry(original.getTransaction().getOutputs().get(i), original.getPsbtOutputs().get(i)));
    }
    // Checking that the PSBT of the receiver is clean
    if (!proposal.getExtendedPublicKeys().isEmpty()) {
        throw new PayjoinReceiverException("Global xpubs should not be included in the receiver's PSBT");
    }
    Transaction originalTx = original.getTransaction();
    Transaction proposalTx = proposal.getTransaction();
    // Verify that the transaction version, and nLockTime are unchanged.
    if (proposalTx.getVersion() != originalTx.getVersion()) {
        throw new PayjoinReceiverException("The proposal PSBT changed the transaction version");
    }
    if (proposalTx.getLocktime() != originalTx.getLocktime()) {
        throw new PayjoinReceiverException("The proposal PSBT changed the nLocktime");
    }
    Set<Long> sequences = new HashSet<>();
    // For each inputs in the proposal:
    for (PSBTInput proposedPSBTInput : proposal.getPsbtInputs()) {
        if (!proposedPSBTInput.getDerivedPublicKeys().isEmpty()) {
            throw new PayjoinReceiverException("The receiver added keypaths to an input");
        }
        if (!proposedPSBTInput.getPartialSignatures().isEmpty()) {
            throw new PayjoinReceiverException("The receiver added partial signatures to an input");
        }
        TransactionInput proposedTxIn = proposedPSBTInput.getInput();
        boolean isOriginalInput = originalInputs.size() > 0 && originalInputs.peek().getKey().getOutpoint().equals(proposedTxIn.getOutpoint());
        if (isOriginalInput) {
            Map.Entry<TransactionInput, PSBTInput> originalInput = originalInputs.remove();
            TransactionInput originalTxIn = originalInput.getKey();
            // Verify that sequence is unchanged.
            if (originalTxIn.getSequenceNumber() != proposedTxIn.getSequenceNumber()) {
                throw new PayjoinReceiverException("The proposed transaction input modified the sequence of one of the original inputs");
            }
            // Verify the PSBT input is not finalized
            if (proposedPSBTInput.isFinalized()) {
                throw new PayjoinReceiverException("The receiver finalized one of the original inputs");
            }
            // Verify that non_witness_utxo and witness_utxo are not specified.
            if (proposedPSBTInput.getNonWitnessUtxo() != null || proposedPSBTInput.getWitnessUtxo() != null) {
                throw new PayjoinReceiverException("The receiver added non_witness_utxo or witness_utxo to one of the original inputs");
            }
            sequences.add(proposedTxIn.getSequenceNumber());
            PSBTInput originalPSBTInput = originalInput.getValue();
            // Fill up the info from the original PSBT input so we can sign and get fees.
            proposedPSBTInput.setNonWitnessUtxo(originalPSBTInput.getNonWitnessUtxo());
            proposedPSBTInput.setWitnessUtxo(originalPSBTInput.getWitnessUtxo());
            // We fill up information we had on the signed PSBT, so we can sign it.
            proposedPSBTInput.getDerivedPublicKeys().putAll(originalPSBTInput.getDerivedPublicKeys());
            proposedPSBTInput.getProprietary().putAll(originalPSBTInput.getProprietary());
            proposedPSBTInput.setRedeemScript(originalPSBTInput.getFinalScriptSig().getFirstNestedScript());
            proposedPSBTInput.setWitnessScript(originalPSBTInput.getFinalScriptWitness().getWitnessScript());
            proposedPSBTInput.setSigHash(originalPSBTInput.getSigHash());
        } else {
            // Verify the PSBT input is finalized
            if (!proposedPSBTInput.isFinalized()) {
                throw new PayjoinReceiverException("The receiver did not finalize one of their inputs");
            }
            // Verify that non_witness_utxo or witness_utxo are filled in.
            if (proposedPSBTInput.getNonWitnessUtxo() == null && proposedPSBTInput.getWitnessUtxo() == null) {
                throw new PayjoinReceiverException("The receiver did not specify non_witness_utxo or witness_utxo for one of their inputs");
            }
            sequences.add(proposedTxIn.getSequenceNumber());
            // Verify that the payjoin proposal did not introduced mixed inputs' type.
            if (wallet.getScriptType() != proposedPSBTInput.getScriptType()) {
                throw new PayjoinReceiverException("Proposal script type of " + proposedPSBTInput.getScriptType() + " did not match wallet script type of " + wallet.getScriptType());
            }
        }
    }
    // Verify that all of sender's inputs from the original PSBT are in the proposal.
    if (!originalInputs.isEmpty()) {
        throw new PayjoinReceiverException("Some of the original inputs are not included in the proposal");
    }
    // Verify that the payjoin proposal did not introduced mixed inputs' sequence.
    if (sequences.size() != 1) {
        throw new PayjoinReceiverException("Mixed sequences detected in the proposal");
    }
    Long newFee = proposal.getFee();
    long additionalFee = newFee - original.getFee();
    if (additionalFee < 0) {
        throw new PayjoinReceiverException("The receiver decreased absolute fee");
    }
    TransactionOutput changeOutput = (changeOutputIndex > -1 ? originalTx.getOutputs().get(changeOutputIndex) : null);
    // For each outputs in the proposal:
    for (int i = 0; i < proposal.getPsbtOutputs().size(); i++) {
        PSBTOutput proposedPSBTOutput = proposal.getPsbtOutputs().get(i);
        // Verify that no keypaths is in the PSBT output
        if (!proposedPSBTOutput.getDerivedPublicKeys().isEmpty()) {
            throw new PayjoinReceiverException("The receiver added keypaths to an output");
        }
        TransactionOutput proposedTxOut = proposalTx.getOutputs().get(i);
        boolean isOriginalOutput = originalOutputs.size() > 0 && originalOutputs.peek().getKey().getScript().equals(proposedTxOut.getScript());
        if (isOriginalOutput) {
            Map.Entry<TransactionOutput, PSBTOutput> originalOutput = originalOutputs.remove();
            if (originalOutput.getKey() == changeOutput) {
                var actualContribution = changeOutput.getValue() - proposedTxOut.getValue();
                // The amount that was subtracted from the output's value is less than or equal to maxadditionalfeecontribution
                if (actualContribution > maxAdditionalFeeContribution) {
                    throw new PayjoinReceiverException("The actual contribution is more than maxadditionalfeecontribution");
                }
                // Make sure the actual contribution is only paying fee
                if (actualContribution > additionalFee) {
                    throw new PayjoinReceiverException("The actual contribution is not only paying fee");
                }
                // Make sure the actual contribution is only paying for fee incurred by additional inputs
                int additionalInputsCount = proposalTx.getInputs().size() - originalTx.getInputs().size();
                if (actualContribution > getSingleInputFee() * additionalInputsCount) {
                    throw new PayjoinReceiverException("The actual contribution is not only paying for additional inputs");
                }
            } else if (allowOutputSubstitution && originalOutput.getKey().getScript().equals(payjoinURI.getAddress().getOutputScript())) {
            // That's the payment output, the receiver may have changed it.
            } else {
                if (originalOutput.getKey().getValue() > proposedTxOut.getValue()) {
                    throw new PayjoinReceiverException("The receiver decreased the value of one of the outputs");
                }
            }
            PSBTOutput originalPSBTOutput = originalOutput.getValue();
            // We fill up information we had on the signed PSBT, so we can sign it.
            proposedPSBTOutput.getDerivedPublicKeys().putAll(originalPSBTOutput.getDerivedPublicKeys());
            proposedPSBTOutput.getProprietary().putAll(originalPSBTOutput.getProprietary());
            proposedPSBTOutput.setRedeemScript(originalPSBTOutput.getRedeemScript());
            proposedPSBTOutput.setWitnessScript(originalPSBTOutput.getWitnessScript());
        }
    }
    // Verify that all of sender's outputs from the original PSBT are in the proposal.
    if (!originalOutputs.isEmpty()) {
        // The payment output may have been substituted
        if (!allowOutputSubstitution || originalOutputs.size() != 1 || !originalOutputs.remove().getKey().getScript().equals(payjoinURI.getAddress().getOutputScript())) {
            throw new PayjoinReceiverException("Some of our outputs are not included in the proposal");
        }
    }
    // Add global pubkey map for signing
    proposal.getExtendedPublicKeys().putAll(psbt.getExtendedPublicKeys());
    proposal.getGlobalProprietary().putAll(psbt.getGlobalProprietary());
}
Also used : TransactionOutput(com.sparrowwallet.drongo.protocol.TransactionOutput) PSBTOutput(com.sparrowwallet.drongo.psbt.PSBTOutput) TransactionInput(com.sparrowwallet.drongo.protocol.TransactionInput) Transaction(com.sparrowwallet.drongo.protocol.Transaction) PSBTInput(com.sparrowwallet.drongo.psbt.PSBTInput) ImmutableMap(com.google.common.collect.ImmutableMap)

Example 7 with Transaction

use of com.sparrowwallet.drongo.protocol.Transaction in project sparrow by sparrowwallet.

the class SorobanController method getWalletTransaction.

private WalletTransaction getWalletTransaction(Wallet wallet, WalletTransaction walletTransaction, Transaction transaction, Map<Sha256Hash, BlockTransaction> inputTransactions) {
    Map<BlockTransactionHashIndex, WalletNode> allWalletUtxos = wallet.getWalletTxos();
    Map<BlockTransactionHashIndex, WalletNode> walletUtxos = new LinkedHashMap<>();
    Map<BlockTransactionHashIndex, WalletNode> externalUtxos = new LinkedHashMap<>();
    for (TransactionInput txInput : transaction.getInputs()) {
        Optional<BlockTransactionHashIndex> optWalletUtxo = allWalletUtxos.keySet().stream().filter(txo -> txo.getHash().equals(txInput.getOutpoint().getHash()) && txo.getIndex() == txInput.getOutpoint().getIndex()).findFirst();
        if (optWalletUtxo.isPresent()) {
            walletUtxos.put(optWalletUtxo.get(), allWalletUtxos.get(optWalletUtxo.get()));
        } else {
            BlockTransactionHashIndex externalUtxo;
            if (inputTransactions != null && inputTransactions.containsKey(txInput.getOutpoint().getHash())) {
                BlockTransaction blockTransaction = inputTransactions.get(txInput.getOutpoint().getHash());
                TransactionOutput txOutput = blockTransaction.getTransaction().getOutputs().get((int) txInput.getOutpoint().getIndex());
                externalUtxo = new BlockTransactionHashIndex(blockTransaction.getHash(), blockTransaction.getHeight(), blockTransaction.getDate(), blockTransaction.getFee(), txInput.getOutpoint().getIndex(), txOutput.getValue());
            } else {
                externalUtxo = new BlockTransactionHashIndex(txInput.getOutpoint().getHash(), 0, null, null, txInput.getOutpoint().getIndex(), 0);
            }
            externalUtxos.put(externalUtxo, null);
        }
    }
    List<Map<BlockTransactionHashIndex, WalletNode>> selectedUtxoSets = new ArrayList<>();
    selectedUtxoSets.add(walletUtxos);
    selectedUtxoSets.add(externalUtxos);
    Map<Address, WalletNode> walletAddresses = wallet.getWalletAddresses();
    List<Payment> payments = new ArrayList<>();
    Map<WalletNode, Long> changeMap = new LinkedHashMap<>();
    for (TransactionOutput txOutput : transaction.getOutputs()) {
        Address address = txOutput.getScript().getToAddress();
        if (address != null) {
            Optional<Payment> optPayment = walletTransaction == null ? Optional.empty() : walletTransaction.getPayments().stream().filter(payment -> payment.getAddress().equals(address) && payment.getAmount() == txOutput.getValue()).findFirst();
            if (optPayment.isPresent()) {
                payments.add(optPayment.get());
            } else if (walletAddresses.containsKey(address) && walletAddresses.get(address).getKeyPurpose() == KeyPurpose.CHANGE) {
                changeMap.put(walletAddresses.get(address), txOutput.getValue());
            } else {
                Payment payment = new Payment(address, null, txOutput.getValue(), false);
                if (transaction.getOutputs().stream().anyMatch(txo -> txo != txOutput && txo.getValue() == txOutput.getValue())) {
                    payment.setType(Payment.Type.MIX);
                }
                payments.add(payment);
            }
        }
    }
    long fee = calculateFee(walletTransaction, selectedUtxoSets, transaction);
    return new WalletTransaction(wallet, transaction, Collections.emptyList(), selectedUtxoSets, payments, changeMap, fee, inputTransactions);
}
Also used : Address(com.sparrowwallet.drongo.address.Address) Transaction(com.sparrowwallet.drongo.protocol.Transaction) java.util(java.util) Logger(org.slf4j.Logger) PSBT(com.sparrowwallet.drongo.psbt.PSBT) com.sparrowwallet.drongo.wallet(com.sparrowwallet.drongo.wallet) LoggerFactory(org.slf4j.LoggerFactory) Collectors(java.util.stream.Collectors) Cahoots(com.samourai.wallet.cahoots.Cahoots) KeyPurpose(com.sparrowwallet.drongo.KeyPurpose) ElectrumServer(com.sparrowwallet.sparrow.net.ElectrumServer) TransactionOutput(com.sparrowwallet.drongo.protocol.TransactionOutput) TransactionDiagram(com.sparrowwallet.sparrow.control.TransactionDiagram) Sha256Hash(com.sparrowwallet.drongo.protocol.Sha256Hash) PSBTParseException(com.sparrowwallet.drongo.psbt.PSBTParseException) Pattern(java.util.regex.Pattern) TransactionInput(com.sparrowwallet.drongo.protocol.TransactionInput) TransactionOutput(com.sparrowwallet.drongo.protocol.TransactionOutput) Address(com.sparrowwallet.drongo.address.Address) TransactionInput(com.sparrowwallet.drongo.protocol.TransactionInput)

Example 8 with Transaction

use of com.sparrowwallet.drongo.protocol.Transaction in project sparrow by sparrowwallet.

the class CounterpartyController method startCounterpartyCollaboration.

private void startCounterpartyCollaboration(SparrowCahootsWallet counterpartyCahootsWallet, PaymentCode initiatorPaymentCode, CahootsType cahootsType) {
    sorobanProgressLabel.setText("Creating mix transaction...");
    Soroban soroban = AppServices.getSorobanServices().getSoroban(walletId);
    Map<BlockTransactionHashIndex, WalletNode> walletUtxos = wallet.getWalletUtxos();
    for (Map.Entry<BlockTransactionHashIndex, WalletNode> entry : walletUtxos.entrySet()) {
        if (entry.getKey().getStatus() != Status.FROZEN) {
            counterpartyCahootsWallet.addUtxo(entry.getValue(), wallet.getWalletTransaction(entry.getKey().getHash()), (int) entry.getKey().getIndex());
        }
    }
    try {
        SorobanCahootsService sorobanCahootsService = soroban.getSorobanCahootsService(counterpartyCahootsWallet);
        CahootsContext cahootsContext = cahootsType == CahootsType.STONEWALLX2 ? CahootsContext.newCounterpartyStonewallx2() : CahootsContext.newCounterpartyStowaway();
        sorobanCahootsService.contributor(counterpartyCahootsWallet.getAccount(), cahootsContext, initiatorPaymentCode, TIMEOUT_MS).subscribeOn(Schedulers.io()).observeOn(JavaFxScheduler.platform()).subscribe(sorobanMessage -> {
            OnlineCahootsMessage cahootsMessage = (OnlineCahootsMessage) sorobanMessage;
            if (cahootsMessage != null) {
                Cahoots cahoots = cahootsMessage.getCahoots();
                sorobanProgressBar.setProgress((double) (cahoots.getStep() + 1) / 5);
                if (cahoots.getStep() == 3) {
                    sorobanProgressLabel.setText("Your mix partner is reviewing the transaction...");
                    step3Timer.start();
                } else if (cahoots.getStep() >= 4) {
                    try {
                        Transaction transaction = getTransaction(cahoots);
                        if (transaction != null) {
                            transactionProperty.set(transaction);
                            updateTransactionDiagram(transactionDiagram, wallet, null, transaction);
                            next();
                        }
                    } catch (PSBTParseException e) {
                        log.error("Invalid collaborative PSBT created", e);
                        step3Desc.setText("Invalid transaction created.");
                        sorobanProgressLabel.setVisible(false);
                    }
                }
            }
        }, error -> {
            log.error("Error creating mix transaction", error);
            String cutFrom = "Exception: ";
            int index = error.getMessage().lastIndexOf(cutFrom);
            String msg = index < 0 ? error.getMessage() : error.getMessage().substring(index + cutFrom.length());
            msg = msg.replace("#Cahoots", "mix transaction");
            step3Desc.setText(msg);
            sorobanProgressLabel.setVisible(false);
        });
    } catch (Exception e) {
        log.error("Error creating mix transaction", e);
        sorobanProgressLabel.setText(e.getMessage());
    }
}
Also used : BlockTransactionHashIndex(com.sparrowwallet.drongo.wallet.BlockTransactionHashIndex) PSBTParseException(com.sparrowwallet.drongo.psbt.PSBTParseException) CahootsContext(com.samourai.soroban.cahoots.CahootsContext) Transaction(com.sparrowwallet.drongo.protocol.Transaction) OnlineCahootsMessage(com.samourai.soroban.client.cahoots.OnlineCahootsMessage) SorobanCahootsService(com.samourai.soroban.client.cahoots.SorobanCahootsService) PSBTParseException(com.sparrowwallet.drongo.psbt.PSBTParseException) Cahoots(com.samourai.wallet.cahoots.Cahoots) HashMap(java.util.HashMap) Map(java.util.Map) WalletNode(com.sparrowwallet.drongo.wallet.WalletNode)

Example 9 with Transaction

use of com.sparrowwallet.drongo.protocol.Transaction in project sparrow by sparrowwallet.

the class SendController method broadcastNotification.

public void broadcastNotification(Wallet decryptedWallet) {
    try {
        PaymentCode paymentCode = decryptedWallet.getPaymentCode();
        PaymentCode externalPaymentCode = paymentCodeProperty.get();
        WalletTransaction walletTransaction = walletTransactionProperty.get();
        WalletNode input0Node = walletTransaction.getSelectedUtxos().entrySet().iterator().next().getValue();
        Keystore keystore = input0Node.getWallet().isNested() ? decryptedWallet.getChildWallet(input0Node.getWallet().getName()).getKeystores().get(0) : decryptedWallet.getKeystores().get(0);
        ECKey input0Key = keystore.getKey(input0Node);
        TransactionOutPoint input0Outpoint = walletTransaction.getTransaction().getInputs().iterator().next().getOutpoint();
        SecretPoint secretPoint = new SecretPoint(input0Key.getPrivKeyBytes(), externalPaymentCode.getNotificationKey().getPubKey());
        byte[] blindingMask = PaymentCode.getMask(secretPoint.ECDHSecretAsBytes(), input0Outpoint.bitcoinSerialize());
        byte[] blindedPaymentCode = PaymentCode.blind(paymentCode.getPayload(), blindingMask);
        List<UtxoSelector> utxoSelectors = List.of(new PresetUtxoSelector(walletTransaction.getSelectedUtxos().keySet(), true));
        Long userFee = userFeeSet.get() ? getFeeValueSats() : null;
        double feeRate = getUserFeeRate();
        Integer currentBlockHeight = AppServices.getCurrentBlockHeight();
        boolean groupByAddress = Config.get().isGroupByAddress();
        boolean includeMempoolOutputs = Config.get().isIncludeMempoolOutputs();
        boolean includeSpentMempoolOutputs = includeSpentMempoolOutputsProperty.get();
        WalletTransaction finalWalletTx = decryptedWallet.createWalletTransaction(utxoSelectors, getUtxoFilters(), walletTransaction.getPayments(), List.of(blindedPaymentCode), excludedChangeNodes, feeRate, getMinimumFeeRate(), userFee, currentBlockHeight, groupByAddress, includeMempoolOutputs, includeSpentMempoolOutputs);
        PSBT psbt = finalWalletTx.createPSBT();
        decryptedWallet.sign(psbt);
        decryptedWallet.finalise(psbt);
        Transaction transaction = psbt.extractTransaction();
        ServiceProgressDialog.ProxyWorker proxyWorker = new ServiceProgressDialog.ProxyWorker();
        ElectrumServer.BroadcastTransactionService broadcastTransactionService = new ElectrumServer.BroadcastTransactionService(transaction);
        broadcastTransactionService.setOnSucceeded(successEvent -> {
            ElectrumServer.TransactionMempoolService transactionMempoolService = new ElectrumServer.TransactionMempoolService(walletTransaction.getWallet(), transaction.getTxId(), new HashSet<>(walletTransaction.getSelectedUtxos().values()));
            transactionMempoolService.setDelay(Duration.seconds(2));
            transactionMempoolService.setPeriod(Duration.seconds(5));
            transactionMempoolService.setRestartOnFailure(false);
            transactionMempoolService.setOnSucceeded(mempoolWorkerStateEvent -> {
                Set<String> scriptHashes = transactionMempoolService.getValue();
                if (!scriptHashes.isEmpty()) {
                    transactionMempoolService.cancel();
                    clear(null);
                    if (Config.get().isUsePayNym()) {
                        proxyWorker.setMessage("Finding PayNym...");
                        AppServices.getPayNymService().getPayNym(externalPaymentCode.toString()).subscribe(payNym -> {
                            proxyWorker.end();
                            addChildWallets(walletTransaction.getWallet(), externalPaymentCode, transaction, payNym);
                        }, error -> {
                            proxyWorker.end();
                            addChildWallets(walletTransaction.getWallet(), externalPaymentCode, transaction, null);
                        });
                    } else {
                        proxyWorker.end();
                        addChildWallets(walletTransaction.getWallet(), externalPaymentCode, transaction, null);
                    }
                }
                if (transactionMempoolService.getIterationCount() > 5 && transactionMempoolService.isRunning()) {
                    transactionMempoolService.cancel();
                    proxyWorker.end();
                    log.error("Timeout searching for broadcasted notification transaction");
                    AppServices.showErrorDialog("Timeout searching for broadcasted transaction", "The transaction was broadcast but the server did not register it in the mempool. It is safe to try broadcasting again.");
                }
            });
            transactionMempoolService.setOnFailed(mempoolWorkerStateEvent -> {
                transactionMempoolService.cancel();
                proxyWorker.end();
                log.error("Error searching for broadcasted notification transaction", mempoolWorkerStateEvent.getSource().getException());
                AppServices.showErrorDialog("Timeout searching for broadcasted transaction", "The transaction was broadcast but the server did not register it in the mempool. It is safe to try broadcasting again.");
            });
            proxyWorker.setMessage("Receiving notification transaction...");
            transactionMempoolService.start();
        });
        broadcastTransactionService.setOnFailed(failedEvent -> {
            proxyWorker.end();
            log.error("Error broadcasting notification transaction", failedEvent.getSource().getException());
            AppServices.showErrorDialog("Error broadcasting notification transaction", failedEvent.getSource().getException().getMessage());
        });
        ServiceProgressDialog progressDialog = new ServiceProgressDialog("Broadcast", "Broadcast Notification Transaction", "/image/paynym.png", proxyWorker);
        AppServices.moveToActiveWindowScreen(progressDialog);
        proxyWorker.setMessage("Broadcasting notification transaction...");
        proxyWorker.start();
        broadcastTransactionService.start();
    } catch (Exception e) {
        log.error("Error creating notification transaction", e);
        AppServices.showErrorDialog("Error creating notification transaction", e.getMessage());
    }
}
Also used : ECKey(com.sparrowwallet.drongo.crypto.ECKey) SecureString(com.sparrowwallet.drongo.SecureString) SecretPoint(com.sparrowwallet.drongo.bip47.SecretPoint) PaymentCode(com.sparrowwallet.drongo.bip47.PaymentCode) InvalidAddressException(com.sparrowwallet.drongo.address.InvalidAddressException) IOException(java.io.IOException) PSBT(com.sparrowwallet.drongo.psbt.PSBT) Transaction(com.sparrowwallet.drongo.protocol.Transaction) TransactionOutPoint(com.sparrowwallet.drongo.protocol.TransactionOutPoint)

Example 10 with Transaction

use of com.sparrowwallet.drongo.protocol.Transaction in project sparrow by sparrowwallet.

the class SparrowDataSource method pushTx.

@Override
public void pushTx(String txHex) throws Exception {
    Transaction transaction = new Transaction(Utils.hexToBytes(txHex));
    ElectrumServer electrumServer = new ElectrumServer();
    electrumServer.broadcastTransactionPrivately(transaction);
}
Also used : ElectrumServer(com.sparrowwallet.sparrow.net.ElectrumServer) Transaction(com.sparrowwallet.drongo.protocol.Transaction)

Aggregations

Transaction (com.sparrowwallet.drongo.protocol.Transaction)11 TransactionOutput (com.sparrowwallet.drongo.protocol.TransactionOutput)4 TransactionInput (com.sparrowwallet.drongo.protocol.TransactionInput)3 Subscribe (com.google.common.eventbus.Subscribe)2 Cahoots (com.samourai.wallet.cahoots.Cahoots)2 KeyPurpose (com.sparrowwallet.drongo.KeyPurpose)2 Address (com.sparrowwallet.drongo.address.Address)2 InvalidAddressException (com.sparrowwallet.drongo.address.InvalidAddressException)2 PaymentCode (com.sparrowwallet.drongo.bip47.PaymentCode)2 ECKey (com.sparrowwallet.drongo.crypto.ECKey)2 Sha256Hash (com.sparrowwallet.drongo.protocol.Sha256Hash)2 PSBT (com.sparrowwallet.drongo.psbt.PSBT)2 PSBTParseException (com.sparrowwallet.drongo.psbt.PSBTParseException)2 com.sparrowwallet.drongo.wallet (com.sparrowwallet.drongo.wallet)2 ElectrumServer (com.sparrowwallet.sparrow.net.ElectrumServer)2 java.util (java.util)2 Collectors (java.util.stream.Collectors)2 JsonRpcClient (com.github.arteam.simplejsonrpc.client.JsonRpcClient)1 JsonRpcException (com.github.arteam.simplejsonrpc.client.exception.JsonRpcException)1 ImmutableMap (com.google.common.collect.ImmutableMap)1