diff --git a/common/src/main/java/bisq/common/config/Config.java b/common/src/main/java/bisq/common/config/Config.java index 34928a1019e..51aaa040502 100644 --- a/common/src/main/java/bisq/common/config/Config.java +++ b/common/src/main/java/bisq/common/config/Config.java @@ -714,7 +714,7 @@ public Config(String defaultAppName, File defaultUserDataDir, String... args) { this.genesisTxId = options.valueOf(genesisTxIdOpt); this.genesisBlockHeight = options.valueOf(genesisBlockHeightOpt); this.genesisTotalSupply = options.valueOf(genesisTotalSupplyOpt); - this.daoActivated = options.valueOf(daoActivatedOpt) || !baseCurrencyNetwork.isMainnet(); + this.daoActivated = options.valueOf(daoActivatedOpt); this.dumpDelayedPayoutTxs = options.valueOf(dumpDelayedPayoutTxsOpt); } catch (OptionException ex) { throw new ConfigException("problem parsing option '%s': %s", 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 64756692869..7f2692d1e48 100644 --- a/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java +++ b/core/src/main/java/bisq/core/btc/wallet/TradeWalletService.java @@ -724,40 +724,6 @@ public Transaction finalizeDelayedPayoutTx(Transaction delayedPayoutTx, return delayedPayoutTx; } - 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; - } - - if (delayedPayoutTx.getInputs().stream().noneMatch(e -> e.getSequenceNumber() == TransactionInput.NO_SEQUENCE - 1)) { - log.error("Sequence number must be 0xFFFFFFFE"); - return false; - } - - return true; - } - /////////////////////////////////////////////////////////////////////////////////////////// // Standard payout tx diff --git a/core/src/main/java/bisq/core/trade/DelayedPayoutTxValidation.java b/core/src/main/java/bisq/core/trade/DelayedPayoutTxValidation.java new file mode 100644 index 00000000000..aaaf026e19f --- /dev/null +++ b/core/src/main/java/bisq/core/trade/DelayedPayoutTxValidation.java @@ -0,0 +1,180 @@ +/* + * 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 bisq.core.offer.Offer; + +import bisq.common.config.Config; + +import org.bitcoinj.core.Address; +import org.bitcoinj.core.Coin; +import org.bitcoinj.core.NetworkParameters; +import org.bitcoinj.core.Transaction; +import org.bitcoinj.core.TransactionInput; +import org.bitcoinj.core.TransactionOutput; + +import java.util.List; + +import lombok.extern.slf4j.Slf4j; + +import static com.google.common.base.Preconditions.checkNotNull; + +@Slf4j +public class DelayedPayoutTxValidation { + + public static class DonationAddressException extends Exception { + DonationAddressException(String msg) { + super(msg); + } + } + + public static class MissingDelayedPayoutTxException extends Exception { + MissingDelayedPayoutTxException(String msg) { + super(msg); + } + } + + public static class InvalidTxException extends Exception { + InvalidTxException(String msg) { + super(msg); + } + } + + public static class InvalidLockTimeException extends Exception { + InvalidLockTimeException(String msg) { + super(msg); + } + } + + public static void validatePayoutTx(Trade trade, + Transaction delayedPayoutTx, + DaoFacade daoFacade, + BtcWalletService btcWalletService) + throws DonationAddressException, MissingDelayedPayoutTxException, + InvalidTxException, InvalidLockTimeException { + String errorMsg; + if (delayedPayoutTx == null) { + errorMsg = "DelayedPayoutTx must not be null"; + log.error(errorMsg); + throw new MissingDelayedPayoutTxException("DelayedPayoutTx must not be null"); + } + + // Validate tx structure + if (delayedPayoutTx.getInputs().size() != 1) { + errorMsg = "Number of delayedPayoutTx inputs must be 1"; + log.error(errorMsg); + log.error(delayedPayoutTx.toString()); + throw new InvalidTxException(errorMsg); + } + + if (delayedPayoutTx.getOutputs().size() != 1) { + errorMsg = "Number of delayedPayoutTx outputs must be 1"; + log.error(errorMsg); + log.error(delayedPayoutTx.toString()); + throw new InvalidTxException(errorMsg); + } + + // connectedOutput is null and input.getValue() is null at that point as the tx is not committed to the wallet + // yet. So we cannot check that the input matches but we did the amount check earlier in the trade protocol. + + // Validate lock time + if (delayedPayoutTx.getLockTime() != trade.getLockTime()) { + errorMsg = "delayedPayoutTx.getLockTime() must match trade.getLockTime()"; + log.error(errorMsg); + log.error(delayedPayoutTx.toString()); + throw new InvalidLockTimeException(errorMsg); + } + + // Validate seq num + if (delayedPayoutTx.getInput(0).getSequenceNumber() != TransactionInput.NO_SEQUENCE - 1) { + errorMsg = "Sequence number must be 0xFFFFFFFE"; + log.error(errorMsg); + log.error(delayedPayoutTx.toString()); + throw new InvalidLockTimeException(errorMsg); + } + + // Check amount + TransactionOutput output = delayedPayoutTx.getOutput(0); + Offer offer = checkNotNull(trade.getOffer()); + Coin msOutputAmount = offer.getBuyerSecurityDeposit() + .add(offer.getSellerSecurityDeposit()) + .add(checkNotNull(trade.getTradeAmount())); + + if (!output.getValue().equals(msOutputAmount)) { + errorMsg = "Output value of deposit tx and delayed payout tx is not matching. Output: " + output + " / msOutputAmount: " + msOutputAmount; + log.error(errorMsg); + log.error(delayedPayoutTx.toString()); + throw new InvalidTxException(errorMsg); + } + + + // Validate donation address + // 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. + + + 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); + if (address == null) { + errorMsg = "Donation address cannot be resolved (not of type P2PKHScript or P2SH). Output: " + output; + log.error(errorMsg); + log.error(delayedPayoutTx.toString()); + throw new DonationAddressException(errorMsg); + } + } + + String addressAsString = address.toString(); + + // In case the seller has deactivated the DAO the default address will be used. + String defaultDonationAddressString = Param.RECIPIENT_BTC_ADDRESS.getDefaultValue(); + boolean defaultNotMatching = !defaultDonationAddressString.equals(addressAsString); + String recentDonationAddressString = daoFacade.getParamValue(Param.RECIPIENT_BTC_ADDRESS); + boolean recentFromDaoNotMatching = !recentDonationAddressString.equals(addressAsString); + + // If buyer has DAO deactivated or not synced he will not be able to see recent address used by the seller, so + // we add it hard coded here. We need to support also the default one as + // FIXME This is a quick fix and should be improved in future. + // We use the default addresses for non mainnet networks. For dev testing it need to be changed here. + // We use a list to gain more flexibility at updates of DAO param, but still might fail if buyer has not updated + // software. Needs a better solution.... + List hardCodedAddresses = Config.baseCurrencyNetwork().isMainnet() ? List.of("3A8Zc1XioE2HRzYfbb5P8iemCS72M6vRJV") : // mainnet + Config.baseCurrencyNetwork().isDaoBetaNet() ? List.of("1BVxNn3T12veSK6DgqwU4Hdn7QHcDDRag7") : // daoBetaNet + Config.baseCurrencyNetwork().isTestnet() ? List.of("2N4mVTpUZAnhm9phnxB7VrHB4aBhnWrcUrV") : // testnet + List.of("2MzBNTJDjjXgViKBGnatDU3yWkJ8pJkEg9w"); // regtest or DAO testnet (regtest) + + boolean noneOfHardCodedMatching = hardCodedAddresses.stream().noneMatch(e -> e.equals(addressAsString)); + + // If seller has DAO deactivated as well we get default address + if (recentFromDaoNotMatching && defaultNotMatching && noneOfHardCodedMatching) { + errorMsg = "Donation address is invalid." + + "\nAddress used by BTC seller: " + addressAsString + + "\nRecent donation address:" + recentDonationAddressString + + "\nDefault donation address: " + defaultDonationAddressString; + log.error(errorMsg); + log.error(delayedPayoutTx.toString()); + throw new DonationAddressException(errorMsg); + } + } +} diff --git a/core/src/main/java/bisq/core/trade/DonationAddressValidation.java b/core/src/main/java/bisq/core/trade/DonationAddressValidation.java deleted file mode 100644 index 1dc8236d032..00000000000 --- a/core/src/main/java/bisq/core/trade/DonationAddressValidation.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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.checkArgument; -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(); - - checkArgument(delayedPayoutTx.getOutputs().size() == 1, - "preparedDelayedPayoutTx must have 1 output"); - - 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/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index a981895b0d2..262156714c6 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -299,12 +299,17 @@ private void initPendingTrades() { } try { - DonationAddressValidation.validate(trade.getDelayedPayoutTx(), + DelayedPayoutTxValidation.validatePayoutTx(trade, + trade.getDelayedPayoutTx(), daoFacade, btcWalletService); - } catch (DonationAddressValidation.DonationAddressException | - DonationAddressValidation.MissingDelayedPayoutTxException e) { + } catch (DelayedPayoutTxValidation.DonationAddressException | + DelayedPayoutTxValidation.InvalidTxException | + DelayedPayoutTxValidation.InvalidLockTimeException | + DelayedPayoutTxValidation.MissingDelayedPayoutTxException e) { // We move it to failed trades so it cannot be continued. + log.warn("We move the trade with ID '{}' to failed trades because of exception {}", + trade.getId(), e.getMessage()); addTradeToFailedTradesList.add(trade); } } 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 7e643f7bf94..d0ebb8a509b 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 @@ -17,6 +17,7 @@ package bisq.core.trade.protocol.tasks.buyer; +import bisq.core.trade.DelayedPayoutTxValidation; import bisq.core.trade.Trade; import bisq.core.trade.protocol.tasks.TradeTask; @@ -26,8 +27,6 @@ import lombok.extern.slf4j.Slf4j; -import static com.google.common.base.Preconditions.checkNotNull; - @Slf4j public class BuyerVerifiesFinalDelayedPayoutTx extends TradeTask { @SuppressWarnings({"unused"}) @@ -40,15 +39,19 @@ protected void run() { try { runInterceptHook(); - Transaction depositTx = checkNotNull(trade.getDepositTx()); - Transaction delayedPayoutTx = checkNotNull(trade.getDelayedPayoutTx()); - if (processModel.getTradeWalletService().verifiesDepositTxAndDelayedPayoutTx(depositTx, + Transaction delayedPayoutTx = trade.getDelayedPayoutTx(); + // Check again tx + DelayedPayoutTxValidation.validatePayoutTx(trade, delayedPayoutTx, - trade.getLockTime())) { - complete(); - } else { - failed("DelayedPayoutTx is not spending depositTx correctly"); - } + processModel.getDaoFacade(), + processModel.getBtcWalletService()); + + complete(); + } catch (DelayedPayoutTxValidation.DonationAddressException | + DelayedPayoutTxValidation.MissingDelayedPayoutTxException | + DelayedPayoutTxValidation.InvalidTxException | + DelayedPayoutTxValidation.InvalidLockTimeException e) { + failed(e.getMessage()); } catch (Throwable t) { failed(t); } 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 bf226a000ac..ea9c2a7cbf4 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,22 +17,14 @@ package bisq.core.trade.protocol.tasks.buyer; -import bisq.core.offer.Offer; -import bisq.core.trade.DonationAddressValidation; +import bisq.core.trade.DelayedPayoutTxValidation; 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"}) @@ -45,36 +37,16 @@ protected void run() { try { runInterceptHook(); - Transaction preparedDelayedPayoutTx = processModel.getPreparedDelayedPayoutTx(); - - // Check donation address - DonationAddressValidation.validate(preparedDelayedPayoutTx, + DelayedPayoutTxValidation.validatePayoutTx(trade, + processModel.getPreparedDelayedPayoutTx(), 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." + - "\nAddress used by BTC seller: " + e.getAddressAsString() + - "\nRecent donation address:" + e.getRecentDonationAddressString() + - "\nDefault donation address: " + e.getDefaultDonationAddressString()); - } catch (DonationAddressValidation.MissingDelayedPayoutTxException e) { + } catch (DelayedPayoutTxValidation.DonationAddressException | + DelayedPayoutTxValidation.MissingDelayedPayoutTxException | + DelayedPayoutTxValidation.InvalidTxException | + DelayedPayoutTxValidation.InvalidLockTimeException e) { failed(e.getMessage()); } catch (Throwable t) { failed(t); diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index f6e9f2ef4b1..7aa10bab572 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -555,12 +555,10 @@ 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\ +portfolio.pending.invalidDelayedPayoutTx=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}; + {0} portfolio.pending.step1.waitForConf=Wait for blockchain confirmation portfolio.pending.step2_buyer.startPayment=Start payment 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 3d74690eaf6..9c90991880b 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 @@ -22,7 +22,7 @@ import bisq.desktop.main.portfolio.pendingtrades.steps.TradeStepView; import bisq.core.locale.Res; -import bisq.core.trade.DonationAddressValidation; +import bisq.core.trade.DelayedPayoutTxValidation; public class BuyerStep1View extends TradeStepView { @@ -39,17 +39,16 @@ public void activate() { super.activate(); try { - DonationAddressValidation.validate(trade.getDelayedPayoutTx(), + DelayedPayoutTxValidation.validatePayoutTx(trade, + 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 + } catch (DelayedPayoutTxValidation.DonationAddressException | + DelayedPayoutTxValidation.InvalidTxException | + DelayedPayoutTxValidation.InvalidLockTimeException e) { + new Popup().warning(Res.get("portfolio.pending.invalidDelayedPayoutTx", e.getMessage())).show(); + } catch (DelayedPayoutTxValidation.MissingDelayedPayoutTxException ignore) { + // We don't react on those errors as a failed trade might get listed initially but getting removed from the // trade manager after initPendingTrades which happens after activate might be called. } } 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 367e3852610..fb212e170b2 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,7 +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.DelayedPayoutTxValidation; import bisq.core.trade.Trade; import bisq.core.user.DontShowAgainLookup; @@ -116,17 +116,16 @@ public void activate() { super.activate(); try { - DonationAddressValidation.validate(trade.getDelayedPayoutTx(), + DelayedPayoutTxValidation.validatePayoutTx(trade, + 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 + } catch (DelayedPayoutTxValidation.DonationAddressException | + DelayedPayoutTxValidation.InvalidTxException | + DelayedPayoutTxValidation.InvalidLockTimeException e) { + new Popup().warning(Res.get("portfolio.pending.invalidDelayedPayoutTx", e.getMessage())).show(); + } catch (DelayedPayoutTxValidation.MissingDelayedPayoutTxException ignore) { + // We don't react on those errors as a failed trade might get listed initially but getting removed from the // trade manager after initPendingTrades which happens after activate might be called. }