Java Code Examples for org.bitcoinj.core.Coin#add()

The following examples show how to use org.bitcoinj.core.Coin#add() . 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: RestrictionsTest.java    From bisq-core with GNU Affero General Public License v3.0 6 votes vote down vote up
@Test
public void testIsMinSpendableAmount() {
    Coin amount = null;
    Coin txFee = Coin.valueOf(20000);

    amount = Coin.ZERO;
    assertFalse(Restrictions.isAboveDust(amount.subtract(txFee)));

    amount = txFee;
    assertFalse(Restrictions.isAboveDust(amount.subtract(txFee)));

    amount = Restrictions.getMinNonDustOutput();
    assertFalse(Restrictions.isAboveDust(amount.subtract(txFee)));

    amount = txFee.add(Restrictions.getMinNonDustOutput());
    assertTrue(Restrictions.isAboveDust(amount.subtract(txFee)));

    amount = txFee.add(Restrictions.getMinNonDustOutput()).add(Coin.valueOf(1));
    assertTrue(Restrictions.isAboveDust(amount.subtract(txFee)));
}
 
Example 2
Source File: DisputeSummaryWindow.java    From bisq with GNU Affero General Public License v3.0 6 votes vote down vote up
private boolean isPayoutAmountValid() {
    Coin buyerAmount = ParsingUtils.parseToCoin(buyerPayoutAmountInputTextField.getText(), formatter);
    Coin sellerAmount = ParsingUtils.parseToCoin(sellerPayoutAmountInputTextField.getText(), formatter);
    Contract contract = dispute.getContract();
    Coin tradeAmount = contract.getTradeAmount();
    Offer offer = new Offer(contract.getOfferPayload());
    Coin available = tradeAmount
            .add(offer.getBuyerSecurityDeposit())
            .add(offer.getSellerSecurityDeposit());
    Coin totalAmount = buyerAmount.add(sellerAmount);

    if (!totalAmount.isPositive()) {
        return false;
    }

    if (getDisputeManager(dispute) instanceof RefundManager) {
        // We allow to spend less in case of RefundAgent
        return totalAmount.compareTo(available) <= 0;
    } else {
        return totalAmount.compareTo(available) == 0;
    }
}
 
Example 3
Source File: TakeOfferDataModel.java    From bisq with GNU Affero General Public License v3.0 6 votes vote down vote up
void calculateTotalToPay() {
    // Taker pays 2 times the tx fee because the mining fee might be different when maker created the offer
    // and reserved his funds, so that would not work well with dynamic fees.
    // The mining fee for the takeOfferFee tx is deducted from the createOfferFee and not visible to the trader
    final Coin takerFee = getTakerFee();
    if (offer != null && amount.get() != null && takerFee != null) {
        Coin feeAndSecDeposit = getTotalTxFee().add(securityDeposit);
        if (isCurrencyForTakerFeeBtc()) {
            feeAndSecDeposit = feeAndSecDeposit.add(takerFee);
        }
        if (isBuyOffer())
            totalToPayAsCoin.set(feeAndSecDeposit.add(amount.get()));
        else
            totalToPayAsCoin.set(feeAndSecDeposit);

        updateBalance();
        log.debug("totalToPayAsCoin {}", totalToPayAsCoin.get().toFriendlyString());
    }
}
 
Example 4
Source File: WalletService.java    From bisq-core with GNU Affero General Public License v3.0 5 votes vote down vote up
protected Coin getBalance(List<TransactionOutput> transactionOutputs, Address address) {
    Coin balance = Coin.ZERO;
    for (TransactionOutput output : transactionOutputs) {
        if (isOutputScriptConvertibleToAddress(output) &&
                address != null &&
                address.equals(getAddressFromOutput(output)))
            balance = balance.add(output.getValue());
    }
    return balance;
}
 
Example 5
Source File: BsqWalletService.java    From bisq-core with GNU Affero General Public License v3.0 5 votes vote down vote up
@Override
public Coin getValueSentToMeForTransaction(Transaction transaction) throws ScriptException {
    Coin result = Coin.ZERO;
    final String txId = transaction.getHashAsString();
    // We check if we have a matching BSQ tx. We do that call here to avoid repeated calls in the loop.
    Optional<Tx> txOptional = bsqStateService.getTx(txId);
    // We check all the outputs of our tx
    for (int i = 0; i < transaction.getOutputs().size(); i++) {
        TransactionOutput output = transaction.getOutputs().get(i);
        final boolean isConfirmed = output.getParentTransaction() != null &&
                output.getParentTransaction().getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING;
        if (output.isMineOrWatched(wallet)) {
            if (isConfirmed) {
                if (txOptional.isPresent()) {
                    // The index of the BSQ tx outputs are the same like the bitcoinj tx outputs
                    TxOutput txOutput = txOptional.get().getTxOutputs().get(i);
                    if (bsqStateService.isBsqTxOutputType(txOutput)) {
                        //TODO check why values are not the same
                        if (txOutput.getValue() != output.getValue().value) {
                            log.warn("getValueSentToMeForTransaction: Value of BSQ output do not match BitcoinJ tx output. " +
                                            "txOutput.getValue()={}, output.getValue().value={}, txId={}",
                                    txOutput.getValue(), output.getValue().value, txId);
                        }

                        // If it is a valid BSQ output we add it
                        result = result.add(Coin.valueOf(txOutput.getValue()));
                    }
                }
            } /*else {
                // TODO atm we don't display amounts of unconfirmed txs but that might change so we leave that code
                // if it will be required
                // If the tx is not confirmed yet we add the value and assume it is a valid BSQ output.
                result = result.add(output.getValue());
            }*/
        }
    }
    return result;
}
 
Example 6
Source File: BsqWalletService.java    From bisq with GNU Affero General Public License v3.0 5 votes vote down vote up
private void addInputsAndChangeOutputForTx(Transaction tx,
                                           Coin fee,
                                           BsqCoinSelector bsqCoinSelector)
        throws InsufficientBsqException {
    Coin requiredInput;
    // If our fee is less then dust limit we increase it so we are sure to not get any dust output.
    if (Restrictions.isDust(fee)) {
        requiredInput = fee.add(Restrictions.getMinNonDustOutput());
    } else {
        requiredInput = fee;
    }

    CoinSelection coinSelection = bsqCoinSelector.select(requiredInput, wallet.calculateAllSpendCandidates());
    coinSelection.gathered.forEach(tx::addInput);
    try {
        Coin change = bsqCoinSelector.getChange(fee, coinSelection);
        if (change.isPositive()) {
            checkArgument(Restrictions.isAboveDust(change),
                    "The change output of " + change.value / 100d + " BSQ is below the min. dust value of "
                            + Restrictions.getMinNonDustOutput().value / 100d +
                            ". At least " + Restrictions.getMinNonDustOutput().add(fee).value / 100d +
                            " BSQ is needed for this transaction");
            tx.addOutput(change, getChangeAddress());
        }
    } catch (InsufficientMoneyException e) {
        log.error(tx.toString());
        throw new InsufficientBsqException(e.missing);
    }
}
 
Example 7
Source File: WalletService.java    From bisq with GNU Affero General Public License v3.0 5 votes vote down vote up
protected Coin getBalance(List<TransactionOutput> transactionOutputs, Address address) {
    Coin balance = Coin.ZERO;
    for (TransactionOutput output : transactionOutputs) {
        if (!isDustAttackUtxo(output)) {
            if (isOutputScriptConvertibleToAddress(output) &&
                    address != null &&
                    address.equals(getAddressFromOutput(output)))
                balance = balance.add(output.getValue());
        }
    }
    return balance;
}
 
Example 8
Source File: TransactionDetailsDialog.java    From cate with MIT License 5 votes vote down vote up
private void setTransaction(final WalletTransaction transaction) {
    wtx = transaction;
    valStatus.setText(MessageFormat.format(resources.getString("txDetails.conf"), wtx.getTransaction().getConfidence().getDepthInBlocks()));

    final DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
    valTime.setText(dateFormat.format(wtx.getTransaction().getUpdateTime()));

    final Coin amount;

    if (wtx.getBalanceChange().isPositive()) {
        // We don't know about the fee for receiving transactions, so remove the next two lines
        hideFeeAndGross();
        amount = wtx.getBalanceChange();
    } else {
        // Here we know the fee, so show it
        final Coin fee = wtx.getTransaction().getFee();
        valFee.setText(wtx.getNetwork().format(fee).toString());

        final Coin gross = wtx.getBalanceChange();
        valGross.setText(wtx.getNetwork().format(gross).toString());

        amount = gross.add(fee); // gross is negative so add the fee back to get the actual amount.
    }

    valTo.setText(TransactionFormatter.getRelevantOutputsAsString(wtx, ", "));
    valMemo.setText(wtx.getMemo());
    wtx.memoProperty().bind(valMemo.textProperty());
    valAmount.setText(wtx.getNetwork().format(amount).toString());

    valID.setText(wtx.getTransaction().getHashAsString());

    // Try to adapt the button sizes to match font
    int buttonSize = (int) Math.round(Font.getDefault().getSize()) + 6;
    btnCopyId.setMaxSize(buttonSize, buttonSize);
    btnCopyTo.setMaxSize(buttonSize, buttonSize);
}
 
Example 9
Source File: CreateOfferService.java    From bisq with GNU Affero General Public License v3.0 5 votes vote down vote up
public Coin getReservedFundsForOffer(OfferPayload.Direction direction,
                                     Coin amount,
                                     double buyerSecurityDeposit,
                                     double sellerSecurityDeposit) {

    Coin reservedFundsForOffer = getSecurityDeposit(direction,
            amount,
            buyerSecurityDeposit,
            sellerSecurityDeposit);
    if (!isBuyOffer(direction))
        reservedFundsForOffer = reservedFundsForOffer.add(amount);

    return reservedFundsForOffer;
}
 
Example 10
Source File: WithdrawalView.java    From bisq with GNU Affero General Public License v3.0 5 votes vote down vote up
private Coin getDust(Transaction transaction) {
    Coin dust = Coin.ZERO;
    for (TransactionOutput transactionOutput: transaction.getOutputs()) {
        if (transactionOutput.getValue().isLessThan(Restrictions.getMinNonDustOutput())) {
            dust = dust.add(transactionOutput.getValue());
            log.info("dust TXO = {}", transactionOutput.toString());
        }
    }
    return dust;
}
 
Example 11
Source File: TakeOfferDataModel.java    From bisq with GNU Affero General Public License v3.0 5 votes vote down vote up
void onTakeOffer(TradeResultHandler tradeResultHandler) {
    checkNotNull(txFeeFromFeeService, "txFeeFromFeeService must not be null");
    checkNotNull(getTakerFee(), "takerFee must not be null");

    Coin fundsNeededForTrade = getFundsNeededForTrade();
    if (isBuyOffer())
        fundsNeededForTrade = fundsNeededForTrade.add(amount.get());

    if (filterManager.isCurrencyBanned(offer.getCurrencyCode())) {
        new Popup().warning(Res.get("offerbook.warning.currencyBanned")).show();
    } else if (filterManager.isPaymentMethodBanned(offer.getPaymentMethod())) {
        new Popup().warning(Res.get("offerbook.warning.paymentMethodBanned")).show();
    } else if (filterManager.isOfferIdBanned(offer.getId())) {
        new Popup().warning(Res.get("offerbook.warning.offerBlocked")).show();
    } else if (filterManager.isNodeAddressBanned(offer.getMakerNodeAddress())) {
        new Popup().warning(Res.get("offerbook.warning.nodeBlocked")).show();
    } else if (filterManager.requireUpdateToNewVersionForTrading()) {
        new Popup().warning(Res.get("offerbook.warning.requireUpdateToNewVersion")).show();
    } else {
        tradeManager.onTakeOffer(amount.get(),
                txFeeFromFeeService,
                getTakerFee(),
                isCurrencyForTakerFeeBtc(),
                tradePrice.getValue(),
                fundsNeededForTrade,
                offer,
                paymentAccount.getId(),
                useSavingsWallet,
                tradeResultHandler,
                errorMessage -> {
                    log.warn(errorMessage);
                    new Popup().warning(errorMessage).show();
                }
        );
    }
}
 
Example 12
Source File: TakeOfferDataModel.java    From bisq with GNU Affero General Public License v3.0 5 votes vote down vote up
public void estimateTxSize() {
    int txSize = 0;
    if (btcWalletService.getBalance(Wallet.BalanceType.AVAILABLE).isPositive()) {
        Coin fundsNeededForTrade = getFundsNeededForTrade();
        if (isBuyOffer())
            fundsNeededForTrade = fundsNeededForTrade.add(amount.get());

        // As taker we pay 3 times the fee and currently the fee is the same for all 3 txs (trade fee tx, deposit
        // tx and payout tx).
        // We should try to change that in future to have the deposit and payout tx with a fixed fee as the size is
        // there more deterministic.
        // The trade fee tx can be in the worst case very large if there are many inputs so if we take that tx alone
        // for the fee estimation we would overpay a lot.
        // On the other side if we have the best case of a 1 input tx fee tx then it is only 260 bytes but the
        // other 2 txs are larger (320 and 380 bytes) and would get a lower fee/byte as intended.
        // We apply following model to not overpay too much but be on the safe side as well.
        // We sum the taker fee tx and the deposit tx together as it can be assumed that both be in the same block and
        // as they are dependent txs the miner will pick both if the fee in total is good enough.
        // We make sure that the fee is sufficient to meet our intended fee/byte for the larger payout tx with 380 bytes.
        Tuple2<Coin, Integer> estimatedFeeAndTxSize = txFeeEstimationService.getEstimatedFeeAndTxSizeForTaker(fundsNeededForTrade,
                getTakerFee());
        txFeeFromFeeService = estimatedFeeAndTxSize.first;
        feeTxSize = estimatedFeeAndTxSize.second;
    } else {
        feeTxSize = 380;
        txFeeFromFeeService = txFeePerByteFromFeeService.multiply(feeTxSize);
        log.info("We cannot do the fee estimation because there are no funds in the wallet.\nThis is expected " +
                        "if the user has not funded their wallet yet.\n" +
                        "In that case we use an estimated tx size of 380 bytes.\n" +
                        "txFee based on estimated size of {} bytes. feeTxSize = {} bytes. Actual tx size = {} bytes. TxFee is {} ({} sat/byte)",
                feeTxSize, feeTxSize, txSize, txFeeFromFeeService.toFriendlyString(), feeService.getTxFeePerByte());
    }
}
 
Example 13
Source File: MutableOfferDataModel.java    From bisq with GNU Affero General Public License v3.0 5 votes vote down vote up
void calculateTotalToPay() {
    // Maker does not pay the mining fee for the trade txs because the mining fee might be different when maker
    // created the offer and reserved his funds, so that would not work well with dynamic fees.
    // The mining fee for the createOfferFee tx is deducted from the createOfferFee and not visible to the trader
    final Coin makerFee = getMakerFee();
    if (direction != null && amount.get() != null && makerFee != null) {
        Coin feeAndSecDeposit = getTxFee().add(getSecurityDeposit());
        if (isCurrencyForMakerFeeBtc())
            feeAndSecDeposit = feeAndSecDeposit.add(makerFee);
        Coin total = isBuyOffer() ? feeAndSecDeposit : feeAndSecDeposit.add(amount.get());
        totalToPayAsCoin.set(total);
        updateBalance();
    }
}
 
Example 14
Source File: BsqWalletService.java    From bisq with GNU Affero General Public License v3.0 4 votes vote down vote up
private Transaction getPreparedTxWithMandatoryBsqChangeOutput(Coin fee) throws InsufficientBsqException {
    daoKillSwitch.assertDaoIsNotDisabled();

    Transaction tx = new Transaction(params);
    // We look for inputs covering out BSQ fee we want to pay.
    CoinSelection coinSelection = bsqCoinSelector.select(fee, wallet.calculateAllSpendCandidates());
    try {
        Coin change = bsqCoinSelector.getChange(fee, coinSelection);
        if (change.isZero() || Restrictions.isDust(change)) {
            // If change is zero or below dust we increase required input amount to enforce a BSQ change output.
            // All outputs after that are considered BTC and therefore would be burned BSQ if BSQ is left from what
            // we use for miner fee.

            Coin minDustThreshold = Coin.valueOf(preferences.getIgnoreDustThreshold());
            Coin increasedRequiredInput = fee.add(minDustThreshold);
            coinSelection = bsqCoinSelector.select(increasedRequiredInput, wallet.calculateAllSpendCandidates());
            change = bsqCoinSelector.getChange(fee, coinSelection);

            log.warn("We increased required input as change output was zero or dust: New change value={}", change);
            String info = "Available BSQ balance=" + coinSelection.valueGathered.value / 100 + " BSQ. " +
                    "Intended fee to burn=" + fee.value / 100 + " BSQ. " +
                    "Please increase your balance to at least " + (coinSelection.valueGathered.value + minDustThreshold.value) / 100 + " BSQ.";
            checkArgument(coinSelection.valueGathered.compareTo(fee) > 0,
                    "This transaction require a change output of at least " + minDustThreshold.value / 100 + " BSQ (dust limit). " +
                            info);

            checkArgument(!Restrictions.isDust(change),
                    "This transaction would create a dust output of " + change.value / 100 + " BSQ. " +
                            "It requires a change output of at least " + minDustThreshold.value / 100 + " BSQ (dust limit). " +
                            info);
        }

        coinSelection.gathered.forEach(tx::addInput);
        tx.addOutput(change, getChangeAddress());

        return tx;

    } catch (InsufficientMoneyException e) {
        log.error("coinSelection.gathered={}", coinSelection.gathered);
        throw new InsufficientBsqException(e.missing);
    }
}
 
Example 15
Source File: BsqWalletService.java    From bisq with GNU Affero General Public License v3.0 4 votes vote down vote up
@Override
public Coin getValueSentFromMeForTransaction(Transaction transaction) throws ScriptException {
    Coin result = Coin.ZERO;
    // We check all our inputs and get the connected outputs.
    for (int i = 0; i < transaction.getInputs().size(); i++) {
        TransactionInput input = transaction.getInputs().get(i);
        // We grab the connected output for that input
        TransactionOutput connectedOutput = input.getConnectedOutput();
        if (connectedOutput != null) {
            // We grab the parent tx of the connected output
            final Transaction parentTransaction = connectedOutput.getParentTransaction();
            final boolean isConfirmed = parentTransaction != null &&
                    parentTransaction.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING;
            if (connectedOutput.isMineOrWatched(wallet)) {
                if (isConfirmed) {
                    // We lookup if we have a BSQ tx matching the parent tx
                    // We cannot make that findTx call outside of the loop as the parent tx can change at each iteration
                    Optional<Tx> txOptional = daoStateService.getTx(parentTransaction.getHash().toString());
                    if (txOptional.isPresent()) {
                        TxOutput txOutput = txOptional.get().getTxOutputs().get(connectedOutput.getIndex());
                        if (daoStateService.isBsqTxOutputType(txOutput)) {
                            //TODO check why values are not the same
                            if (txOutput.getValue() != connectedOutput.getValue().value)
                                log.warn("getValueSentToMeForTransaction: Value of BSQ output do not match BitcoinJ tx output. " +
                                                "txOutput.getValue()={}, output.getValue().value={}, txId={}",
                                        txOutput.getValue(), connectedOutput.getValue().value, txOptional.get().getId());

                            // If it is a valid BSQ output we add it
                            result = result.add(Coin.valueOf(txOutput.getValue()));
                        }
                    }
                } /*else {
                    // TODO atm we don't display amounts of unconfirmed txs but that might change so we leave that code
                    // if it will be required
                    // If the tx is not confirmed yet we add the value and assume it is a valid BSQ output.
                    result = result.add(connectedOutput.getValue());
                }*/
            }
        }
    }
    return result;
}
 
Example 16
Source File: DisputeSummaryWindow.java    From bisq with GNU Affero General Public License v3.0 4 votes vote down vote up
private void showPayoutTxConfirmation(Contract contract, DisputeResult disputeResult, ResultHandler resultHandler) {
    Coin buyerPayoutAmount = disputeResult.getBuyerPayoutAmount();
    String buyerPayoutAddressString = contract.getBuyerPayoutAddressString();
    Coin sellerPayoutAmount = disputeResult.getSellerPayoutAmount();
    String sellerPayoutAddressString = contract.getSellerPayoutAddressString();
    Coin outputAmount = buyerPayoutAmount.add(sellerPayoutAmount);
    Tuple2<Coin, Integer> feeTuple = txFeeEstimationService.getEstimatedFeeAndTxSize(outputAmount, feeService, btcWalletService);
    Coin fee = feeTuple.first;
    Integer txSize = feeTuple.second;
    double feePerByte = CoinUtil.getFeePerByte(fee, txSize);
    double kb = txSize / 1000d;
    Coin inputAmount = outputAmount.add(fee);
    String buyerDetails = "";
    if (buyerPayoutAmount.isPositive()) {
        buyerDetails = Res.get("disputeSummaryWindow.close.txDetails.buyer",
                formatter.formatCoinWithCode(buyerPayoutAmount),
                buyerPayoutAddressString);
    }
    String sellerDetails = "";
    if (sellerPayoutAmount.isPositive()) {
        sellerDetails = Res.get("disputeSummaryWindow.close.txDetails.seller",
                formatter.formatCoinWithCode(sellerPayoutAmount),
                sellerPayoutAddressString);
    }
    new Popup().width(900)
            .headLine(Res.get("disputeSummaryWindow.close.txDetails.headline"))
            .confirmation(Res.get("disputeSummaryWindow.close.txDetails",
                    formatter.formatCoinWithCode(inputAmount),
                    buyerDetails,
                    sellerDetails,
                    formatter.formatCoinWithCode(fee),
                    feePerByte,
                    kb))
            .actionButtonText(Res.get("shared.yes"))
            .onAction(() -> {
                doPayout(buyerPayoutAmount,
                        sellerPayoutAmount,
                        fee,
                        buyerPayoutAddressString,
                        sellerPayoutAddressString,
                        resultHandler);
            })
            .closeButtonText(Res.get("shared.cancel"))
            .onClose(() -> {
            })
            .show();
}
 
Example 17
Source File: TransactionActivity.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
private static Pair<Integer, JSONMap>
createRawTransaction(final GaService service,
                     final Transaction tx, final List<JSONMap> usedUtxos,
                     final List<JSONMap> utxos, final int subAccount,
                     GATx.ChangeOutput changeOutput,
                     final Coin amount, final Coin oldFee,
                     final Coin feeRate,
                     final JSONMap privateData, final boolean sendAll) {

    final boolean isRBF = usedUtxos != null;
    final boolean haveExistingChange = changeOutput != null;
    Coin total =  isRBF ? getUtxoSum(usedUtxos) : Coin.ZERO;
    Coin fee;

    // First add inputs until we cover the amount to send
    while ((sendAll || total.isLessThan(amount)) && !utxos.isEmpty())
        total = total.add(GATx.addUtxo(service, tx, utxos, usedUtxos));

    // Then add inputs until we cover amount + fee/change
    while (true) {
        fee = GATx.getTxFee(service, tx, feeRate);
        if (isRBF) {
            final Coin bandwidthFee = GATx.getTxFee(service, tx, service.getMinFeeRate());
            fee = (fee.isLessThan(oldFee) ? oldFee : fee).add(bandwidthFee);
        }

        final Coin minChange = changeOutput == null ? Coin.ZERO : service.getDustThreshold();
        final int cmp = sendAll ? 0 : total.compareTo(amount.add(fee).add(minChange));
        if (cmp < 0) {
            // Need more inputs to cover amount + fee/change
            if (utxos.isEmpty())
                return createFailed(R.string.insufficientFundsText); // None left, fail

            total = total.add(GATx.addUtxo(service, tx, utxos, usedUtxos));
            continue;
        }

        if (cmp == 0 || changeOutput != null) {
            // Inputs exactly match amount + fee/change, or are greater
            // and we have a change output for the excess
            break;
        }

        // Inputs greater than amount + fee, add a change output and try again
        changeOutput = GATx.addChangeOutput(service, tx, subAccount);
        if (changeOutput == null)
            return createFailed(R.string.unable_to_create_change);
    }

    boolean randomizedChange = false;
    if (changeOutput != null) {
        // Set the value of the change output
        if (tx.getOutputs().size() == 1)
            changeOutput.mOutput.setValue(total.subtract(fee)); // Redeposit
        else
            changeOutput.mOutput.setValue(total.subtract(amount).subtract(fee));
        if (haveExistingChange)
            randomizedChange = changeOutput.mOutput == tx.getOutput(0);
        else
            randomizedChange = GATx.randomizeChangeOutput(tx);
    }

    if (sendAll) {
        final Coin actualAmount = total.subtract(fee);
        if (!actualAmount.isGreaterThan(Coin.ZERO))
            return createFailed(R.string.insufficientFundsText);
        final int amtIndex = tx.getOutputs().size() == 1 ? 0 : (randomizedChange ? 1 : 0);
        tx.getOutput(amtIndex).setValue(actualAmount);
    }

    tx.setLockTime(service.getCurrentBlock()); // Prevent fee sniping

    int changeIndex = -1;
    if (changeOutput != null && tx.getOutputs().size() != 1)
        changeIndex = randomizedChange ? 0 : 1;
    return new Pair<>(0,
                      GATx.makeLimitsData(fee.subtract(oldFee), fee, changeIndex));
}
 
Example 18
Source File: TransactionActivity.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
private static Coin getUtxoSum(final List<JSONMap> utxos) {
    Coin value = Coin.ZERO;
    for (final JSONMap utxo : utxos)
        value = value.add(Coin.valueOf(utxo.getLong("value")));
    return value;
}
 
Example 19
Source File: Verifier.java    From GreenBits with GNU General Public License v3.0 4 votes vote down vote up
static Coin verify(final GaService service,
                   final Map<TransactionOutPoint, Coin> countedUtxoValues, final PreparedTransaction ptx,
                   final Address recipient, final Coin amount, final List<Boolean> input) {
    final int changeIdx;
    if (input == null)
        changeIdx = -1;
    else if (input.get(0))
        changeIdx = 0;
    else if (input.get(1))
        changeIdx = 1;
    else
        throw new IllegalArgumentException("Verification: Change output missing.");

    if (input != null && input.get(0) && input.get(1)) {
        // Shouldn't happen really. In theory user can send money to a new change address
        // of themselves which they've generated manually, but it's unlikely, so for
        // simplicity we don't handle it.
        throw new IllegalArgumentException("Verification: Cannot send to a change address.");
    }
    final TransactionOutput output = ptx.mDecoded.getOutputs().get(1 - Math.abs(changeIdx));
    if (recipient != null) {
        final Address gotAddress = output.getScriptPubKey().getToAddress(service.getNetworkParameters());
        if (!gotAddress.equals(recipient))
            throw new IllegalArgumentException("Verification: Invalid recipient address.");
    }
    if (amount != null && !output.getValue().equals(amount))
        throw new IllegalArgumentException("Verification: Invalid output amount.");

    // 3. Verify fee value
    Coin fee = Coin.ZERO;
    for (final TransactionInput in : ptx.mDecoded.getInputs()) {
        if (countedUtxoValues.get(in.getOutpoint()) != null) {
            fee = fee.add(countedUtxoValues.get(in.getOutpoint()));
            continue;
        }

        final Transaction prevTx = ptx.mPrevoutRawTxs.get(in.getOutpoint().getHash().toString());
        if (!prevTx.getHash().equals(in.getOutpoint().getHash()))
            throw new IllegalArgumentException("Verification: Prev tx hash invalid");
        fee = fee.add(prevTx.getOutput((int) in.getOutpoint().getIndex()).getValue());
    }
    for (final TransactionOutput out : ptx.mDecoded.getOutputs())
        fee = fee.subtract(out.getValue());

    final double messageSize = ptx.mDecoded.getMessageSize();
    final double satoshiPerByte = fee.value / messageSize;
    final double satoshiPerKiloByte = satoshiPerByte * 1000.0;
    final Coin feeRate = Coin.valueOf((int) satoshiPerKiloByte);

    final Coin minFeeRate = service.getMinFeeRate();
    if (feeRate.isLessThan(minFeeRate) && service.getNetworkParameters() != RegTestParams.get())
        feeError("small", feeRate, minFeeRate);

    final Coin maxFeeRate = Coin.valueOf(15000 * 1000); // FIXME: Get max fee rate from server
    if (feeRate.isGreaterThan(maxFeeRate))
        feeError("large", feeRate, maxFeeRate);

    return amount == null ? output.getValue() : fee;
}
 
Example 20
Source File: BsqWalletService.java    From bisq-core with GNU Affero General Public License v3.0 4 votes vote down vote up
@Override
public Coin getValueSentFromMeForTransaction(Transaction transaction) throws ScriptException {
    Coin result = Coin.ZERO;
    // We check all our inputs and get the connected outputs.
    for (int i = 0; i < transaction.getInputs().size(); i++) {
        TransactionInput input = transaction.getInputs().get(i);
        // We grab the connected output for that input
        TransactionOutput connectedOutput = input.getConnectedOutput();
        if (connectedOutput != null) {
            // We grab the parent tx of the connected output
            final Transaction parentTransaction = connectedOutput.getParentTransaction();
            final boolean isConfirmed = parentTransaction != null &&
                    parentTransaction.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING;
            if (connectedOutput.isMineOrWatched(wallet)) {
                if (isConfirmed) {
                    // We lookup if we have a BSQ tx matching the parent tx
                    // We cannot make that findTx call outside of the loop as the parent tx can change at each iteration
                    Optional<Tx> txOptional = bsqStateService.getTx(parentTransaction.getHash().toString());
                    if (txOptional.isPresent()) {
                        TxOutput txOutput = txOptional.get().getTxOutputs().get(connectedOutput.getIndex());
                        if (bsqStateService.isBsqTxOutputType(txOutput)) {
                            //TODO check why values are not the same
                            if (txOutput.getValue() != connectedOutput.getValue().value)
                                log.warn("getValueSentToMeForTransaction: Value of BSQ output do not match BitcoinJ tx output. " +
                                                "txOutput.getValue()={}, output.getValue().value={}, txId={}",
                                        txOutput.getValue(), connectedOutput.getValue().value, txOptional.get().getId());

                            // If it is a valid BSQ output we add it
                            result = result.add(Coin.valueOf(txOutput.getValue()));
                        }
                    }
                } /*else {
                    // TODO atm we don't display amounts of unconfirmed txs but that might change so we leave that code
                    // if it will be required
                    // If the tx is not confirmed yet we add the value and assume it is a valid BSQ output.
                    result = result.add(connectedOutput.getValue());
                }*/
            }
        }
    }
    return result;
}