diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index 3160125d8a..940e84b582 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -3293,6 +3293,18 @@ payment.accountType=Account type payment.checking=Checking payment.savings=Savings payment.personalId=Personal ID +payment.makeOfferToUnsignedAccount.warning=With the recent rise in BTC price, beware that selling 0.01 BTC or less incurs higher risk than before.\n\n\ +It is highly recommended to either:\n\ +- make offers >0.01 BTC, so you only deal with signed/trusted buyers\n\ +- keep any offers to sell <0.01 BTC to around ~100 USD in value, as this value has (historically) discouraged scammers\n\n\ +Bisq developers are working on better ways to secure the payment account model for such smaller trades. \ + Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling 0.01 BTC or less incurs higher risk than before.\n\n\ +It is highly recommended to either:\n\ +- take offers from signed buyers only\n\ +- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\n\ +Bisq developers are working on better ways to secure the payment account model for such smaller trades. \ + Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.clearXchange.info=Zelle is a money transfer service that works best *through* another bank.\n\n\ 1. Check this page to see if (and how) your bank works with Zelle: [HYPERLINK:https://www.zellepay.com/get-started]\n\n\ 2. Take special note of your transfer limits—sending limits vary by bank, and banks often specify separate daily, weekly, and monthly limits.\n\n\ 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 4c60ca7220..2bddeb4141 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/MutableOfferViewModel.java @@ -49,6 +49,7 @@ import bisq.core.offer.OfferPayload; import bisq.core.offer.OfferRestrictions; import bisq.core.offer.OfferUtil; import bisq.core.payment.PaymentAccount; +import bisq.core.payment.payload.PaymentMethod; import bisq.core.provider.fee.FeeService; import bisq.core.provider.price.MarketPrice; import bisq.core.provider.price.PriceFeedService; @@ -660,6 +661,7 @@ public abstract class MutableOfferViewModel ext btcValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin(dataModel.getTradeCurrencyCode().get())); btcValidator.setMaxTradeLimit(Coin.valueOf(dataModel.getMaxTradeLimit())); + maybeShowMakeOfferToUnsignedAccountWarning(); securityDepositValidator.setPaymentAccount(paymentAccount); } @@ -776,6 +778,8 @@ public abstract class MutableOfferViewModel ext } else { syncMinAmountWithAmount = true; } + + maybeShowMakeOfferToUnsignedAccountWarning(); } } @@ -1218,6 +1222,16 @@ public abstract class MutableOfferViewModel ext } } + private void maybeShowMakeOfferToUnsignedAccountWarning() { + if (dataModel.getDirection() == OfferPayload.Direction.SELL && + PaymentMethod.hasChargebackRisk(dataModel.getPaymentAccount().getPaymentMethod(), dataModel.getTradeCurrency().getCode())) { + Coin checkAmount = dataModel.getMinAmount().get() == null ? dataModel.getAmount().get() : dataModel.getMinAmount().get(); + if (checkAmount != null && !checkAmount.isGreaterThan(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT)) { + GUIUtil.showMakeOfferToUnsignedAccountWarning(); + } + } + } + private InputValidator.ValidationResult isBtcInputValid(String input) { return btcValidator.validate(input); } diff --git a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java index a10e9f08f0..016f0824c4 100644 --- a/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java +++ b/desktop/src/main/java/bisq/desktop/main/offer/takeoffer/TakeOfferView.java @@ -161,7 +161,7 @@ public class TakeOfferView extends ActivatableViewAndModel amountFocusedListener, getShowWalletFundedNotificationListener; @@ -304,6 +304,7 @@ public class TakeOfferView extends ActivatableViewAndModel im return dataModel.getDirection() == OfferPayload.Direction.BUY; } + public boolean isSellingToAnUnsignedAccount(Offer offer) { + if (offer.getDirection() == OfferPayload.Direction.BUY && + PaymentMethod.hasChargebackRisk(offer.getPaymentMethod(), offer.getCurrencyCode())) { + // considered risky when either UNSIGNED, PEER_INITIAL, or BANNED (see #5343) + return accountAgeWitnessService.getSignState(offer) == AccountAgeWitnessService.SignState.UNSIGNED || + accountAgeWitnessService.getSignState(offer) == AccountAgeWitnessService.SignState.PEER_INITIAL || + accountAgeWitnessService.getSignState(offer) == AccountAgeWitnessService.SignState.BANNED; + } + return false; + } + private InputValidator.ValidationResult isBtcInputValid(String input) { return btcValidator.validate(input); } diff --git a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java index ba1e174d7e..1cd240f5a9 100644 --- a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java +++ b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java @@ -698,6 +698,24 @@ public class GUIUtil { return t.cast(parent); } + public static void showTakeOfferFromUnsignedAccountWarning() { + String key = "confirmTakeOfferFromUnsignedAccount"; + new Popup().warning(Res.get("payment.takeOfferFromUnsignedAccount.warning")) + .width(900) + .closeButtonText(Res.get("shared.iConfirm")) + .dontShowAgainId(key) + .show(); + } + + public static void showMakeOfferToUnsignedAccountWarning() { + String key = "confirmMakeOfferToUnsignedAccount"; + new Popup().warning(Res.get("payment.makeOfferToUnsignedAccount.warning")) + .width(900) + .closeButtonText(Res.get("shared.iConfirm")) + .dontShowAgainId(key) + .show(); + } + public static void showClearXchangeWarning() { String key = "confirmClearXchangeRequirements"; final String currencyName = Config.baseCurrencyNetwork().getCurrencyName();