use of org.bitcoinj.core.Transaction in project bisq-core by bisq-network.
the class BsqWalletService method getPreparedSendBtcTx.
// /////////////////////////////////////////////////////////////////////////////////////////
// Send BTC (non-BSQ) with BTC fee (e.g. the issuance output from a lost comp. request)
// /////////////////////////////////////////////////////////////////////////////////////////
public Transaction getPreparedSendBtcTx(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();
sendRequest.coinSelector = nonBsqCoinSelector;
try {
wallet.completeTx(sendRequest);
} catch (InsufficientMoneyException e) {
throw new InsufficientBsqException(e.missing);
}
checkWalletConsistency(wallet);
verifyTransaction(tx);
// printTx("prepareSendTx", tx);
return tx;
}
use of org.bitcoinj.core.Transaction in project bisq-core by bisq-network.
the class BtcWalletService method getSendRequest.
private SendRequest getSendRequest(String fromAddress, String toAddress, Coin amount, Coin fee, @Nullable KeyParameter aesKey, AddressEntry.Context context) throws AddressFormatException, AddressEntryException {
Transaction tx = new Transaction(params);
final Coin receiverAmount = amount.subtract(fee);
Preconditions.checkArgument(Restrictions.isAboveDust(receiverAmount), "The amount is too low (dust limit).");
tx.addOutput(receiverAmount, Address.fromBase58(params, toAddress));
SendRequest sendRequest = SendRequest.forTx(tx);
sendRequest.fee = fee;
sendRequest.feePerKb = Coin.ZERO;
sendRequest.ensureMinRequiredFee = false;
sendRequest.aesKey = aesKey;
sendRequest.shuffleOutputs = false;
Optional<AddressEntry> addressEntry = findAddressEntry(fromAddress, context);
if (!addressEntry.isPresent())
throw new AddressEntryException("WithdrawFromAddress is not found in our wallet.");
checkNotNull(addressEntry.get(), "addressEntry.get() must not be null");
checkNotNull(addressEntry.get().getAddress(), "addressEntry.get().getAddress() must not be null");
sendRequest.coinSelector = new BtcCoinSelector(addressEntry.get().getAddress());
sendRequest.changeAddress = addressEntry.get().getAddress();
return sendRequest;
}
use of org.bitcoinj.core.Transaction in project bisq-core by bisq-network.
the class BtcWalletService method getSendRequestForMultipleAddresses.
private SendRequest getSendRequestForMultipleAddresses(Set<String> fromAddresses, String toAddress, Coin amount, Coin fee, @Nullable String changeAddress, @Nullable KeyParameter aesKey) throws AddressFormatException, AddressEntryException, InsufficientMoneyException {
Transaction tx = new Transaction(params);
checkArgument(Restrictions.isAboveDust(amount), "The amount is too low (dust limit).");
final Coin netValue = amount.subtract(fee);
if (netValue.isNegative())
throw new InsufficientMoneyException(netValue.multiply(-1), "The mining fee for that transaction exceed the available amount.");
tx.addOutput(netValue, Address.fromBase58(params, toAddress));
SendRequest sendRequest = SendRequest.forTx(tx);
sendRequest.fee = fee;
sendRequest.feePerKb = Coin.ZERO;
sendRequest.ensureMinRequiredFee = false;
sendRequest.aesKey = aesKey;
sendRequest.shuffleOutputs = false;
Set<AddressEntry> addressEntries = fromAddresses.stream().map(address -> {
Optional<AddressEntry> addressEntryOptional = findAddressEntry(address, AddressEntry.Context.AVAILABLE);
if (!addressEntryOptional.isPresent())
addressEntryOptional = findAddressEntry(address, AddressEntry.Context.OFFER_FUNDING);
if (!addressEntryOptional.isPresent())
addressEntryOptional = findAddressEntry(address, AddressEntry.Context.TRADE_PAYOUT);
if (!addressEntryOptional.isPresent())
addressEntryOptional = findAddressEntry(address, AddressEntry.Context.ARBITRATOR);
return addressEntryOptional;
}).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toSet());
if (addressEntries.isEmpty())
throw new AddressEntryException("No Addresses for withdraw found in our wallet");
sendRequest.coinSelector = new BtcCoinSelector(walletsSetup.getAddressesFromAddressEntries(addressEntries));
Optional<AddressEntry> addressEntryOptional = Optional.<AddressEntry>empty();
AddressEntry changeAddressAddressEntry = null;
if (changeAddress != null)
addressEntryOptional = findAddressEntry(changeAddress, AddressEntry.Context.AVAILABLE);
changeAddressAddressEntry = addressEntryOptional.orElseGet(() -> getFreshAddressEntry());
checkNotNull(changeAddressAddressEntry, "change address must not be null");
sendRequest.changeAddress = changeAddressAddressEntry.getAddress();
return sendRequest;
}
use of org.bitcoinj.core.Transaction in project bisq-core by bisq-network.
the class BtcWalletService method addInputsForMinerFee.
private Transaction addInputsForMinerFee(Transaction preparedTx, byte[] opReturnData) throws InsufficientMoneyException {
// 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.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;
}
use of org.bitcoinj.core.Transaction in project bisq-core by bisq-network.
the class MakerSetupDepositTxListener method run.
@Override
protected void run() {
try {
runInterceptHook();
if (trade.getDepositTx() == null && processModel.getPreparedDepositTx() != null) {
BtcWalletService walletService = processModel.getBtcWalletService();
final NetworkParameters params = walletService.getParams();
Transaction preparedDepositTx = new Transaction(params, processModel.getPreparedDepositTx());
checkArgument(!preparedDepositTx.getOutputs().isEmpty(), "preparedDepositTx.getOutputs() must not be empty");
Address depositTxAddress = preparedDepositTx.getOutput(0).getAddressFromP2SH(params);
final TransactionConfidence confidence = walletService.getConfidenceForAddress(depositTxAddress);
if (isInNetwork(confidence)) {
applyConfidence(confidence);
} else {
confidenceListener = new AddressConfidenceListener(depositTxAddress) {
@Override
public void onTransactionConfidenceChanged(TransactionConfidence confidence) {
if (isInNetwork(confidence))
applyConfidence(confidence);
}
};
walletService.addAddressConfidenceListener(confidenceListener);
tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), newValue -> {
if (trade.isDepositPublished()) {
swapReservedForTradeEntry();
// hack to remove tradeStateSubscription at callback
UserThread.execute(this::unSubscribe);
}
});
}
}
// we complete immediately, our object stays alive because the balanceListener is stored in the WalletService
complete();
} catch (Throwable t) {
failed(t);
}
}
Aggregations