Java Code Examples for org.bitcoinj.wallet.SendRequest#forTx()
The following examples show how to use
org.bitcoinj.wallet.SendRequest#forTx() .
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: TransactionOutputTest.java From green_android with GNU General Public License v3.0 | 6 votes |
@Test public void testMultiSigOutputToString() throws Exception { sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, Coin.COIN); ECKey myKey = new ECKey(); this.wallet.importKey(myKey); // Simulate another signatory ECKey otherKey = new ECKey(); // Create multi-sig transaction Transaction multiSigTransaction = new Transaction(PARAMS); ImmutableList<ECKey> keys = ImmutableList.of(myKey, otherKey); Script scriptPubKey = ScriptBuilder.createMultiSigOutputScript(2, keys); multiSigTransaction.addOutput(Coin.COIN, scriptPubKey); SendRequest req = SendRequest.forTx(multiSigTransaction); this.wallet.completeTx(req); TransactionOutput multiSigTransactionOutput = multiSigTransaction.getOutput(0); assertThat(multiSigTransactionOutput.toString(), CoreMatchers.containsString("CHECKMULTISIG")); }
Example 2
Source File: TransactionOutputTest.java From bcm-android with GNU General Public License v3.0 | 6 votes |
@Test public void testMultiSigOutputToString() throws Exception { sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, Coin.COIN); ECKey myKey = new ECKey(); this.wallet.importKey(myKey); // Simulate another signatory ECKey otherKey = new ECKey(); // Create multi-sig transaction Transaction multiSigTransaction = new Transaction(UNITTEST); ImmutableList<ECKey> keys = ImmutableList.of(myKey, otherKey); Script scriptPubKey = ScriptBuilder.createMultiSigOutputScript(2, keys); multiSigTransaction.addOutput(Coin.COIN, scriptPubKey); SendRequest req = SendRequest.forTx(multiSigTransaction); this.wallet.completeTx(req); TransactionOutput multiSigTransactionOutput = multiSigTransaction.getOutput(0); assertThat(multiSigTransactionOutput.toString(), CoreMatchers.containsString("CHECKMULTISIG")); }
Example 3
Source File: BsqWalletService.java From bisq-core with GNU Affero General Public License v3.0 | 6 votes |
public Transaction getPreparedSendTx(String receiverAddress, Coin receiverAmount) throws AddressFormatException, InsufficientBsqException, WalletException, TransactionVerificationException { Transaction tx = new Transaction(params); checkArgument(Restrictions.isAboveDust(receiverAmount), "The amount is too low (dust limit)."); tx.addOutput(receiverAmount, Address.fromBase58(params, receiverAddress)); SendRequest sendRequest = SendRequest.forTx(tx); sendRequest.fee = Coin.ZERO; sendRequest.feePerKb = Coin.ZERO; sendRequest.ensureMinRequiredFee = false; sendRequest.aesKey = aesKey; sendRequest.shuffleOutputs = false; sendRequest.signInputs = false; sendRequest.ensureMinRequiredFee = false; sendRequest.changeAddress = getUnusedAddress(); try { wallet.completeTx(sendRequest); } catch (InsufficientMoneyException e) { throw new InsufficientBsqException(e.missing); } checkWalletConsistency(wallet); verifyTransaction(tx); // printTx("prepareSendTx", tx); return tx; }
Example 4
Source File: TransactionOutputTest.java From GreenBits with GNU General Public License v3.0 | 6 votes |
@Test public void testMultiSigOutputToString() throws Exception { sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, Coin.COIN); ECKey myKey = new ECKey(); this.wallet.importKey(myKey); // Simulate another signatory ECKey otherKey = new ECKey(); // Create multi-sig transaction Transaction multiSigTransaction = new Transaction(PARAMS); ImmutableList<ECKey> keys = ImmutableList.of(myKey, otherKey); Script scriptPubKey = ScriptBuilder.createMultiSigOutputScript(2, keys); multiSigTransaction.addOutput(Coin.COIN, scriptPubKey); SendRequest req = SendRequest.forTx(multiSigTransaction); this.wallet.completeTx(req); TransactionOutput multiSigTransactionOutput = multiSigTransaction.getOutput(0); assertThat(multiSigTransactionOutput.toString(), CoreMatchers.containsString("CHECKMULTISIG")); }
Example 5
Source File: BtcWalletService.java From bisq with GNU Affero General Public License v3.0 | 6 votes |
public int getEstimatedFeeTxSize(List<Coin> outputValues, Coin txFee) throws InsufficientMoneyException, AddressFormatException { Transaction transaction = new Transaction(params); Address dummyAddress = wallet.currentReceiveKey().toAddress(params); outputValues.forEach(outputValue -> transaction.addOutput(outputValue, dummyAddress)); SendRequest sendRequest = SendRequest.forTx(transaction); sendRequest.shuffleOutputs = false; sendRequest.aesKey = aesKey; sendRequest.coinSelector = new BtcCoinSelector(walletsSetup.getAddressesByContext(AddressEntry.Context.AVAILABLE), preferences.getIgnoreDustThreshold()); sendRequest.fee = txFee; sendRequest.feePerKb = Coin.ZERO; sendRequest.ensureMinRequiredFee = false; sendRequest.changeAddress = dummyAddress; wallet.completeTx(sendRequest); return transaction.bitcoinSerialize().length; }
Example 6
Source File: BsqWalletService.java From bisq with GNU Affero General Public License v3.0 | 5 votes |
private Transaction getPreparedSendTx(String receiverAddress, Coin receiverAmount, CoinSelector coinSelector) throws AddressFormatException, InsufficientBsqException, WalletException, TransactionVerificationException, BsqChangeBelowDustException { daoKillSwitch.assertDaoIsNotDisabled(); Transaction tx = new Transaction(params); checkArgument(Restrictions.isAboveDust(receiverAmount), "The amount is too low (dust limit)."); tx.addOutput(receiverAmount, Address.fromBase58(params, receiverAddress)); SendRequest sendRequest = SendRequest.forTx(tx); sendRequest.fee = Coin.ZERO; sendRequest.feePerKb = Coin.ZERO; sendRequest.ensureMinRequiredFee = false; sendRequest.aesKey = aesKey; sendRequest.shuffleOutputs = false; sendRequest.signInputs = false; sendRequest.changeAddress = getChangeAddress(); sendRequest.coinSelector = coinSelector; try { wallet.completeTx(sendRequest); checkWalletConsistency(wallet); verifyTransaction(tx); // printTx("prepareSendTx", tx); // Tx has as first output BSQ and an optional second BSQ change output. // At that stage we do not have added the BTC inputs so there is no BTC change output here. if (tx.getOutputs().size() == 2) { Coin bsqChangeOutputValue = tx.getOutputs().get(1).getValue(); if (!Restrictions.isAboveDust(bsqChangeOutputValue)) { String msg = "BSQ change output is below dust limit. outputValue=" + bsqChangeOutputValue.value / 100 + " BSQ"; log.warn(msg); throw new BsqChangeBelowDustException(msg, bsqChangeOutputValue); } } return tx; } catch (InsufficientMoneyException e) { log.error(e.toString()); throw new InsufficientBsqException(e.missing); } }
Example 7
Source File: TradeWalletService.java From bisq with GNU Affero General Public License v3.0 | 5 votes |
private void addAvailableInputsAndChangeOutputs(Transaction transaction, Address address, Address changeAddress) throws WalletException { SendRequest sendRequest = null; try { // Let the framework do the work to find the right inputs sendRequest = SendRequest.forTx(transaction); sendRequest.shuffleOutputs = false; sendRequest.aesKey = aesKey; // We use a fixed fee sendRequest.fee = Coin.ZERO; sendRequest.feePerKb = Coin.ZERO; sendRequest.ensureMinRequiredFee = false; // we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to wait for 1 confirmation) sendRequest.coinSelector = new BtcCoinSelector(address, preferences.getIgnoreDustThreshold()); // We use always the same address in a trade for all transactions sendRequest.changeAddress = changeAddress; // With the usage of completeTx() we get all the work done with fee calculation, validation and coin selection. // We don't commit that tx to the wallet as it will be changed later and it's not signed yet. // So it will not change the wallet balance. checkNotNull(wallet, "wallet must not be null"); wallet.completeTx(sendRequest); } catch (Throwable t) { if (sendRequest != null && sendRequest.tx != null) { log.warn("addAvailableInputsAndChangeOutputs: sendRequest.tx={}, sendRequest.tx.getOutputs()={}", sendRequest.tx, sendRequest.tx.getOutputs()); } throw new WalletException(t); } }
Example 8
Source File: PaymentChannelServerState.java From green_android with GNU General Public License v3.0 | 5 votes |
protected synchronized SendRequest makeUnsignedChannelContract(Coin valueToMe) { Transaction tx = new Transaction(wallet.getParams()); if (!getTotalValue().subtract(valueToMe).equals(Coin.ZERO)) { tx.addOutput(getTotalValue().subtract(valueToMe), getClientKey().toAddress(wallet.getParams())); } tx.addInput(contract.getOutput(0)); return SendRequest.forTx(tx); }
Example 9
Source File: TradeWalletService.java From bisq-core with GNU Affero General Public License v3.0 | 5 votes |
private void addAvailableInputsAndChangeOutputs(Transaction transaction, Address address, Address changeAddress, Coin txFee) throws WalletException { SendRequest sendRequest = null; try { // Lets let the framework do the work to find the right inputs sendRequest = SendRequest.forTx(transaction); sendRequest.shuffleOutputs = false; sendRequest.aesKey = aesKey; // We use a fixed fee sendRequest.fee = txFee; sendRequest.feePerKb = Coin.ZERO; sendRequest.ensureMinRequiredFee = false; // we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to wait for 1 confirmation) sendRequest.coinSelector = new BtcCoinSelector(address); // We use always the same address in a trade for all transactions sendRequest.changeAddress = changeAddress; // With the usage of completeTx() we get all the work done with fee calculation, validation and coin selection. // We don't commit that tx to the wallet as it will be changed later and it's not signed yet. // So it will not change the wallet balance. checkNotNull(wallet, "wallet must not be null"); wallet.completeTx(sendRequest); } catch (Throwable t) { if (sendRequest != null && sendRequest.tx != null) log.warn("addAvailableInputsAndChangeOutputs: sendRequest.tx={}, sendRequest.tx.getOutputs()={}", sendRequest.tx, sendRequest.tx.getOutputs()); throw new WalletException(t); } }
Example 10
Source File: TradeWalletService.java From bisq-core with GNU Affero General Public License v3.0 | 5 votes |
public Transaction estimateBtcTradingFeeTxSize(Address fundingAddress, Address reservedForTradeAddress, Address changeAddress, Coin reservedFundsForOffer, boolean useSavingsWallet, Coin tradingFee, Coin txFee, String feeReceiverAddresses) throws InsufficientMoneyException, AddressFormatException { Transaction tradingFeeTx = new Transaction(params); tradingFeeTx.addOutput(tradingFee, Address.fromBase58(params, feeReceiverAddresses)); tradingFeeTx.addOutput(reservedFundsForOffer, reservedForTradeAddress); SendRequest sendRequest = SendRequest.forTx(tradingFeeTx); sendRequest.shuffleOutputs = false; sendRequest.aesKey = aesKey; if (useSavingsWallet) sendRequest.coinSelector = new BtcCoinSelector(walletsSetup.getAddressesByContext(AddressEntry.Context.AVAILABLE)); else sendRequest.coinSelector = new BtcCoinSelector(fundingAddress); sendRequest.fee = txFee; sendRequest.feePerKb = Coin.ZERO; sendRequest.ensureMinRequiredFee = false; sendRequest.changeAddress = changeAddress; checkNotNull(wallet, "Wallet must not be null"); log.info("estimateBtcTradingFeeTxSize"); wallet.completeTx(sendRequest); return tradingFeeTx; }
Example 11
Source File: PaymentChannelServerState.java From bcm-android with GNU General Public License v3.0 | 5 votes |
protected synchronized SendRequest makeUnsignedChannelContract(Coin valueToMe) { Transaction tx = new Transaction(wallet.getParams()); if (!getTotalValue().subtract(valueToMe).equals(Coin.ZERO)) { tx.addOutput(getTotalValue().subtract(valueToMe), LegacyAddress.fromKey(wallet.getParams(), getClientKey())); } tx.addInput(contract.getOutput(0)); return SendRequest.forTx(tx); }
Example 12
Source File: BtcWalletService.java From bisq with GNU Affero General Public License v3.0 | 4 votes |
private Transaction completePreparedProposalTx(Transaction feeTx, byte[] opReturnData, @Nullable Coin issuanceAmount, @Nullable Address issuanceAddress) throws TransactionVerificationException, WalletException, InsufficientMoneyException { // (BsqFee)tx has following structure: // inputs [1-n] BSQ inputs (fee) // outputs [0-1] BSQ request fee change output (>= 546 Satoshi) // preparedCompensationRequestTx has following structure: // inputs [1-n] BSQ inputs for request fee // inputs [1-n] BTC inputs for BSQ issuance and miner fee // outputs [1] Mandatory BSQ request fee change output (>= 546 Satoshi) // outputs [1] Potentially BSQ issuance output (>= 546 Satoshi) - in case of a issuance tx, otherwise that output does not exist // outputs [0-1] BTC change output from issuance and miner fee inputs (>= 546 Satoshi) // outputs [1] OP_RETURN with opReturnData and amount 0 // mining fee: BTC mining fee + burned BSQ fee Transaction preparedTx = new Transaction(params); // Copy inputs from BSQ fee tx feeTx.getInputs().forEach(preparedTx::addInput); int indexOfBtcFirstInput = feeTx.getInputs().size(); // Need to be first because issuance is not guaranteed to be valid and would otherwise burn change output! // BSQ change outputs from BSQ fee inputs. feeTx.getOutputs().forEach(preparedTx::addOutput); // For generic proposals there is no issuance output, for compensation and reimburse requests there is if (issuanceAmount != null && issuanceAddress != null) { // BSQ issuance output preparedTx.addOutput(issuanceAmount, issuanceAddress); } // safety check counter to avoid endless loops int counter = 0; // estimated size of input sig int sigSizePerInput = 106; // typical size for a tx with 3 inputs int txSizeWithUnsignedInputs = 300; Coin txFeePerByte = feeService.getTxFeePerByte(); Address changeAddress = getFreshAddressEntry().getAddress(); checkNotNull(changeAddress, "changeAddress must not be null"); BtcCoinSelector coinSelector = new BtcCoinSelector(walletsSetup.getAddressesByContext(AddressEntry.Context.AVAILABLE), preferences.getIgnoreDustThreshold()); List<TransactionInput> preparedBsqTxInputs = preparedTx.getInputs(); List<TransactionOutput> preparedBsqTxOutputs = preparedTx.getOutputs(); int numInputs = preparedBsqTxInputs.size(); Transaction resultTx = null; boolean isFeeOutsideTolerance; do { counter++; if (counter >= 10) { checkNotNull(resultTx, "resultTx must not be null"); log.error("Could not calculate the fee. Tx=" + resultTx); break; } Transaction tx = new Transaction(params); preparedBsqTxInputs.forEach(tx::addInput); preparedBsqTxOutputs.forEach(tx::addOutput); SendRequest sendRequest = SendRequest.forTx(tx); sendRequest.shuffleOutputs = false; sendRequest.aesKey = aesKey; // signInputs needs to be false as it would try to sign all inputs (BSQ inputs are not in this wallet) sendRequest.signInputs = false; sendRequest.fee = txFeePerByte.multiply(txSizeWithUnsignedInputs + sigSizePerInput * numInputs); sendRequest.feePerKb = Coin.ZERO; sendRequest.ensureMinRequiredFee = false; sendRequest.coinSelector = coinSelector; sendRequest.changeAddress = changeAddress; wallet.completeTx(sendRequest); resultTx = sendRequest.tx; // add OP_RETURN output resultTx.addOutput(new TransactionOutput(params, resultTx, Coin.ZERO, ScriptBuilder.createOpReturnScript(opReturnData).getProgram())); numInputs = resultTx.getInputs().size(); txSizeWithUnsignedInputs = resultTx.bitcoinSerialize().length; long estimatedFeeAsLong = txFeePerByte.multiply(txSizeWithUnsignedInputs + sigSizePerInput * numInputs).value; // calculated fee must be inside of a tolerance range with tx fee isFeeOutsideTolerance = Math.abs(resultTx.getFee().value - estimatedFeeAsLong) > 1000; } while (isFeeOutsideTolerance); // Sign all BTC inputs signAllBtcInputs(indexOfBtcFirstInput, resultTx); checkWalletConsistency(wallet); verifyTransaction(resultTx); // printTx("BTC wallet: Signed tx", resultTx); return resultTx; }
Example 13
Source File: TradeWalletService.java From bisq-core with GNU Affero General Public License v3.0 | 4 votes |
public Transaction completeBsqTradingFeeTx(Transaction preparedBsqTx, Address fundingAddress, Address reservedForTradeAddress, Address changeAddress, Coin reservedFundsForOffer, boolean useSavingsWallet, Coin txFee) throws TransactionVerificationException, WalletException, InsufficientMoneyException, AddressFormatException { log.debug("preparedBsqTx " + preparedBsqTx.toString()); log.debug("fundingAddress " + fundingAddress.toString()); log.debug("changeAddress " + changeAddress.toString()); log.debug("reservedFundsForOffer " + reservedFundsForOffer.toPlainString()); log.debug("useSavingsWallet " + useSavingsWallet); log.debug("txFee " + txFee.toPlainString()); // preparedBsqTx has following structure: // inputs [1-n] BSQ inputs // outputs [0-1] BSQ change output // mining fee: burned BSQ fee // We add BTC mining fee. Result tx looks like: // inputs [1-n] BSQ inputs // inputs [1-n] BTC inputs // outputs [0-1] BSQ change output // outputs [1] BTC reservedForTrade output // outputs [0-1] BTC change output // mining fee: BTC mining fee + burned BSQ fee // In case of txs for burned BSQ fees we have no receiver output and it might be that there is no change outputs // We need to guarantee that min. 1 valid output is added (OP_RETURN does not count). So we use a higher input // for BTC to force an additional change output. final int preparedBsqTxInputsSize = preparedBsqTx.getInputs().size(); // the reserved amount we need for the trade we send to our trade reservedForTradeAddress preparedBsqTx.addOutput(reservedFundsForOffer, reservedForTradeAddress); // we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to // wait for 1 confirmation) // In case of double spend we will detect later in the trade process and use a ban score to penalize bad behaviour (not impl. yet) // WalletService.printTx("preparedBsqTx", preparedBsqTx); SendRequest sendRequest = SendRequest.forTx(preparedBsqTx); sendRequest.shuffleOutputs = false; sendRequest.aesKey = aesKey; if (useSavingsWallet) sendRequest.coinSelector = new BtcCoinSelector(walletsSetup.getAddressesByContext(AddressEntry.Context.AVAILABLE)); else sendRequest.coinSelector = new BtcCoinSelector(fundingAddress); // We use a fixed fee sendRequest.fee = txFee; sendRequest.feePerKb = Coin.ZERO; sendRequest.ensureMinRequiredFee = false; sendRequest.signInputs = false; // Change is optional in case of overpay or use of funds from savings wallet sendRequest.changeAddress = changeAddress; checkNotNull(wallet, "Wallet must not be null"); wallet.completeTx(sendRequest); Transaction resultTx = sendRequest.tx; // Sign all BTC inputs for (int i = preparedBsqTxInputsSize; i < resultTx.getInputs().size(); i++) { TransactionInput txIn = resultTx.getInputs().get(i); checkArgument(txIn.getConnectedOutput() != null && txIn.getConnectedOutput().isMine(wallet), "txIn.getConnectedOutput() is not in our wallet. That must not happen."); WalletService.signTransactionInput(wallet, aesKey, resultTx, txIn, i); WalletService.checkScriptSig(resultTx, txIn, i); } WalletService.checkWalletConsistency(wallet); WalletService.verifyTransaction(resultTx); WalletService.printTx(Res.getBaseCurrencyCode() + " wallet: Signed tx", resultTx); return resultTx; }
Example 14
Source File: BtcWalletService.java From bisq with GNU Affero General Public License v3.0 | 4 votes |
public Transaction createRefundPayoutTx(Coin buyerAmount, Coin sellerAmount, Coin fee, String buyerAddressString, String sellerAddressString) throws AddressFormatException, InsufficientMoneyException, WalletException, TransactionVerificationException { Transaction tx = new Transaction(params); Preconditions.checkArgument(buyerAmount.add(sellerAmount).isPositive(), "The sellerAmount + buyerAmount must be positive."); // buyerAmount can be 0 if (buyerAmount.isPositive()) { Preconditions.checkArgument(Restrictions.isAboveDust(buyerAmount), "The buyerAmount is too low (dust limit)."); tx.addOutput(buyerAmount, Address.fromBase58(params, buyerAddressString)); } // sellerAmount can be 0 if (sellerAmount.isPositive()) { Preconditions.checkArgument(Restrictions.isAboveDust(sellerAmount), "The sellerAmount is too low (dust limit)."); tx.addOutput(sellerAmount, Address.fromBase58(params, sellerAddressString)); } SendRequest sendRequest = SendRequest.forTx(tx); sendRequest.fee = fee; sendRequest.feePerKb = Coin.ZERO; sendRequest.ensureMinRequiredFee = false; sendRequest.aesKey = aesKey; sendRequest.shuffleOutputs = false; sendRequest.coinSelector = new BtcCoinSelector(walletsSetup.getAddressesByContext(AddressEntry.Context.AVAILABLE), preferences.getIgnoreDustThreshold()); sendRequest.changeAddress = getFreshAddressEntry().getAddress(); checkNotNull(wallet); wallet.completeTx(sendRequest); Transaction resultTx = sendRequest.tx; checkWalletConsistency(wallet); verifyTransaction(resultTx); WalletService.printTx("createRefundPayoutTx", resultTx); return resultTx; }
Example 15
Source File: BtcWalletService.java From bisq-core with GNU Affero General Public License v3.0 | 4 votes |
public Transaction completePreparedCompensationRequestTx(Coin issuanceAmount, Address issuanceAddress, Transaction feeTx, byte[] opReturnData) throws TransactionVerificationException, WalletException, InsufficientMoneyException { // (BsqFee)tx has following structure: // inputs [1-n] BSQ inputs (fee) // outputs [0-1] BSQ request fee change output (>= 546 Satoshi) // preparedCompensationRequestTx has following structure: // inputs [1-n] BSQ inputs for request fee // inputs [1-n] BTC inputs for BSQ issuance and miner fee // outputs [1] Mandatory BSQ request fee change output (>= 546 Satoshi) // outputs [1] Potentially BSQ issuance output (>= 546 Satoshi) // outputs [0-1] BTC change output from issuance and miner fee inputs (>= 546 Satoshi) // outputs [1] OP_RETURN with opReturnData and amount 0 // mining fee: BTC mining fee + burned BSQ fee Transaction preparedTx = new Transaction(params); // Copy inputs from BSQ fee tx feeTx.getInputs().forEach(preparedTx::addInput); int indexOfBtcFirstInput = feeTx.getInputs().size(); // Need to be first because issuance is not guaranteed to be valid and would otherwise burn change output! // BSQ change outputs from BSQ fee inputs. feeTx.getOutputs().forEach(preparedTx::addOutput); // BSQ issuance output preparedTx.addOutput(issuanceAmount, issuanceAddress); // safety check counter to avoid endless loops int counter = 0; // estimated size of input sig final int sigSizePerInput = 106; // typical size for a tx with 3 inputs int txSizeWithUnsignedInputs = 300; final Coin txFeePerByte = feeService.getTxFeePerByte(); Address changeAddress = getFreshAddressEntry().getAddress(); checkNotNull(changeAddress, "changeAddress must not be null"); final BtcCoinSelector coinSelector = new BtcCoinSelector(walletsSetup.getAddressesByContext(AddressEntry.Context.AVAILABLE)); final List<TransactionInput> preparedBsqTxInputs = preparedTx.getInputs(); final List<TransactionOutput> preparedBsqTxOutputs = preparedTx.getOutputs(); int numInputs = preparedBsqTxInputs.size(); Transaction resultTx = null; boolean isFeeOutsideTolerance; do { counter++; if (counter >= 10) { checkNotNull(resultTx, "resultTx must not be null"); log.error("Could not calculate the fee. Tx=" + resultTx); break; } Transaction tx = new Transaction(params); preparedBsqTxInputs.stream().forEach(tx::addInput); preparedBsqTxOutputs.stream().forEach(tx::addOutput); SendRequest sendRequest = SendRequest.forTx(tx); sendRequest.shuffleOutputs = false; sendRequest.aesKey = aesKey; // signInputs needs to be false as it would try to sign all inputs (BSQ inputs are not in this wallet) sendRequest.signInputs = false; sendRequest.fee = txFeePerByte.multiply(txSizeWithUnsignedInputs + sigSizePerInput * numInputs); sendRequest.feePerKb = Coin.ZERO; sendRequest.ensureMinRequiredFee = false; sendRequest.coinSelector = coinSelector; sendRequest.changeAddress = changeAddress; wallet.completeTx(sendRequest); resultTx = sendRequest.tx; // add OP_RETURN output resultTx.addOutput(new TransactionOutput(params, resultTx, Coin.ZERO, ScriptBuilder.createOpReturnScript(opReturnData).getProgram())); numInputs = resultTx.getInputs().size(); txSizeWithUnsignedInputs = resultTx.bitcoinSerialize().length; final long estimatedFeeAsLong = txFeePerByte.multiply(txSizeWithUnsignedInputs + sigSizePerInput * numInputs).value; // calculated fee must be inside of a tolerance range with tx fee isFeeOutsideTolerance = Math.abs(resultTx.getFee().value - estimatedFeeAsLong) > 1000; } while (isFeeOutsideTolerance); // Sign all BTC inputs signAllBtcInputs(indexOfBtcFirstInput, resultTx); checkWalletConsistency(wallet); verifyTransaction(resultTx); // printTx("BTC wallet: Signed tx", resultTx); return resultTx; }
Example 16
Source File: BtcWalletService.java From bisq with GNU Affero General Public License v3.0 | 4 votes |
private Transaction addInputsForMinerFee(Transaction preparedTx, byte[] opReturnData) throws InsufficientMoneyException { // safety check counter to avoid endless loops int counter = 0; // estimated size of input sig int sigSizePerInput = 106; // typical size for a tx with 3 inputs int txSizeWithUnsignedInputs = 300; Coin txFeePerByte = feeService.getTxFeePerByte(); Address changeAddress = getFreshAddressEntry().getAddress(); checkNotNull(changeAddress, "changeAddress must not be null"); BtcCoinSelector coinSelector = new BtcCoinSelector(walletsSetup.getAddressesByContext(AddressEntry.Context.AVAILABLE), preferences.getIgnoreDustThreshold()); List<TransactionInput> preparedBsqTxInputs = preparedTx.getInputs(); List<TransactionOutput> preparedBsqTxOutputs = preparedTx.getOutputs(); int numInputs = preparedBsqTxInputs.size(); Transaction resultTx = null; boolean isFeeOutsideTolerance; do { counter++; if (counter >= 10) { checkNotNull(resultTx, "resultTx must not be null"); log.error("Could not calculate the fee. Tx=" + resultTx); break; } Transaction tx = new Transaction(params); preparedBsqTxInputs.forEach(tx::addInput); preparedBsqTxOutputs.forEach(tx::addOutput); SendRequest sendRequest = SendRequest.forTx(tx); sendRequest.shuffleOutputs = false; sendRequest.aesKey = aesKey; // signInputs needs to be false as it would try to sign all inputs (BSQ inputs are not in this wallet) sendRequest.signInputs = false; sendRequest.fee = txFeePerByte.multiply(txSizeWithUnsignedInputs + sigSizePerInput * numInputs); sendRequest.feePerKb = Coin.ZERO; sendRequest.ensureMinRequiredFee = false; sendRequest.coinSelector = coinSelector; sendRequest.changeAddress = changeAddress; wallet.completeTx(sendRequest); resultTx = sendRequest.tx; // add OP_RETURN output resultTx.addOutput(new TransactionOutput(params, resultTx, Coin.ZERO, ScriptBuilder.createOpReturnScript(opReturnData).getProgram())); numInputs = resultTx.getInputs().size(); txSizeWithUnsignedInputs = resultTx.bitcoinSerialize().length; final long estimatedFeeAsLong = txFeePerByte.multiply(txSizeWithUnsignedInputs + sigSizePerInput * numInputs).value; // calculated fee must be inside of a tolerance range with tx fee isFeeOutsideTolerance = Math.abs(resultTx.getFee().value - estimatedFeeAsLong) > 1000; } while (isFeeOutsideTolerance); return resultTx; }
Example 17
Source File: PaymentChannelV1ClientState.java From green_android with GNU General Public License v3.0 | 4 votes |
/** * Creates the initial multisig contract and incomplete refund transaction which can be requested at the appropriate * time using {@link PaymentChannelV1ClientState#getIncompleteRefundTransaction} and * {@link PaymentChannelV1ClientState#getContract()}. * By default unconfirmed coins are allowed to be used, as for micropayments the risk should be relatively low. * @param userKey Key derived from a user password, needed for any signing when the wallet is encrypted. * The wallet KeyCrypter is assumed. * @param clientChannelProperties Modify the channel's configuration. * * @throws ValueOutOfRangeException if the value being used is too small to be accepted by the network * @throws InsufficientMoneyException if the wallet doesn't contain enough balance to initiate */ @Override public synchronized void initiate(@Nullable KeyParameter userKey, ClientChannelProperties clientChannelProperties) throws ValueOutOfRangeException, InsufficientMoneyException { final NetworkParameters params = wallet.getParams(); Transaction template = new Transaction(params); // We always place the client key before the server key because, if either side wants some privacy, they can // use a fresh key for the the multisig contract and nowhere else List<ECKey> keys = Lists.newArrayList(myKey, serverKey); // There is also probably a change output, but we don't bother shuffling them as it's obvious from the // format which one is the change. If we start obfuscating the change output better in future this may // be worth revisiting. TransactionOutput multisigOutput = template.addOutput(totalValue, ScriptBuilder.createMultiSigOutputScript(2, keys)); if (multisigOutput.isDust()) throw new ValueOutOfRangeException("totalValue too small to use"); SendRequest req = SendRequest.forTx(template); req.coinSelector = AllowUnconfirmedCoinSelector.get(); req.shuffleOutputs = false; // TODO: Fix things so shuffling is usable. req = clientChannelProperties.modifyContractSendRequest(req); if (userKey != null) req.aesKey = userKey; wallet.completeTx(req); Coin multisigFee = req.tx.getFee(); multisigContract = req.tx; // Build a refund transaction that protects us in the case of a bad server that's just trying to cause havoc // by locking up peoples money (perhaps as a precursor to a ransom attempt). We time lock it so the server // has an assurance that we cannot take back our money by claiming a refund before the channel closes - this // relies on the fact that since Bitcoin 0.8 time locked transactions are non-final. This will need to change // in future as it breaks the intended design of timelocking/tx replacement, but for now it simplifies this // specific protocol somewhat. refundTx = new Transaction(params); // don't disable lock time. the sequence will be included in the server's signature and thus won't be changeable. // by using this sequence value, we avoid extra full replace-by-fee and relative lock time processing. refundTx.addInput(multisigOutput).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L); refundTx.setLockTime(expiryTime); if (Context.get().isEnsureMinRequiredFee()) { // Must pay min fee. final Coin valueAfterFee = totalValue.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE); if (Transaction.MIN_NONDUST_OUTPUT.compareTo(valueAfterFee) > 0) throw new ValueOutOfRangeException("totalValue too small to use"); refundTx.addOutput(valueAfterFee, myKey.toAddress(params)); refundFees = multisigFee.add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE); } else { refundTx.addOutput(totalValue, myKey.toAddress(params)); refundFees = multisigFee; } refundTx.getConfidence().setSource(TransactionConfidence.Source.SELF); log.info("initiated channel with multi-sig contract {}, refund {}", multisigContract.getHashAsString(), refundTx.getHashAsString()); stateMachine.transition(State.INITIATED); // Client should now call getIncompleteRefundTransaction() and send it to the server. }
Example 18
Source File: PaymentChannelV1ClientState.java From bcm-android with GNU General Public License v3.0 | 4 votes |
/** * Creates the initial multisig contract and incomplete refund transaction which can be requested at the appropriate * time using {@link PaymentChannelV1ClientState#getIncompleteRefundTransaction} and * {@link PaymentChannelV1ClientState#getContract()}. * By default unconfirmed coins are allowed to be used, as for micropayments the risk should be relatively low. * * @param userKey Key derived from a user password, needed for any signing when the wallet is encrypted. * The wallet KeyCrypter is assumed. * @param clientChannelProperties Modify the channel's configuration. * @throws ValueOutOfRangeException if the value being used is too small to be accepted by the network * @throws InsufficientMoneyException if the wallet doesn't contain enough balance to initiate */ @Override public synchronized void initiate(@Nullable KeyParameter userKey, ClientChannelProperties clientChannelProperties) throws ValueOutOfRangeException, InsufficientMoneyException { final NetworkParameters params = wallet.getParams(); Transaction template = new Transaction(params); // We always place the client key before the server key because, if either side wants some privacy, they can // use a fresh key for the the multisig contract and nowhere else List<ECKey> keys = Lists.newArrayList(myKey, serverKey); // There is also probably a change output, but we don't bother shuffling them as it's obvious from the // format which one is the change. If we start obfuscating the change output better in future this may // be worth revisiting. TransactionOutput multisigOutput = template.addOutput(totalValue, ScriptBuilder.createMultiSigOutputScript(2, keys)); if (multisigOutput.isDust()) throw new ValueOutOfRangeException("totalValue too small to use"); SendRequest req = SendRequest.forTx(template); req.coinSelector = AllowUnconfirmedCoinSelector.get(); req.shuffleOutputs = false; // TODO: Fix things so shuffling is usable. req = clientChannelProperties.modifyContractSendRequest(req); if (userKey != null) req.aesKey = userKey; wallet.completeTx(req); Coin multisigFee = req.tx.getFee(); multisigContract = req.tx; // Build a refund transaction that protects us in the case of a bad server that's just trying to cause havoc // by locking up peoples money (perhaps as a precursor to a ransom attempt). We time lock it so the server // has an assurance that we cannot take back our money by claiming a refund before the channel closes - this // relies on the fact that since Bitcoin 0.8 time locked transactions are non-final. This will need to change // in future as it breaks the intended design of timelocking/tx replacement, but for now it simplifies this // specific protocol somewhat. refundTx = new Transaction(params); // don't disable lock time. the sequence will be included in the server's signature and thus won't be changeable. // by using this sequence value, we avoid extra full replace-by-fee and relative lock time processing. refundTx.addInput(multisigOutput).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L); refundTx.setLockTime(expiryTime); if (Context.get().isEnsureMinRequiredFee()) { // Must pay min fee. final Coin valueAfterFee = totalValue.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE); if (Transaction.MIN_NONDUST_OUTPUT.compareTo(valueAfterFee) > 0) throw new ValueOutOfRangeException("totalValue too small to use"); refundTx.addOutput(valueAfterFee, LegacyAddress.fromKey(params, myKey)); refundFees = multisigFee.add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE); } else { refundTx.addOutput(totalValue, LegacyAddress.fromKey(params, myKey)); refundFees = multisigFee; } refundTx.getConfidence().setSource(TransactionConfidence.Source.SELF); log.info("initiated channel with multi-sig contract {}, refund {}", multisigContract.getHashAsString(), refundTx.getHashAsString()); stateMachine.transition(State.INITIATED); // Client should now call getIncompleteRefundTransaction() and send it to the server. }
Example 19
Source File: TradeWalletService.java From bisq with GNU Affero General Public License v3.0 | 4 votes |
public Transaction completeBsqTradingFeeTx(Transaction preparedBsqTx, Address fundingAddress, Address reservedForTradeAddress, Address changeAddress, Coin reservedFundsForOffer, boolean useSavingsWallet, Coin txFee) throws TransactionVerificationException, WalletException, InsufficientMoneyException, AddressFormatException { // preparedBsqTx has following structure: // inputs [1-n] BSQ inputs // outputs [0-1] BSQ change output // mining fee: burned BSQ fee // We add BTC mining fee. Result tx looks like: // inputs [1-n] BSQ inputs // inputs [1-n] BTC inputs // outputs [0-1] BSQ change output // outputs [1] BTC reservedForTrade output // outputs [0-1] BTC change output // mining fee: BTC mining fee + burned BSQ fee // In case of txs for burned BSQ fees we have no receiver output and it might be that there are no change outputs // We need to guarantee that min. 1 valid output is added (OP_RETURN does not count). So we use a higher input // for BTC to force an additional change output. final int preparedBsqTxInputsSize = preparedBsqTx.getInputs().size(); // the reserved amount we need for the trade we send to our trade reservedForTradeAddress preparedBsqTx.addOutput(reservedFundsForOffer, reservedForTradeAddress); // we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to // wait for 1 confirmation) // In case of double spend we will detect later in the trade process and use a ban score to penalize bad behaviour (not impl. yet) // If BSQ trade fee > reservedFundsForOffer we would create a BSQ output instead of a BTC output. // As the min. reservedFundsForOffer is 0.001 BTC which is 1000 BSQ this is an unrealistic scenario and not // handled atm (if BTC price is 1M USD and BSQ price is 0.1 USD, then fee would be 10% which still is unrealistic). // WalletService.printTx("preparedBsqTx", preparedBsqTx); SendRequest sendRequest = SendRequest.forTx(preparedBsqTx); sendRequest.shuffleOutputs = false; sendRequest.aesKey = aesKey; if (useSavingsWallet) { sendRequest.coinSelector = new BtcCoinSelector(walletsSetup.getAddressesByContext(AddressEntry.Context.AVAILABLE), preferences.getIgnoreDustThreshold()); } else { sendRequest.coinSelector = new BtcCoinSelector(fundingAddress, preferences.getIgnoreDustThreshold()); } // We use a fixed fee sendRequest.fee = txFee; sendRequest.feePerKb = Coin.ZERO; sendRequest.ensureMinRequiredFee = false; sendRequest.signInputs = false; // Change is optional in case of overpay or use of funds from savings wallet sendRequest.changeAddress = changeAddress; checkNotNull(wallet, "Wallet must not be null"); wallet.completeTx(sendRequest); Transaction resultTx = sendRequest.tx; removeDust(resultTx); // Sign all BTC inputs for (int i = preparedBsqTxInputsSize; i < resultTx.getInputs().size(); i++) { TransactionInput txIn = resultTx.getInputs().get(i); checkArgument(txIn.getConnectedOutput() != null && txIn.getConnectedOutput().isMine(wallet), "txIn.getConnectedOutput() is not in our wallet. That must not happen."); WalletService.signTransactionInput(wallet, aesKey, resultTx, txIn, i); WalletService.checkScriptSig(resultTx, txIn, i); } WalletService.checkWalletConsistency(wallet); WalletService.verifyTransaction(resultTx); WalletService.printTx(Res.getBaseCurrencyCode() + " wallet: Signed tx", resultTx); return resultTx; }
Example 20
Source File: PaymentChannelV1ClientState.java From GreenBits with GNU General Public License v3.0 | 4 votes |
/** * Creates the initial multisig contract and incomplete refund transaction which can be requested at the appropriate * time using {@link PaymentChannelV1ClientState#getIncompleteRefundTransaction} and * {@link PaymentChannelV1ClientState#getContract()}. * By default unconfirmed coins are allowed to be used, as for micropayments the risk should be relatively low. * @param userKey Key derived from a user password, needed for any signing when the wallet is encrypted. * The wallet KeyCrypter is assumed. * @param clientChannelProperties Modify the channel's configuration. * * @throws ValueOutOfRangeException if the value being used is too small to be accepted by the network * @throws InsufficientMoneyException if the wallet doesn't contain enough balance to initiate */ @Override public synchronized void initiate(@Nullable KeyParameter userKey, ClientChannelProperties clientChannelProperties) throws ValueOutOfRangeException, InsufficientMoneyException { final NetworkParameters params = wallet.getParams(); Transaction template = new Transaction(params); // We always place the client key before the server key because, if either side wants some privacy, they can // use a fresh key for the the multisig contract and nowhere else List<ECKey> keys = Lists.newArrayList(myKey, serverKey); // There is also probably a change output, but we don't bother shuffling them as it's obvious from the // format which one is the change. If we start obfuscating the change output better in future this may // be worth revisiting. TransactionOutput multisigOutput = template.addOutput(totalValue, ScriptBuilder.createMultiSigOutputScript(2, keys)); if (multisigOutput.isDust()) throw new ValueOutOfRangeException("totalValue too small to use"); SendRequest req = SendRequest.forTx(template); req.coinSelector = AllowUnconfirmedCoinSelector.get(); req.shuffleOutputs = false; // TODO: Fix things so shuffling is usable. req = clientChannelProperties.modifyContractSendRequest(req); if (userKey != null) req.aesKey = userKey; wallet.completeTx(req); Coin multisigFee = req.tx.getFee(); multisigContract = req.tx; // Build a refund transaction that protects us in the case of a bad server that's just trying to cause havoc // by locking up peoples money (perhaps as a precursor to a ransom attempt). We time lock it so the server // has an assurance that we cannot take back our money by claiming a refund before the channel closes - this // relies on the fact that since Bitcoin 0.8 time locked transactions are non-final. This will need to change // in future as it breaks the intended design of timelocking/tx replacement, but for now it simplifies this // specific protocol somewhat. refundTx = new Transaction(params); // don't disable lock time. the sequence will be included in the server's signature and thus won't be changeable. // by using this sequence value, we avoid extra full replace-by-fee and relative lock time processing. refundTx.addInput(multisigOutput).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1L); refundTx.setLockTime(expiryTime); if (Context.get().isEnsureMinRequiredFee()) { // Must pay min fee. final Coin valueAfterFee = totalValue.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE); if (Transaction.MIN_NONDUST_OUTPUT.compareTo(valueAfterFee) > 0) throw new ValueOutOfRangeException("totalValue too small to use"); refundTx.addOutput(valueAfterFee, myKey.toAddress(params)); refundFees = multisigFee.add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE); } else { refundTx.addOutput(totalValue, myKey.toAddress(params)); refundFees = multisigFee; } refundTx.getConfidence().setSource(TransactionConfidence.Source.SELF); log.info("initiated channel with multi-sig contract {}, refund {}", multisigContract.getHashAsString(), refundTx.getHashAsString()); stateMachine.transition(State.INITIATED); // Client should now call getIncompleteRefundTransaction() and send it to the server. }