Manfred Karrer 2019-05-14 15:05:12 +02:00
parent b8cf1d7e67
commit 25ee98dbce
No known key found for this signature in database
GPG key ID: 401250966A6B2C46
4 changed files with 69 additions and 8 deletions

View file

@ -0,0 +1,33 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.core.btc.exceptions;
import org.bitcoinj.core.Coin;
import lombok.Getter;
public class BsqChangeBelowDustException extends Exception {
@Getter
private final Coin outputValue;
public BsqChangeBelowDustException(String message, Coin outputValue) {
super(message);
this.outputValue = outputValue;
}
}

View file

@ -17,6 +17,7 @@
package bisq.core.btc.wallet; package bisq.core.btc.wallet;
import bisq.core.btc.exceptions.BsqChangeBelowDustException;
import bisq.core.btc.exceptions.InsufficientBsqException; import bisq.core.btc.exceptions.InsufficientBsqException;
import bisq.core.btc.exceptions.TransactionVerificationException; import bisq.core.btc.exceptions.TransactionVerificationException;
import bisq.core.btc.exceptions.WalletException; import bisq.core.btc.exceptions.WalletException;
@ -475,7 +476,7 @@ public class BsqWalletService extends WalletService implements DaoStateListener
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public Transaction getPreparedSendBsqTx(String receiverAddress, Coin receiverAmount) public Transaction getPreparedSendBsqTx(String receiverAddress, Coin receiverAmount)
throws AddressFormatException, InsufficientBsqException, WalletException, TransactionVerificationException { throws AddressFormatException, InsufficientBsqException, WalletException, TransactionVerificationException, BsqChangeBelowDustException {
return getPreparedSendTx(receiverAddress, receiverAmount, bsqCoinSelector); return getPreparedSendTx(receiverAddress, receiverAmount, bsqCoinSelector);
} }
@ -484,12 +485,12 @@ public class BsqWalletService extends WalletService implements DaoStateListener
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public Transaction getPreparedSendBtcTx(String receiverAddress, Coin receiverAmount) public Transaction getPreparedSendBtcTx(String receiverAddress, Coin receiverAmount)
throws AddressFormatException, InsufficientBsqException, WalletException, TransactionVerificationException { throws AddressFormatException, InsufficientBsqException, WalletException, TransactionVerificationException, BsqChangeBelowDustException {
return getPreparedSendTx(receiverAddress, receiverAmount, nonBsqCoinSelector); return getPreparedSendTx(receiverAddress, receiverAmount, nonBsqCoinSelector);
} }
private Transaction getPreparedSendTx(String receiverAddress, Coin receiverAmount, CoinSelector coinSelector) private Transaction getPreparedSendTx(String receiverAddress, Coin receiverAmount, CoinSelector coinSelector)
throws AddressFormatException, InsufficientBsqException, WalletException, TransactionVerificationException { throws AddressFormatException, InsufficientBsqException, WalletException, TransactionVerificationException, BsqChangeBelowDustException {
DaoKillSwitch.assertDaoIsNotDisabled(); DaoKillSwitch.assertDaoIsNotDisabled();
Transaction tx = new Transaction(params); Transaction tx = new Transaction(params);
checkArgument(Restrictions.isAboveDust(receiverAmount), checkArgument(Restrictions.isAboveDust(receiverAmount),
@ -510,6 +511,18 @@ public class BsqWalletService extends WalletService implements DaoStateListener
checkWalletConsistency(wallet); checkWalletConsistency(wallet);
verifyTransaction(tx); verifyTransaction(tx);
// printTx("prepareSendTx", 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) {
TransactionOutput bsqChangeOutput = tx.getOutputs().get(1);
if (!Restrictions.isAboveDust(bsqChangeOutput.getValue())) {
String msg = "BSQ change output is below dust limit. outputValue=" + bsqChangeOutput.getValue().toFriendlyString();
log.warn(msg);
throw new BsqChangeBelowDustException(msg, bsqChangeOutput.getValue());
}
}
return tx; return tx;
} catch (InsufficientMoneyException e) { } catch (InsufficientMoneyException e) {
log.error(e.toString()); log.error(e.toString());

View file

@ -2278,6 +2278,15 @@ popup.warning.noPriceFeedAvailable=There is no price feed available for that cur
popup.warning.sendMsgFailed=Sending message to your trading partner failed.\nPlease try again and if it continue to fail report a bug. popup.warning.sendMsgFailed=Sending message to your trading partner failed.\nPlease try again and if it continue to fail report a bug.
popup.warning.insufficientBtcFundsForBsqTx=You don''t have sufficient BTC funds for paying the miner fee for that transaction.\n\ popup.warning.insufficientBtcFundsForBsqTx=You don''t have sufficient BTC funds for paying the miner fee for that transaction.\n\
Please fund your BTC wallet.\nMissing funds: {0} Please fund your BTC wallet.\nMissing funds: {0}
popup.warning.bsqChangeBelowDustException=This transaction creates a BSQ change output which is below dust \
limit (5.46 BSQ) and would be rejected by the bitcoin network.\n\n\
You need to either send a higher amount to avoid the change output (e.g. by adding the dust amount to your \
sending amount) or add more BSQ funds to your wallet so you avoid to generate a dust output.\n\n\
The dust output is {0}.
popup.warning.btcChangeBelowDustException=This transaction creates a change output which is below dust \
limit (546 Satoshi) and would be rejected by the bitcoin network.\n\n\
You need to add the dust amount to your sending amount to avoid to generate a dust output.\n\n\
The dust output is {0}.
popup.warning.insufficientBsqFundsForBtcFeePayment=You don''t have sufficient BSQ funds for paying the trade fee in BSQ. \ popup.warning.insufficientBsqFundsForBtcFeePayment=You don''t have sufficient BSQ funds for paying the trade fee in BSQ. \
You can pay the fee in BTC or you need to fund your BSQ wallet. You can buy BSQ in Bisq.\n\n\ You can pay the fee in BTC or you need to fund your BSQ wallet. You can buy BSQ in Bisq.\n\n\

View file

@ -33,6 +33,7 @@ import bisq.desktop.util.validation.BsqAddressValidator;
import bisq.desktop.util.validation.BsqValidator; import bisq.desktop.util.validation.BsqValidator;
import bisq.desktop.util.validation.BtcValidator; import bisq.desktop.util.validation.BtcValidator;
import bisq.core.btc.exceptions.BsqChangeBelowDustException;
import bisq.core.btc.exceptions.TxBroadcastException; import bisq.core.btc.exceptions.TxBroadcastException;
import bisq.core.btc.listeners.BsqBalanceListener; import bisq.core.btc.listeners.BsqBalanceListener;
import bisq.core.btc.setup.WalletsSetup; import bisq.core.btc.setup.WalletsSetup;
@ -85,7 +86,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
private int gridRow = 0; private int gridRow = 0;
private InputTextField amountInputTextField, btcAmountInputTextField; private InputTextField amountInputTextField, btcAmountInputTextField;
private Button sendButton, sendBtcButton; private Button sendBsqButton, sendBtcButton;
private InputTextField receiversAddressInputTextField, receiversBtcAddressInputTextField; private InputTextField receiversAddressInputTextField, receiversBtcAddressInputTextField;
private ChangeListener<Boolean> focusOutListener; private ChangeListener<Boolean> focusOutListener;
private TitledGroupBg btcTitledGroupBg; private TitledGroupBg btcTitledGroupBg;
@ -200,7 +201,7 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
bsqValidator.setAvailableBalance(availableConfirmedBalance); bsqValidator.setAvailableBalance(availableConfirmedBalance);
boolean isValid = bsqAddressValidator.validate(receiversAddressInputTextField.getText()).isValid && boolean isValid = bsqAddressValidator.validate(receiversAddressInputTextField.getText()).isValid &&
bsqValidator.validate(amountInputTextField.getText()).isValid; bsqValidator.validate(amountInputTextField.getText()).isValid;
sendButton.setDisable(!isValid); sendBsqButton.setDisable(!isValid);
boolean isBtcValid = btcAddressValidator.validate(receiversBtcAddressInputTextField.getText()).isValid && boolean isBtcValid = btcAddressValidator.validate(receiversBtcAddressInputTextField.getText()).isValid &&
btcValidator.validate(btcAmountInputTextField.getText()).isValid; btcValidator.validate(btcAmountInputTextField.getText()).isValid;
@ -227,9 +228,9 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
onUpdateBalances(); onUpdateBalances();
}; };
sendButton = addButtonAfterGroup(root, ++gridRow, Res.get("dao.wallet.send.send")); sendBsqButton = addButtonAfterGroup(root, ++gridRow, Res.get("dao.wallet.send.send"));
sendButton.setOnAction((event) -> { sendBsqButton.setOnAction((event) -> {
// TODO break up in methods // TODO break up in methods
if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) { if (GUIUtil.isReadyForTxBroadcast(p2PService, walletsSetup)) {
String receiversAddressString = bsqFormatter.getAddressFromBsqAddress(receiversAddressInputTextField.getText()).toString(); String receiversAddressString = bsqFormatter.getAddressFromBsqAddress(receiversAddressInputTextField.getText()).toString();
@ -252,6 +253,9 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
receiversAddressInputTextField.setText(""); receiversAddressInputTextField.setText("");
amountInputTextField.setText(""); amountInputTextField.setText("");
}); });
} catch (BsqChangeBelowDustException e) {
String msg = Res.get("popup.warning.bsqChangeBelowDustException", bsqFormatter.formatCoinWithCode(e.getOutputValue()));
new Popup<>().warning(msg).show();
} catch (Throwable t) { } catch (Throwable t) {
handleError(t); handleError(t);
} }
@ -314,7 +318,9 @@ public class BsqSendView extends ActivatableView<GridPane, Void> implements BsqB
}); });
} }
} catch (BsqChangeBelowDustException e) {
String msg = Res.get("popup.warning.btcChangeBelowDustException", btcFormatter.formatCoinWithCode(e.getOutputValue()));
new Popup<>().warning(msg).show();
} catch (Throwable t) { } catch (Throwable t) {
handleError(t); handleError(t);
} }