Skip to content

Commit

Permalink
Increase trading limits as an opt-in setting (GH proposal 398)
Browse files Browse the repository at this point in the history
More restrictive limits will still apply based on payment method.

It is intended to avoid that a new users who do not fully understand
the process of a Bisq trade to cause an arbitration case with high
amounts and therefore higher risks and costs for the DAO.
  • Loading branch information
jmacxx committed Nov 29, 2022
1 parent 28c4da3 commit c796531
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 7 deletions.
15 changes: 15 additions & 0 deletions core/src/main/java/bisq/core/user/Preferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
public static final boolean USE_SYMMETRIC_SECURITY_DEPOSIT = true;
public static final int CLEAR_DATA_AFTER_DAYS_INITIAL = 99999; // feature effectively disabled until user agrees to settings notification
public static final int CLEAR_DATA_AFTER_DAYS_DEFAULT = 60; // used when user has agreed to settings notification
public static final long INITIAL_TRADE_LIMIT = 10000000L;

// payload is initialized so the default values are available for Property initialization.
@Setter
Expand Down Expand Up @@ -835,6 +836,16 @@ public void setUseBitcoinUrisInQrCodes(boolean value) {
requestPersistence();
}

public void setUserHasRaisedTradeLimit(boolean value) {
prefPayload.setUserHasRaisedTradeLimit(value);
requestPersistence();
}

public void setUserDefinedTradeLimit(long value) {
prefPayload.setUserDefinedTradeLimit(value);
requestPersistence();
}


///////////////////////////////////////////////////////////////////////////////////////////
// Getter
Expand Down Expand Up @@ -1160,5 +1171,9 @@ private interface ExcludesDelegateMethods {
void setBuyScreenCryptoCurrencyCode(String buyScreenCurrencyCode);

void setSellScreenCryptoCurrencyCode(String sellScreenCurrencyCode);

void setUserDefinedTradeLimit(long userDefinedTradeLimit);

void setUserHasRaisedTradeLimit(boolean userHasRaisedTradeLimit);
}
}
11 changes: 9 additions & 2 deletions core/src/main/java/bisq/core/user/PreferencesPayload.java
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ public final class PreferencesPayload implements PersistableEnvelope {
private boolean useFullModeDaoMonitor;
private boolean useBitcoinUrisInQrCodes = true;

private long userDefinedTradeLimit = Preferences.INITIAL_TRADE_LIMIT;
private boolean userHasRaisedTradeLimit = false;

///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -211,7 +214,9 @@ public Message toProtoMessage() {
.setDenyApiTaker(denyApiTaker)
.setNotifyOnPreRelease(notifyOnPreRelease)
.setUseFullModeDaoMonitor(useFullModeDaoMonitor)
.setUseBitcoinUrisInQrCodes(useBitcoinUrisInQrCodes);
.setUseBitcoinUrisInQrCodes(useBitcoinUrisInQrCodes)
.setUserDefinedTradeLimit(userDefinedTradeLimit)
.setUserHasRaisedTradeLimit(userHasRaisedTradeLimit);

Optional.ofNullable(backupDirectory).ifPresent(builder::setBackupDirectory);
Optional.ofNullable(preferredTradeCurrency).ifPresent(e -> builder.setPreferredTradeCurrency((protobuf.TradeCurrency) e.toProtoMessage()));
Expand Down Expand Up @@ -316,7 +321,9 @@ public static PreferencesPayload fromProto(protobuf.PreferencesPayload proto, Co
proto.getDenyApiTaker(),
proto.getNotifyOnPreRelease(),
proto.getUseFullModeDaoMonitor(),
proto.getUseBitcoinUrisInQrCodes()
proto.getUseBitcoinUrisInQrCodes(),
proto.getUserHasRaisedTradeLimit() ? proto.getUserDefinedTradeLimit() : Preferences.INITIAL_TRADE_LIMIT,
proto.getUserHasRaisedTradeLimit()
);
}
}
13 changes: 13 additions & 0 deletions core/src/main/resources/i18n/displayStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,19 @@ setting.preferences.autoConfirmEnabled=Enabled
setting.preferences.autoConfirmRequiredConfirmations=Required confirmations
setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (BTC)
setting.preferences.autoConfirmServiceAddresses=Monero Explorer URLs (uses Tor, except for localhost, LAN IP addresses, and *.local hostnames)
setting.preferences.tradeLimits=Trade Limits
setting.preferences.tradeLimitsEnabled=Increase Trade Limits
setting.preferences.tradeLimitMax=Max. trade amount (BTC)
setting.preferences.tradeLimitBlurb=Trading limits are set to reduce risk of costly disputes and losing funds for new \
users. Raise trading limits at your own risk. Every trader has their own pace, but it's recommended to complete at \
least 5 trades before raising trade limits.\n\n\
By raising trading limits you acknowledge to be familiar with the basic use of Bisq, like backing up your data \
[HYPERLINK:https://bisq.wiki/Backing_up_application_data], \
trading rules [HYPERLINK:https://bisq.wiki/Trading_rules], dispute resolution \
[HYPERLINK:https://bisq.wiki/Dispute_resolution], penalties [HYPERLINK:https://bisq.wiki/Table_of_penalties] or find \
support [HYPERLINK:https://bisq.wiki/User_support].\n\n\
Account signing limits [HYPERLINK:https://bisq.wiki/Account_signing] are still applied to buy BTC with most National \
Account payment methods [HYPERLINK:https://bisq.wiki/Payment_methods], to reduce chargeback risk.
setting.preferences.deviationToLarge=Values higher than {0}% are not allowed.
setting.preferences.txFee=BSQ Withdrawal transaction fee (satoshis/vbyte)
setting.preferences.useCustomValue=Use custom value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import bisq.desktop.common.view.FxmlView;
import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.components.AutoTooltipLabel;
import bisq.desktop.components.AutoTooltipSlideToggleButton;
import bisq.desktop.components.InputTextField;
import bisq.desktop.components.PasswordTextField;
import bisq.desktop.components.TitledGroupBg;
Expand All @@ -46,6 +47,7 @@
import bisq.core.locale.Res;
import bisq.core.locale.TradeCurrency;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.TradeLimits;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.provider.fee.FeeService;
import bisq.core.user.DontShowAgainLookup;
Expand Down Expand Up @@ -84,12 +86,14 @@
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;

import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.geometry.VPos;

import javafx.beans.value.ChangeListener;
Expand All @@ -112,6 +116,7 @@

import static bisq.desktop.util.FormBuilder.*;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

@FxmlView
public class PreferencesView extends ActivatableViewAndModel<GridPane, PreferencesViewModel> {
Expand All @@ -124,12 +129,13 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc

private ToggleButton showOwnOffersInOfferBook, useAnimations, useDarkMode, sortMarketCurrenciesNumerically,
avoidStandbyMode, useCustomFee, autoConfirmXmrToggle, hideNonAccountPaymentMethodsToggle, denyApiTakerToggle,
notifyOnPreReleaseToggle, isDaoFullNodeToggleButton, fullModeDaoMonitorToggleButton, useBitcoinUrisToggle;
notifyOnPreReleaseToggle, isDaoFullNodeToggleButton,
fullModeDaoMonitorToggleButton, useBitcoinUrisToggle, tradeLimitToggle;
private int gridRow = 0;
private int displayCurrenciesGridRowIndex = 0;
private InputTextField transactionFeeInputTextField, ignoreTradersListInputTextField, ignoreDustThresholdInputTextField,
autoConfRequiredConfirmationsTf, autoConfServiceAddressTf, autoConfTradeLimitTf, clearDataAfterDaysInputTextField,
rpcUserTextField, blockNotifyPortTextField;
rpcUserTextField, blockNotifyPortTextField, tradeLimitTf;
private PasswordTextField rpcPwTextField;
private TitledGroupBg daoOptionsTitledGroupBg;

Expand Down Expand Up @@ -158,7 +164,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
private InputTextField deviationInputTextField, bsqAverageTrimThresholdTextField;
private ChangeListener<String> deviationListener, bsqAverageTrimThresholdListener, ignoreTradersListListener, ignoreDustThresholdListener,
rpcUserListener, rpcPwListener, blockNotifyPortListener, clearDataAfterDaysListener,
autoConfTradeLimitListener, autoConfServiceAddressListener;
autoConfTradeLimitListener, autoConfServiceAddressListener, userDefinedTradeLimitListener;
private ChangeListener<Boolean> deviationFocusedListener, bsqAverageTrimThresholdFocusedListener;
private ChangeListener<Boolean> useCustomFeeCheckboxListener;
private ChangeListener<Number> transactionFeeChangeListener;
Expand Down Expand Up @@ -217,6 +223,7 @@ public void initialize() {
initializeDaoOptions();
initializeSeparator();
initializeAutoConfirmOptions();
initializeTradeLimitOptions();
initializeDisplayCurrencies();
}

Expand Down Expand Up @@ -248,6 +255,7 @@ protected void activate() {
activateDisplayCurrencies();
activateDisplayPreferences();
activateAutoConfirmPreferences();
activateTradeLimitPreferences();
activateDaoPreferences();
}

Expand All @@ -257,6 +265,7 @@ protected void deactivate() {
deactivateDisplayCurrencies();
deactivateDisplayPreferences();
deactivateAutoConfirmPreferences();
deactivateTradeLimitPreferences();
deactivateDaoPreferences();
}

Expand Down Expand Up @@ -440,13 +449,13 @@ private void initializeSeparator() {
private void initializeDisplayCurrencies() {

TitledGroupBg titledGroupBg = addTitledGroupBg(root, displayCurrenciesGridRowIndex, 8,
Res.get("setting.preferences.currenciesInList"), Layout.GROUP_DISTANCE);
Res.get("setting.preferences.currenciesInList"));
GridPane.setColumnIndex(titledGroupBg, 2);
GridPane.setColumnSpan(titledGroupBg, 2);

preferredTradeCurrencyComboBox = addComboBox(root, displayCurrenciesGridRowIndex++,
Res.get("setting.preferences.prefCurrency"),
Layout.FIRST_ROW_AND_GROUP_DISTANCE);
Layout.FIRST_ROW_DISTANCE);
GridPane.setColumnIndex(preferredTradeCurrencyComboBox, 2);

preferredTradeCurrencyComboBox.setConverter(new StringConverter<>() {
Expand Down Expand Up @@ -841,6 +850,39 @@ private void initializeAutoConfirmOptions() {
autoConfirmGridPane.setDisable(filterManager.getFilter() != null && filterManager.getFilter().isDisableAutoConf());
}

private void initializeTradeLimitOptions() {
GridPane tradeLimitGridPane = new GridPane();
GridPane.setHgrow(tradeLimitGridPane, Priority.ALWAYS);
root.add(tradeLimitGridPane, 2, displayCurrenciesGridRowIndex, 2, 4);
addTitledGroupBg(tradeLimitGridPane, 0, 4, Res.get("setting.preferences.tradeLimits"), 0);

tradeLimitToggle = new AutoTooltipSlideToggleButton();
tradeLimitToggle.setText(Res.get("setting.preferences.tradeLimitsEnabled"));
tradeLimitTf = new InputTextField();
tradeLimitTf.setLabelFloat(true);
tradeLimitTf.setPromptText(Res.get("setting.preferences.tradeLimitMax"));
tradeLimitTf.setPrefWidth(200);

HBox hBox = new HBox(12, tradeLimitToggle, tradeLimitTf);
hBox.setAlignment(Pos.CENTER_LEFT);
tradeLimitGridPane.add(hBox, 0, 0);
GridPane.setMargin(hBox, new Insets(Layout.FIRST_ROW_DISTANCE, 0, 0, 0));

BtcValidator btcValidator = new BtcValidator(formatter);
btcValidator.setMinValue(Coin.valueOf(Preferences.INITIAL_TRADE_LIMIT));
TradeLimits tradeLimits = TradeLimits.getINSTANCE();
checkNotNull(tradeLimits, "tradeLimits must not be null");
btcValidator.setMaxValue(tradeLimits.getMaxTradeLimit());
tradeLimitTf.setValidator(btcValidator);
displayCurrenciesGridRowIndex++;

userDefinedTradeLimitListener = (observable, oldValue, newValue) -> {
if (!newValue.equals(oldValue) && tradeLimitTf.getValidator().validate(newValue).isValid) {
Coin amountAsCoin = ParsingUtils.parseToCoin(newValue, formatter);
preferences.setUserDefinedTradeLimit(amountAsCoin.value);
}
};
}

///////////////////////////////////////////////////////////////////////////////////////////
// Activate
Expand Down Expand Up @@ -1152,6 +1194,27 @@ private void activateAutoConfirmPreferences() {
});
}

private void activateTradeLimitPreferences() {
tradeLimitToggle.setSelected(preferences.isUserHasRaisedTradeLimit());
tradeLimitTf.setEditable(preferences.isUserHasRaisedTradeLimit());
tradeLimitTf.setText(formatter.formatCoin(Coin.valueOf(preferences.getUserDefinedTradeLimit())));
tradeLimitTf.textProperty().addListener(userDefinedTradeLimitListener);

tradeLimitToggle.setOnAction(e -> {
if (tradeLimitToggle.isSelected()) {
new Popup()
.information(Res.get("setting.preferences.tradeLimitBlurb"))
.width(800)
.show();
} else {
// no increased limits, resetting back to default
tradeLimitTf.setText(Coin.valueOf(Preferences.INITIAL_TRADE_LIMIT).toPlainString());
}
preferences.setUserHasRaisedTradeLimit(tradeLimitToggle.isSelected());
tradeLimitTf.setEditable(tradeLimitToggle.isSelected());
});
}

private void updateDaoFields() {
boolean isDaoFullNode = isDaoFullNodeToggleButton.isSelected();
GridPane.setRowSpan(daoOptionsTitledGroupBg, isDaoFullNode ? 8 : 5);
Expand Down Expand Up @@ -1238,4 +1301,8 @@ private void deactivateAutoConfirmPreferences() {
filterManager.filterProperty().removeListener(filterChangeListener);
});
}

private void deactivateTradeLimitPreferences() {
tradeLimitTf.textProperty().removeListener(userDefinedTradeLimitListener);
}
}
2 changes: 2 additions & 0 deletions proto/src/main/proto/pb.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1957,6 +1957,8 @@ message PreferencesPayload {
string buy_screen_crypto_currency_code = 64;
string sell_screen_crypto_currency_code = 65;
bool use_bitcoin_uris_in_qr_codes = 66;
int64 user_defined_trade_limit = 67;
bool user_has_raised_trade_limit = 68;
}

message AutoConfirmSettings {
Expand Down

0 comments on commit c796531

Please sign in to comment.