From 8a604ea60cdce6ded61ecd48057e4ca625d29e83 Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Tue, 7 Apr 2020 22:13:24 -0500 Subject: [PATCH 1/6] Rename class --- .../java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java | 4 ++-- .../java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java | 4 ++-- ...edPayoutTx.java => BuyerVerifiesFinalDelayedPayoutTx.java} | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename core/src/main/java/bisq/core/trade/protocol/tasks/buyer/{BuyerVerifiesDelayedPayoutTx.java => BuyerVerifiesFinalDelayedPayoutTx.java} (91%) diff --git a/core/src/main/java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java index 7bb9f25cd19..49f97dc8679 100644 --- a/core/src/main/java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java @@ -37,8 +37,8 @@ import bisq.core.trade.protocol.tasks.buyer.BuyerSetupPayoutTxListener; import bisq.core.trade.protocol.tasks.buyer.BuyerSignPayoutTx; import bisq.core.trade.protocol.tasks.buyer.BuyerSignsDelayedPayoutTx; -import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesDelayedPayoutTx; import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesDonationAddress; +import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesFinalDelayedPayoutTx; import bisq.core.trade.protocol.tasks.buyer_as_maker.BuyerAsMakerCreatesAndSignsDepositTx; import bisq.core.trade.protocol.tasks.buyer_as_maker.BuyerAsMakerSendsInputsForDepositTxResponse; import bisq.core.trade.protocol.tasks.maker.MakerCreateAndSignContract; @@ -171,7 +171,7 @@ private void handle(DepositTxAndDelayedPayoutTxMessage tradeMessage, NodeAddress errorMessage -> handleTaskRunnerFault(tradeMessage, errorMessage)); taskRunner.addTasks( BuyerProcessDepositTxAndDelayedPayoutTxMessage.class, - BuyerVerifiesDelayedPayoutTx.class, + BuyerVerifiesFinalDelayedPayoutTx.class, PublishTradeStatistics.class ); taskRunner.run(); diff --git a/core/src/main/java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java index c9e41e669ae..851cc2da9a9 100644 --- a/core/src/main/java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java @@ -39,8 +39,8 @@ import bisq.core.trade.protocol.tasks.buyer.BuyerSetupPayoutTxListener; import bisq.core.trade.protocol.tasks.buyer.BuyerSignPayoutTx; import bisq.core.trade.protocol.tasks.buyer.BuyerSignsDelayedPayoutTx; -import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesDelayedPayoutTx; import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesDonationAddress; +import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesFinalDelayedPayoutTx; import bisq.core.trade.protocol.tasks.buyer_as_taker.BuyerAsTakerCreatesDepositTxInputs; import bisq.core.trade.protocol.tasks.buyer_as_taker.BuyerAsTakerSendsDepositTxMessage; import bisq.core.trade.protocol.tasks.buyer_as_taker.BuyerAsTakerSignsDepositTx; @@ -195,7 +195,7 @@ private void handle(DepositTxAndDelayedPayoutTxMessage tradeMessage, NodeAddress errorMessage -> handleTaskRunnerFault(tradeMessage, errorMessage)); taskRunner.addTasks( BuyerProcessDepositTxAndDelayedPayoutTxMessage.class, - BuyerVerifiesDelayedPayoutTx.class, + BuyerVerifiesFinalDelayedPayoutTx.class, PublishTradeStatistics.class ); taskRunner.run(); diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesDelayedPayoutTx.java b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesFinalDelayedPayoutTx.java similarity index 91% rename from core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesDelayedPayoutTx.java rename to core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesFinalDelayedPayoutTx.java index fb98001183a..02b6610b259 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesDelayedPayoutTx.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesFinalDelayedPayoutTx.java @@ -29,9 +29,9 @@ import static com.google.common.base.Preconditions.checkNotNull; @Slf4j -public class BuyerVerifiesDelayedPayoutTx extends TradeTask { +public class BuyerVerifiesFinalDelayedPayoutTx extends TradeTask { @SuppressWarnings({"unused"}) - public BuyerVerifiesDelayedPayoutTx(TaskRunner taskHandler, Trade trade) { + public BuyerVerifiesFinalDelayedPayoutTx(TaskRunner taskHandler, Trade trade) { super(taskHandler, trade); } From 856863ee7018819bbf368c1c22640ba7150b5e70 Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Tue, 7 Apr 2020 22:16:02 -0500 Subject: [PATCH 2/6] Add DonationAddressValidation static class --- .../core/trade/DonationAddressValidation.java | 94 +++++++++++++++++++ .../buyer/BuyerVerifiesDonationAddress.java | 49 +++------- 2 files changed, 106 insertions(+), 37 deletions(-) create mode 100644 core/src/main/java/bisq/core/trade/DonationAddressValidation.java diff --git a/core/src/main/java/bisq/core/trade/DonationAddressValidation.java b/core/src/main/java/bisq/core/trade/DonationAddressValidation.java new file mode 100644 index 00000000000..8d798409c4e --- /dev/null +++ b/core/src/main/java/bisq/core/trade/DonationAddressValidation.java @@ -0,0 +1,94 @@ +/* + * 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 . + */ + +package bisq.core.trade; + +import bisq.core.btc.wallet.BtcWalletService; +import bisq.core.dao.DaoFacade; +import bisq.core.dao.governance.param.Param; + +import org.bitcoinj.core.Address; +import org.bitcoinj.core.NetworkParameters; +import org.bitcoinj.core.Transaction; +import org.bitcoinj.core.TransactionOutput; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import static com.google.common.base.Preconditions.checkNotNull; + +@Slf4j +public class DonationAddressValidation { + + @Getter + public static class DonationAddressException extends Exception { + private final String addressAsString; + private final String recentDonationAddressString; + private final String defaultDonationAddressString; + + DonationAddressException(String addressAsString, + String recentDonationAddressString, + String defaultDonationAddressString) { + + this.addressAsString = addressAsString; + this.recentDonationAddressString = recentDonationAddressString; + this.defaultDonationAddressString = defaultDonationAddressString; + } + } + + public static class MissingDelayedPayoutTxException extends Exception { + public MissingDelayedPayoutTxException(String msg) { + super(msg); + } + } + + public static void validate(Transaction delayedPayoutTx, + DaoFacade daoFacade, + BtcWalletService btcWalletService) throws DonationAddressException, MissingDelayedPayoutTxException { + if (delayedPayoutTx == null) { + throw new MissingDelayedPayoutTxException("DelayedPayoutTx must not be null"); + } + + // Get most recent donation address. + // We do not support past DAO param addresses to avoid that those receive funds (no bond set up anymore). + // Users who have not synced the DAO cannot trade. + String recentDonationAddressString = daoFacade.getParamValue(Param.RECIPIENT_BTC_ADDRESS); + + // In case the seller has deactivated the DAO the default address will be used. + String defaultDonationAddressString = Param.RECIPIENT_BTC_ADDRESS.getDefaultValue(); + + TransactionOutput output = delayedPayoutTx.getOutput(0); + NetworkParameters params = btcWalletService.getParams(); + Address address = output.getAddressFromP2PKHScript(params); + if (address == null) { + // The donation address can be as well be a multisig address. + address = output.getAddressFromP2SH(params); + checkNotNull(address, "address must not be null"); + } + + String addressAsString = address.toString(); + boolean isValid = recentDonationAddressString.equals(addressAsString) || + defaultDonationAddressString.equals(addressAsString); + if (!isValid) { + log.warn("Donation address is invalid." + + "\nAddress used by BTC seller: " + addressAsString + + "\nRecent donation address:" + recentDonationAddressString + + "\nDefault donation address: " + defaultDonationAddressString); + throw new DonationAddressException(addressAsString, recentDonationAddressString, defaultDonationAddressString); + } + } +} diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesDonationAddress.java b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesDonationAddress.java index c9c19ae3d59..5e91dc39c5d 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesDonationAddress.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesDonationAddress.java @@ -17,21 +17,14 @@ package bisq.core.trade.protocol.tasks.buyer; -import bisq.core.dao.governance.param.Param; +import bisq.core.trade.DonationAddressValidation; import bisq.core.trade.Trade; import bisq.core.trade.protocol.tasks.TradeTask; import bisq.common.taskrunner.TaskRunner; -import org.bitcoinj.core.Address; -import org.bitcoinj.core.NetworkParameters; -import org.bitcoinj.core.Transaction; -import org.bitcoinj.core.TransactionOutput; - import lombok.extern.slf4j.Slf4j; -import static com.google.common.base.Preconditions.checkNotNull; - @Slf4j public class BuyerVerifiesDonationAddress extends TradeTask { @SuppressWarnings({"unused"}) @@ -44,35 +37,17 @@ protected void run() { try { runInterceptHook(); - Transaction preparedDelayedPayoutTx = checkNotNull(processModel.getPreparedDelayedPayoutTx(), "preparedDelayedPayoutTx must not be null"); - - // Get most recent donation address. - // We do not support past DAO param addresses to avoid that those receive funds (no bond set up anymore). - // Users who have not synced the DAO cannot trade. - String recentDonationAddressString = processModel.getDaoFacade().getParamValue(Param.RECIPIENT_BTC_ADDRESS); - - // In case the seller has deactivated the DAO the default address will be used. - String defaultDonationAddressString = Param.RECIPIENT_BTC_ADDRESS.getDefaultValue(); - - TransactionOutput output = preparedDelayedPayoutTx.getOutput(0); - NetworkParameters params = processModel.getBtcWalletService().getParams(); - Address address = output.getAddressFromP2PKHScript(params); - if (address == null) { - // The donation address can be as well be a multisig address. - address = output.getAddressFromP2SH(params); - checkNotNull(address, "address must not be null"); - } - - String addressAsString = address.toString(); - if (recentDonationAddressString.equals(addressAsString) || - defaultDonationAddressString.equals(addressAsString)) { - complete(); - } else { - failed("Sellers donation address not recognized." + - "\nAddress used by BTC seller: " + addressAsString + - "\nRecent donation address:" + recentDonationAddressString + - "\nDefault donation address: " + defaultDonationAddressString); - } + DonationAddressValidation.validate(processModel.getPreparedDelayedPayoutTx(), + processModel.getDaoFacade(), + processModel.getBtcWalletService()); + complete(); + } catch (DonationAddressValidation.DonationAddressException e) { + failed("Sellers donation address is invalid." + + "\nAddress used by BTC seller: " + e.getAddressAsString() + + "\nRecent donation address:" + e.getRecentDonationAddressString() + + "\nDefault donation address: " + e.getDefaultDonationAddressString()); + } catch (DonationAddressValidation.MissingDelayedPayoutTxException e) { + failed(e.getMessage()); } catch (Throwable t) { failed(t); } From 99f542bc4bc6d1d154ab7c658fcf979e0ccb8635 Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Tue, 7 Apr 2020 22:16:32 -0500 Subject: [PATCH 3/6] Rename class --- .../java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java | 4 ++-- .../java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java | 4 ++-- ...Address.java => BuyerVerifiesPreparedDelayedPayoutTx.java} | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename core/src/main/java/bisq/core/trade/protocol/tasks/buyer/{BuyerVerifiesDonationAddress.java => BuyerVerifiesPreparedDelayedPayoutTx.java} (92%) diff --git a/core/src/main/java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java index 49f97dc8679..ec5d5547937 100644 --- a/core/src/main/java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/BuyerAsMakerProtocol.java @@ -37,8 +37,8 @@ import bisq.core.trade.protocol.tasks.buyer.BuyerSetupPayoutTxListener; import bisq.core.trade.protocol.tasks.buyer.BuyerSignPayoutTx; import bisq.core.trade.protocol.tasks.buyer.BuyerSignsDelayedPayoutTx; -import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesDonationAddress; import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesFinalDelayedPayoutTx; +import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesPreparedDelayedPayoutTx; import bisq.core.trade.protocol.tasks.buyer_as_maker.BuyerAsMakerCreatesAndSignsDepositTx; import bisq.core.trade.protocol.tasks.buyer_as_maker.BuyerAsMakerSendsInputsForDepositTxResponse; import bisq.core.trade.protocol.tasks.maker.MakerCreateAndSignContract; @@ -155,7 +155,7 @@ private void handle(DelayedPayoutTxSignatureRequest tradeMessage, NodeAddress pe errorMessage -> handleTaskRunnerFault(tradeMessage, errorMessage)); taskRunner.addTasks( BuyerProcessDelayedPayoutTxSignatureRequest.class, - BuyerVerifiesDonationAddress.class, + BuyerVerifiesPreparedDelayedPayoutTx.class, BuyerSignsDelayedPayoutTx.class, BuyerSendsDelayedPayoutTxSignatureResponse.class ); diff --git a/core/src/main/java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java b/core/src/main/java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java index 851cc2da9a9..6665c001ec6 100644 --- a/core/src/main/java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java +++ b/core/src/main/java/bisq/core/trade/protocol/BuyerAsTakerProtocol.java @@ -39,8 +39,8 @@ import bisq.core.trade.protocol.tasks.buyer.BuyerSetupPayoutTxListener; import bisq.core.trade.protocol.tasks.buyer.BuyerSignPayoutTx; import bisq.core.trade.protocol.tasks.buyer.BuyerSignsDelayedPayoutTx; -import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesDonationAddress; import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesFinalDelayedPayoutTx; +import bisq.core.trade.protocol.tasks.buyer.BuyerVerifiesPreparedDelayedPayoutTx; import bisq.core.trade.protocol.tasks.buyer_as_taker.BuyerAsTakerCreatesDepositTxInputs; import bisq.core.trade.protocol.tasks.buyer_as_taker.BuyerAsTakerSendsDepositTxMessage; import bisq.core.trade.protocol.tasks.buyer_as_taker.BuyerAsTakerSignsDepositTx; @@ -178,7 +178,7 @@ private void handle(DelayedPayoutTxSignatureRequest tradeMessage, NodeAddress se errorMessage -> handleTaskRunnerFault(tradeMessage, errorMessage)); taskRunner.addTasks( BuyerProcessDelayedPayoutTxSignatureRequest.class, - BuyerVerifiesDonationAddress.class, + BuyerVerifiesPreparedDelayedPayoutTx.class, BuyerSignsDelayedPayoutTx.class, BuyerSendsDelayedPayoutTxSignatureResponse.class ); diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesDonationAddress.java b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesPreparedDelayedPayoutTx.java similarity index 92% rename from core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesDonationAddress.java rename to core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesPreparedDelayedPayoutTx.java index 5e91dc39c5d..51c28b30fb3 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesDonationAddress.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesPreparedDelayedPayoutTx.java @@ -26,9 +26,9 @@ import lombok.extern.slf4j.Slf4j; @Slf4j -public class BuyerVerifiesDonationAddress extends TradeTask { +public class BuyerVerifiesPreparedDelayedPayoutTx extends TradeTask { @SuppressWarnings({"unused"}) - public BuyerVerifiesDonationAddress(TaskRunner taskHandler, Trade trade) { + public BuyerVerifiesPreparedDelayedPayoutTx(TaskRunner taskHandler, Trade trade) { super(taskHandler, trade); } From 8cf6d42309eaee88ac2bc1edceb6ab3068924805 Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Tue, 7 Apr 2020 23:04:57 -0500 Subject: [PATCH 4/6] Add more checks for delayed payout tx --- .../core/btc/wallet/TradeWalletService.java | 33 ++++++++++++++----- .../core/trade/DonationAddressValidation.java | 4 +++ .../BuyerVerifiesFinalDelayedPayoutTx.java | 4 ++- .../BuyerVerifiesPreparedDelayedPayoutTx.java | 30 ++++++++++++++++- .../main/offer/MutableOfferViewModel.java | 2 +- 5 files changed, 62 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java b/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java index d6f4a8b4f96..c55ffb122ac 100644 --- a/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java +++ b/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java @@ -724,11 +724,29 @@ public Transaction finalizeDelayedPayoutTx(Transaction delayedPayoutTx, return delayedPayoutTx; } - public boolean verifiesDepositTxAndDelayedPayoutTx(@SuppressWarnings("unused") Transaction depositTx, - Transaction delayedPayoutTx) { - // todo add more checks - if (delayedPayoutTx.getLockTime() == 0) { - log.error("Time lock is not set"); + public boolean verifiesDepositTxAndDelayedPayoutTx(Transaction depositTx, + Transaction delayedPayoutTx, + long lockTime) { + + TransactionOutput p2SHMultiSigOutput = depositTx.getOutput(0); + if (delayedPayoutTx.getInputs().size() != 1) { + log.error("Number of inputs must be 1"); + return false; + } + + TransactionOutput connectedOutput = delayedPayoutTx.getInput(0).getConnectedOutput(); + if (connectedOutput == null) { + log.error("connectedOutput must not be null"); + return false; + } + + if (!connectedOutput.equals(p2SHMultiSigOutput)) { + log.error("connectedOutput must be p2SHMultiSigOutput"); + return false; + } + + if (delayedPayoutTx.getLockTime() != lockTime) { + log.error("LockTime must match trades lockTime"); return false; } @@ -1228,11 +1246,10 @@ private void applyLockTime(long lockTime, Transaction tx) { private boolean removeDust(Transaction transaction) { List originalTransactionOutputs = transaction.getOutputs(); List keepTransactionOutputs = new ArrayList<>(); - for (TransactionOutput transactionOutput: originalTransactionOutputs) { + for (TransactionOutput transactionOutput : originalTransactionOutputs) { if (transactionOutput.getValue().isLessThan(Restrictions.getMinNonDustOutput())) { log.info("your transaction would have contained a dust output of {}", transactionOutput.toString()); - } - else { + } else { keepTransactionOutputs.add(transactionOutput); } } diff --git a/core/src/main/java/bisq/core/trade/DonationAddressValidation.java b/core/src/main/java/bisq/core/trade/DonationAddressValidation.java index 8d798409c4e..1dc8236d032 100644 --- a/core/src/main/java/bisq/core/trade/DonationAddressValidation.java +++ b/core/src/main/java/bisq/core/trade/DonationAddressValidation.java @@ -29,6 +29,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; @Slf4j @@ -71,6 +72,9 @@ public static void validate(Transaction delayedPayoutTx, // In case the seller has deactivated the DAO the default address will be used. String defaultDonationAddressString = Param.RECIPIENT_BTC_ADDRESS.getDefaultValue(); + checkArgument(delayedPayoutTx.getOutputs().size() == 1, + "preparedDelayedPayoutTx must have 1 output"); + TransactionOutput output = delayedPayoutTx.getOutput(0); NetworkParameters params = btcWalletService.getParams(); Address address = output.getAddressFromP2PKHScript(params); diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesFinalDelayedPayoutTx.java b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesFinalDelayedPayoutTx.java index 02b6610b259..7e643f7bf94 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesFinalDelayedPayoutTx.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesFinalDelayedPayoutTx.java @@ -42,7 +42,9 @@ protected void run() { Transaction depositTx = checkNotNull(trade.getDepositTx()); Transaction delayedPayoutTx = checkNotNull(trade.getDelayedPayoutTx()); - if (processModel.getTradeWalletService().verifiesDepositTxAndDelayedPayoutTx(depositTx, delayedPayoutTx)) { + if (processModel.getTradeWalletService().verifiesDepositTxAndDelayedPayoutTx(depositTx, + delayedPayoutTx, + trade.getLockTime())) { complete(); } else { failed("DelayedPayoutTx is not spending depositTx correctly"); diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesPreparedDelayedPayoutTx.java b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesPreparedDelayedPayoutTx.java index 51c28b30fb3..bf226a000ac 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesPreparedDelayedPayoutTx.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/buyer/BuyerVerifiesPreparedDelayedPayoutTx.java @@ -17,14 +17,22 @@ package bisq.core.trade.protocol.tasks.buyer; +import bisq.core.offer.Offer; import bisq.core.trade.DonationAddressValidation; import bisq.core.trade.Trade; import bisq.core.trade.protocol.tasks.TradeTask; import bisq.common.taskrunner.TaskRunner; +import org.bitcoinj.core.Coin; +import org.bitcoinj.core.Transaction; +import org.bitcoinj.core.TransactionInput; + import lombok.extern.slf4j.Slf4j; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + @Slf4j public class BuyerVerifiesPreparedDelayedPayoutTx extends TradeTask { @SuppressWarnings({"unused"}) @@ -37,9 +45,29 @@ protected void run() { try { runInterceptHook(); - DonationAddressValidation.validate(processModel.getPreparedDelayedPayoutTx(), + Transaction preparedDelayedPayoutTx = processModel.getPreparedDelayedPayoutTx(); + + // Check donation address + DonationAddressValidation.validate(preparedDelayedPayoutTx, processModel.getDaoFacade(), processModel.getBtcWalletService()); + + // Check amount + Offer offer = checkNotNull(trade.getOffer()); + Coin msOutputAmount = offer.getBuyerSecurityDeposit() + .add(offer.getSellerSecurityDeposit()) + .add(checkNotNull(trade.getTradeAmount())); + checkArgument(preparedDelayedPayoutTx.getOutput(0).getValue().equals(msOutputAmount), + "output value of deposit tx and delayed payout tx must match"); + + // Check lock time + checkArgument(preparedDelayedPayoutTx.getLockTime() == trade.getLockTime(), + "preparedDelayedPayoutTx lock time must match trade.getLockTime()"); + + // Check seq num + checkArgument(preparedDelayedPayoutTx.getInputs().stream().anyMatch(e -> e.getSequenceNumber() == TransactionInput.NO_SEQUENCE - 1), + "Sequence number must be 0xFFFFFFFE"); + complete(); } catch (DonationAddressValidation.DonationAddressException e) { failed("Sellers donation address is invalid." + diff --git a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java index cf3aa27dbaf..7d4125a3e2c 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java @@ -231,7 +231,7 @@ public void activate() { if (DevEnv.isDevMode()) { UserThread.runAfter(() -> { amount.set("0.001"); - price.set("75000"); // for CNY + price.set("0.0001"); // for BSQ minAmount.set(amount.get()); onFocusOutPriceAsPercentageTextField(true, false); applyMakerFee(); From 4f28205478f8ba0135ad51f0dadc72e82b5e4f8f Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Tue, 7 Apr 2020 23:23:58 -0500 Subject: [PATCH 5/6] Add check for donation address at pending trades --- .../java/bisq/core/trade/TradeManager.java | 10 ++++++++ .../resources/i18n/displayStrings.properties | 7 ++++++ .../pendingtrades/PendingTradesDataModel.java | 4 ++++ .../steps/buyer/BuyerStep1View.java | 23 +++++++++++++++++++ .../steps/buyer/BuyerStep2View.java | 16 +++++++++++++ 5 files changed, 60 insertions(+) diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index f55b8bd0d0c..a981895b0d2 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -297,6 +297,16 @@ private void initPendingTrades() { trade.getId()); tradesWithoutDepositTx.add(trade); } + + try { + DonationAddressValidation.validate(trade.getDelayedPayoutTx(), + daoFacade, + btcWalletService); + } catch (DonationAddressValidation.DonationAddressException | + DonationAddressValidation.MissingDelayedPayoutTxException e) { + // We move it to failed trades so it cannot be continued. + addTradeToFailedTradesList.add(trade); + } } ); diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index 47764e19d3a..f6e9f2ef4b1 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -555,6 +555,13 @@ portfolio.tab.history=History portfolio.tab.failed=Failed portfolio.tab.editOpenOffer=Edit offer +portfolio.pending.invalidDonationAddress=The donation address in the delayed payout transaction is invalid.\n\n\ + Please do NOT send the Altcoin or Fiat payment but contact the Bisq developers at 'https://bisq.community' or \ + the Keybase channel.\n\n\ + Address used by BTC seller: {0}\n\ + Recent donation address: {1}\n\ + Default donation address: {2}; + portfolio.pending.step1.waitForConf=Wait for blockchain confirmation portfolio.pending.step2_buyer.startPayment=Start payment portfolio.pending.step2_seller.waitPaymentStarted=Wait until payment has started diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java index 88f45602f13..49d79a0874a 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java @@ -31,6 +31,7 @@ import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.btc.setup.WalletsSetup; import bisq.core.btc.wallet.BtcWalletService; +import bisq.core.dao.DaoFacade; import bisq.core.locale.Res; import bisq.core.offer.Offer; import bisq.core.offer.OfferPayload; @@ -99,6 +100,7 @@ public class PendingTradesDataModel extends ActivatableDataModel { private final WalletsSetup walletsSetup; @Getter private final AccountAgeWitnessService accountAgeWitnessService; + public final DaoFacade daoFacade; public final Navigation navigation; public final WalletPasswordWindow walletPasswordWindow; private final NotificationCenter notificationCenter; @@ -134,6 +136,7 @@ public PendingTradesDataModel(TradeManager tradeManager, P2PService p2PService, WalletsSetup walletsSetup, AccountAgeWitnessService accountAgeWitnessService, + DaoFacade daoFacade, Navigation navigation, WalletPasswordWindow walletPasswordWindow, NotificationCenter notificationCenter) { @@ -147,6 +150,7 @@ public PendingTradesDataModel(TradeManager tradeManager, this.p2PService = p2PService; this.walletsSetup = walletsSetup; this.accountAgeWitnessService = accountAgeWitnessService; + this.daoFacade = daoFacade; this.navigation = navigation; this.walletPasswordWindow = walletPasswordWindow; this.notificationCenter = notificationCenter; diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java index 2c1d75fa501..3d74690eaf6 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java @@ -17,10 +17,12 @@ package bisq.desktop.main.portfolio.pendingtrades.steps.buyer; +import bisq.desktop.main.overlays.popups.Popup; import bisq.desktop.main.portfolio.pendingtrades.PendingTradesViewModel; import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView; import bisq.core.locale.Res; +import bisq.core.trade.DonationAddressValidation; public class BuyerStep1View extends TradeStepView { @@ -32,6 +34,27 @@ public BuyerStep1View(PendingTradesViewModel model) { super(model); } + @Override + public void activate() { + super.activate(); + + try { + DonationAddressValidation.validate(trade.getDelayedPayoutTx(), + model.dataModel.daoFacade, + model.dataModel.btcWalletService); + } catch (DonationAddressValidation.DonationAddressException e) { + new Popup().warning(Res.get("portfolio.pending.invalidDonationAddress", + e.getAddressAsString(), + e.getRecentDonationAddressString(), + e.getDefaultDonationAddressString())) + .show(); + } catch (DonationAddressValidation.MissingDelayedPayoutTxException e) { + // We don't react on that error as a failed trade might get listed initially but getting removed from the + // trade manager after initPendingTrades which happens after activate might be called. + } + } + + /////////////////////////////////////////////////////////////////////////////////////////// // Info /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java index 80cb21526b5..367e3852610 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java @@ -69,6 +69,7 @@ import bisq.core.payment.payload.PaymentMethod; import bisq.core.payment.payload.USPostalMoneyOrderAccountPayload; import bisq.core.payment.payload.WesternUnionAccountPayload; +import bisq.core.trade.DonationAddressValidation; import bisq.core.trade.Trade; import bisq.core.user.DontShowAgainLookup; @@ -114,6 +115,21 @@ public BuyerStep2View(PendingTradesViewModel model) { public void activate() { super.activate(); + try { + DonationAddressValidation.validate(trade.getDelayedPayoutTx(), + model.dataModel.daoFacade, + model.dataModel.btcWalletService); + } catch (DonationAddressValidation.DonationAddressException e) { + new Popup().warning(Res.get("portfolio.pending.invalidDonationAddress", + e.getAddressAsString(), + e.getRecentDonationAddressString(), + e.getDefaultDonationAddressString())) + .show(); + } catch (DonationAddressValidation.MissingDelayedPayoutTxException ignore) { + // We don't react on that error as a failed trade might get listed initially but getting removed from the + // trade manager after initPendingTrades which happens after activate might be called. + } + if (timeoutTimer != null) timeoutTimer.stop(); From 0e6c4239b59d4c6902265006aa582f5f837620bd Mon Sep 17 00:00:00 2001 From: sqrrm Date: Wed, 8 Apr 2020 11:22:36 +0200 Subject: [PATCH 6/6] Fix value of delayedpayouttx for ranged trades --- core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java b/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java index c55ffb122ac..64756692869 100644 --- a/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java +++ b/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java @@ -675,7 +675,7 @@ public Transaction createDelayedUnsignedPayoutTx(Transaction depositTx, Transaction delayedPayoutTx = new Transaction(params); delayedPayoutTx.addInput(p2SHMultiSigOutput); applyLockTime(lockTime, delayedPayoutTx); - Coin outputAmount = depositTx.getOutputSum().subtract(minerFee); + Coin outputAmount = p2SHMultiSigOutput.getValue().subtract(minerFee); delayedPayoutTx.addOutput(outputAmount, Address.fromBase58(params, donationAddressString)); WalletService.printTx("Unsigned delayedPayoutTx ToDonationAddress", delayedPayoutTx); WalletService.verifyTransaction(delayedPayoutTx);