mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Clear account payload info & chats from closed trades & disputes.
This commit is contained in:
parent
44b02b3cbb
commit
57821b7474
@ -100,7 +100,7 @@ public final class Dispute implements NetworkPayload, PersistablePayload {
|
||||
private final PubKeyRing traderPubKeyRing;
|
||||
private final long tradeDate;
|
||||
private final long tradePeriodEnd;
|
||||
private final Contract contract;
|
||||
private Contract contract;
|
||||
@Nullable
|
||||
private final byte[] contractHash;
|
||||
@Nullable
|
||||
@ -111,7 +111,7 @@ public final class Dispute implements NetworkPayload, PersistablePayload {
|
||||
private final String depositTxId;
|
||||
@Nullable
|
||||
private final String payoutTxId;
|
||||
private final String contractAsJson;
|
||||
private String contractAsJson;
|
||||
@Nullable
|
||||
private final String makerContractSignature;
|
||||
@Nullable
|
||||
@ -351,6 +351,31 @@ public final class Dispute implements NetworkPayload, PersistablePayload {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeAllChatMessages() {
|
||||
if (chatMessages.size() > 0) {
|
||||
chatMessages.clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void maybeClearSensitiveData() {
|
||||
String change = "";
|
||||
if (contract.maybeClearSensitiveData()) {
|
||||
change += "contract;";
|
||||
}
|
||||
String edited = contract.sanitizeContractAsJson(contractAsJson);
|
||||
if (!edited.equals(contractAsJson)) {
|
||||
contractAsJson = edited;
|
||||
change += "contractAsJson;";
|
||||
}
|
||||
if (removeAllChatMessages()) {
|
||||
change += "chat messages;";
|
||||
}
|
||||
if (change.length() > 0) {
|
||||
log.info("cleared sensitive data from {} of dispute for trade {}", change, Utilities.getShortId(getTradeId()));
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Setters
|
||||
|
@ -66,6 +66,8 @@ import javafx.collections.ObservableList;
|
||||
|
||||
import java.security.KeyPair;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@ -282,6 +284,8 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||
log.error(disputeReplayException.toString());
|
||||
validationExceptions.add(disputeReplayException);
|
||||
});
|
||||
|
||||
maybeClearSensitiveData();
|
||||
}
|
||||
|
||||
public boolean isTrader(Dispute dispute) {
|
||||
@ -298,6 +302,15 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup
|
||||
return disputeList.stream().filter(e -> e.getTradeId().equals(tradeId)).findAny();
|
||||
}
|
||||
|
||||
public void maybeClearSensitiveData() {
|
||||
log.info("{} checking closed disputes eligibility for having sensitive data cleared", super.getClass().getSimpleName());
|
||||
Instant safeDate = closedTradableManager.getSafeDateForSensitiveDataClearing();
|
||||
getDisputeList().getList().stream()
|
||||
.filter(e -> e.isClosed())
|
||||
.filter(e -> e.getTradeDate().toInstant().isBefore(safeDate))
|
||||
.forEach(Dispute::maybeClearSensitiveData);
|
||||
requestPersistence();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Message handler
|
||||
|
@ -338,6 +338,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL
|
||||
sendAckMessage(chatMessage, dispute.getAgentPubKeyRing(), success, errorMessage);
|
||||
}
|
||||
|
||||
maybeClearSensitiveData();
|
||||
requestPersistence();
|
||||
}
|
||||
|
||||
|
@ -223,6 +223,7 @@ public final class MediationManager extends DisputeManager<MediationDisputeList>
|
||||
}
|
||||
sendAckMessage(chatMessage, dispute.getAgentPubKeyRing(), true, null);
|
||||
|
||||
maybeClearSensitiveData();
|
||||
requestPersistence();
|
||||
}
|
||||
|
||||
|
@ -224,6 +224,7 @@ public final class RefundManager extends DisputeManager<RefundDisputeList> {
|
||||
openOfferOptional.ifPresent(openOffer -> openOfferManager.closeOpenOffer(openOffer.getOffer()));
|
||||
}
|
||||
|
||||
maybeClearSensitiveData();
|
||||
requestPersistence();
|
||||
}
|
||||
|
||||
|
@ -49,9 +49,12 @@ import com.google.common.collect.ImmutableList;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -120,10 +123,12 @@ public class ClosedTradableManager implements PersistedDataHost {
|
||||
|
||||
public void onAllServicesInitialized() {
|
||||
cleanupMailboxMessagesService.handleTrades(getClosedTrades());
|
||||
maybeClearSensitiveData();
|
||||
}
|
||||
|
||||
public void add(Tradable tradable) {
|
||||
if (closedTradables.add(tradable)) {
|
||||
maybeClearSensitiveData();
|
||||
requestPersistence();
|
||||
}
|
||||
}
|
||||
@ -153,6 +158,29 @@ public class ClosedTradableManager implements PersistedDataHost {
|
||||
return closedTradables.stream().filter(e -> e.getId().equals(id)).findFirst();
|
||||
}
|
||||
|
||||
public void maybeClearSensitiveData() {
|
||||
log.info("checking closed trades eligibility for having sensitive data cleared");
|
||||
closedTradables.stream()
|
||||
.filter(e -> e instanceof Trade)
|
||||
.map(e -> (Trade) e)
|
||||
.filter(e -> canTradeHaveSensitiveDataCleared(e.getId()))
|
||||
.forEach(Trade::maybeClearSensitiveData);
|
||||
requestPersistence();
|
||||
}
|
||||
|
||||
public boolean canTradeHaveSensitiveDataCleared(String tradeId) {
|
||||
Instant safeDate = getSafeDateForSensitiveDataClearing();
|
||||
return closedTradables.stream()
|
||||
.filter(e -> e.getId().equals(tradeId))
|
||||
.filter(e -> e.getDate().toInstant().isBefore(safeDate))
|
||||
.count() > 0;
|
||||
}
|
||||
|
||||
public Instant getSafeDateForSensitiveDataClearing() {
|
||||
return Instant.ofEpochSecond(Instant.now().getEpochSecond()
|
||||
- TimeUnit.DAYS.toSeconds(preferences.getClearDataAfterDays()));
|
||||
}
|
||||
|
||||
public Stream<Trade> getTradesStreamWithFundsLockedIn() {
|
||||
return getClosedTrades().stream()
|
||||
.filter(Trade::isFundsLockedIn);
|
||||
|
@ -350,6 +350,30 @@ public final class Contract implements NetworkPayload {
|
||||
return isBuyerMakerAndSellerTaker() == isMyRoleBuyer(myPubKeyRing);
|
||||
}
|
||||
|
||||
public boolean maybeClearSensitiveData() {
|
||||
boolean changed = false;
|
||||
if (makerPaymentAccountPayload != null) {
|
||||
makerPaymentAccountPayload = null;
|
||||
changed = true;
|
||||
}
|
||||
if (takerPaymentAccountPayload != null) {
|
||||
takerPaymentAccountPayload = null;
|
||||
changed = true;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
// edits a contract json string, removing the payment account payloads
|
||||
public static String sanitizeContractAsJson(String contractAsJson) {
|
||||
return contractAsJson
|
||||
.replaceAll(
|
||||
"\"takerPaymentAccountPayload\": \\{[^}]*}",
|
||||
"\"takerPaymentAccountPayload\": null")
|
||||
.replaceAll(
|
||||
"\"makerPaymentAccountPayload\": \\{[^}]*}",
|
||||
"\"makerPaymentAccountPayload\": null");
|
||||
}
|
||||
|
||||
public void printDiff(@Nullable String peersContractAsJson) {
|
||||
String json = JsonUtil.objectToJson(this);
|
||||
String diff = StringUtils.difference(json, peersContractAsJson);
|
||||
|
@ -689,6 +689,14 @@ public abstract class Trade extends TradeModel {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeAllChatMessages() {
|
||||
if (chatMessages.size() > 0) {
|
||||
chatMessages.clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean mediationResultAppliedPenaltyToSeller() {
|
||||
// If mediated payout is same or more then normal payout we enable otherwise a penalty was applied
|
||||
// by mediators and we keep the confirm disabled to avoid that the seller can complete the trade
|
||||
@ -698,6 +706,26 @@ public abstract class Trade extends TradeModel {
|
||||
return payoutAmountFromMediation < normalPayoutAmount;
|
||||
}
|
||||
|
||||
public void maybeClearSensitiveData() {
|
||||
String change = "";
|
||||
if (contract != null && contract.maybeClearSensitiveData()) {
|
||||
change += "contract;";
|
||||
}
|
||||
if (contractAsJson != null) {
|
||||
String edited = contract.sanitizeContractAsJson(contractAsJson);
|
||||
if (!edited.equals(contractAsJson)) {
|
||||
contractAsJson = edited;
|
||||
change += "contractAsJson;";
|
||||
}
|
||||
}
|
||||
if (removeAllChatMessages()) {
|
||||
change += "chat messages;";
|
||||
}
|
||||
if (change.length() > 0) {
|
||||
log.info("cleared sensitive data from {} of trade {}", change, getShortId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TradeModel implementation
|
||||
|
@ -145,7 +145,8 @@ 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 = 20; // used when user has agreed to settings notification
|
||||
|
||||
// payload is initialized so the default values are available for Property initialization.
|
||||
@Setter
|
||||
@ -355,6 +356,10 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
||||
setIgnoreDustThreshold(600);
|
||||
}
|
||||
|
||||
if (prefPayload.getClearDataAfterDays() < 1) {
|
||||
setClearDataAfterDays(Preferences.CLEAR_DATA_AFTER_DAYS_INITIAL);
|
||||
}
|
||||
|
||||
// For users from old versions the 4 flags a false but we want to have it true by default
|
||||
// PhoneKeyAndToken is also null so we can use that to enable the flags
|
||||
if (prefPayload.getPhoneKeyAndToken() == null) {
|
||||
@ -785,6 +790,11 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid
|
||||
requestPersistence();
|
||||
}
|
||||
|
||||
public void setClearDataAfterDays(int value) {
|
||||
prefPayload.setClearDataAfterDays(value);
|
||||
requestPersistence();
|
||||
}
|
||||
|
||||
public void setShowOffersMatchingMyAccounts(boolean value) {
|
||||
prefPayload.setShowOffersMatchingMyAccounts(value);
|
||||
requestPersistence();
|
||||
|
@ -121,6 +121,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
||||
private String takeOfferSelectedPaymentAccountId;
|
||||
private double buyerSecurityDepositAsPercent = getDefaultBuyerSecurityDepositAsPercent();
|
||||
private int ignoreDustThreshold = 600;
|
||||
private int clearDataAfterDays = Preferences.CLEAR_DATA_AFTER_DAYS_INITIAL;
|
||||
private double buyerSecurityDepositAsPercentForCrypto = getDefaultBuyerSecurityDepositAsPercent();
|
||||
private int blockNotifyPort;
|
||||
private boolean tacAcceptedV120;
|
||||
@ -192,6 +193,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
||||
.setIsDaoFullNode(isDaoFullNode)
|
||||
.setBuyerSecurityDepositAsPercent(buyerSecurityDepositAsPercent)
|
||||
.setIgnoreDustThreshold(ignoreDustThreshold)
|
||||
.setClearDataAfterDays(clearDataAfterDays)
|
||||
.setBuyerSecurityDepositAsPercentForCrypto(buyerSecurityDepositAsPercentForCrypto)
|
||||
.setBlockNotifyPort(blockNotifyPort)
|
||||
.setTacAcceptedV120(tacAcceptedV120)
|
||||
@ -290,6 +292,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
|
||||
proto.getTakeOfferSelectedPaymentAccountId().isEmpty() ? null : proto.getTakeOfferSelectedPaymentAccountId(),
|
||||
proto.getBuyerSecurityDepositAsPercent(),
|
||||
proto.getIgnoreDustThreshold(),
|
||||
proto.getClearDataAfterDays(),
|
||||
proto.getBuyerSecurityDepositAsPercentForCrypto(),
|
||||
proto.getBlockNotifyPort(),
|
||||
proto.getTacAcceptedV120(),
|
||||
|
@ -1324,6 +1324,7 @@ setting.preferences.txFeeMin=Transaction fee must be at least {0} satoshis/vbyte
|
||||
setting.preferences.txFeeTooLarge=Your input is above any reasonable value (>5000 satoshis/vbyte). Transaction fee is usually in the range of 50-400 satoshis/vbyte.
|
||||
setting.preferences.ignorePeers=Ignored peers [onion address:port]
|
||||
setting.preferences.ignoreDustThreshold=Min. non-dust output value
|
||||
setting.preferences.clearDataAfterDays=Clear sensitive data after (days)
|
||||
setting.preferences.currenciesInList=Currencies in market price feed list
|
||||
setting.preferences.prefCurrency=Preferred currency
|
||||
setting.preferences.displayFiat=Display national currencies
|
||||
@ -1386,6 +1387,15 @@ settings.preferences.editCustomExplorer.name=Name
|
||||
settings.preferences.editCustomExplorer.txUrl=Transaction URL
|
||||
settings.preferences.editCustomExplorer.addressUrl=Address URL
|
||||
|
||||
setting.info.headline=New data-privacy feature
|
||||
settings.preferences.sensitiveDataRemoval.msg=To protect the privacy of yourself and other traders, Bisq intends to \
|
||||
remove payment account details from old trades. This is particularly important for fiat trades which may include bank \
|
||||
account details. Read more about this at [HYPERLINK:https://bisq.wiki/Data_Privacy].\n\n\
|
||||
The threshold for data removal can be configured on this screen via the field "Clear sensitive data after (days)". \
|
||||
It is recommended to set it as low as possible, for example 20 days. That means trades from more than 20 \
|
||||
days ago will have payment account details cleared, as long as they are finished. Finished trades are ones which \
|
||||
are found in the Portfolio / History tab.
|
||||
|
||||
settings.net.btcHeader=Bitcoin network
|
||||
settings.net.p2pHeader=Bisq network
|
||||
settings.net.onionAddressLabel=My onion address
|
||||
|
@ -58,5 +58,6 @@ public class SettingsPresentation {
|
||||
}
|
||||
|
||||
public void setup() {
|
||||
showNotification.set(preferences.showAgain(SETTINGS_NEWS));
|
||||
}
|
||||
}
|
||||
|
@ -24,11 +24,14 @@ import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.common.view.View;
|
||||
import bisq.desktop.common.view.ViewLoader;
|
||||
import bisq.desktop.main.MainView;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.presentation.SettingsPresentation;
|
||||
import bisq.desktop.main.settings.about.AboutView;
|
||||
import bisq.desktop.main.settings.network.NetworkSettingsView;
|
||||
import bisq.desktop.main.settings.preferences.PreferencesView;
|
||||
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.user.DontShowAgainLookup;
|
||||
import bisq.core.user.Preferences;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -85,6 +88,9 @@ public class SettingsView extends ActivatableView<TabPane, Void> {
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
// Hide new badge if user saw this section
|
||||
preferences.dontShowAgain(SettingsPresentation.SETTINGS_NEWS, true);
|
||||
|
||||
root.getSelectionModel().selectedItemProperty().addListener(tabChangeListener);
|
||||
navigation.addListener(navigationListener);
|
||||
|
||||
|
@ -127,7 +127,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
private int gridRow = 0;
|
||||
private int displayCurrenciesGridRowIndex = 0;
|
||||
private InputTextField transactionFeeInputTextField, ignoreTradersListInputTextField, ignoreDustThresholdInputTextField,
|
||||
autoConfRequiredConfirmationsTf, autoConfServiceAddressTf, autoConfTradeLimitTf,
|
||||
autoConfRequiredConfirmationsTf, autoConfServiceAddressTf, autoConfTradeLimitTf, clearDataAfterDaysInputTextField,
|
||||
rpcUserTextField, blockNotifyPortTextField;
|
||||
private PasswordTextField rpcPwTextField;
|
||||
private TitledGroupBg daoOptionsTitledGroupBg;
|
||||
@ -156,7 +156,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
private ObservableList<TradeCurrency> tradeCurrencies;
|
||||
private InputTextField deviationInputTextField, bsqAverageTrimThresholdTextField;
|
||||
private ChangeListener<String> deviationListener, bsqAverageTrimThresholdListener, ignoreTradersListListener, ignoreDustThresholdListener,
|
||||
rpcUserListener, rpcPwListener, blockNotifyPortListener,
|
||||
rpcUserListener, rpcPwListener, blockNotifyPortListener, clearDataAfterDaysListener,
|
||||
autoConfTradeLimitListener, autoConfServiceAddressListener;
|
||||
private ChangeListener<Boolean> deviationFocusedListener, bsqAverageTrimThresholdFocusedListener;
|
||||
private ChangeListener<Boolean> useCustomFeeCheckboxListener;
|
||||
@ -225,6 +225,22 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
String key = "sensitiveDataRemovalInfo";
|
||||
if (DontShowAgainLookup.showAgain(key)) {
|
||||
new Popup()
|
||||
.headLine(Res.get("setting.info.headline"))
|
||||
.backgroundInfo(Res.get("settings.preferences.sensitiveDataRemoval.msg"))
|
||||
.actionButtonText(Res.get("shared.iUnderstand"))
|
||||
.onAction(() -> {
|
||||
DontShowAgainLookup.dontShowAgain(key, true);
|
||||
// user has acknowledged, enable the feature with a reasonable default value
|
||||
preferences.setClearDataAfterDays(preferences.CLEAR_DATA_AFTER_DAYS_DEFAULT);
|
||||
clearDataAfterDaysInputTextField.setText(String.valueOf(preferences.getClearDataAfterDays()));
|
||||
})
|
||||
.closeButtonText(Res.get("shared.cancel"))
|
||||
.show();
|
||||
}
|
||||
|
||||
// We want to have it updated in case an asset got removed
|
||||
allCryptoCurrencies = FXCollections.observableArrayList(CurrencyUtil.getActiveSortedCryptoCurrencies(assetService, filterManager));
|
||||
allCryptoCurrencies.removeAll(cryptoCurrencies);
|
||||
@ -250,7 +266,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void initializeGeneralOptions() {
|
||||
int titledGroupBgRowSpan = displayStandbyModeFeature ? 9 : 8;
|
||||
int titledGroupBgRowSpan = displayStandbyModeFeature ? 10 : 9;
|
||||
TitledGroupBg titledGroupBg = addTitledGroupBg(root, gridRow, titledGroupBgRowSpan, Res.get("setting.preferences.general"));
|
||||
GridPane.setColumnSpan(titledGroupBg, 1);
|
||||
|
||||
@ -382,6 +398,22 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
}
|
||||
};
|
||||
|
||||
// clearDataAfterDays
|
||||
clearDataAfterDaysInputTextField = addInputTextField(root, ++gridRow, Res.get("setting.preferences.clearDataAfterDays"));
|
||||
IntegerValidator clearDataAfterDaysValidator = new IntegerValidator();
|
||||
clearDataAfterDaysValidator.setMinValue(1);
|
||||
clearDataAfterDaysValidator.setMaxValue(Preferences.CLEAR_DATA_AFTER_DAYS_INITIAL);
|
||||
clearDataAfterDaysInputTextField.setValidator(clearDataAfterDaysValidator);
|
||||
clearDataAfterDaysListener = (observable, oldValue, newValue) -> {
|
||||
try {
|
||||
int value = Integer.parseInt(newValue);
|
||||
if (!newValue.equals(oldValue)) {
|
||||
preferences.setClearDataAfterDays(value);
|
||||
}
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
};
|
||||
|
||||
if (displayStandbyModeFeature) {
|
||||
// AvoidStandbyModeService feature works only on OSX & Windows
|
||||
avoidStandbyMode = addSlideToggleButton(root, ++gridRow,
|
||||
@ -825,6 +857,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
/* referralIdService.getOptionalReferralId().ifPresent(referralId -> referralIdInputTextField.setText(referralId));
|
||||
referralIdInputTextField.setPromptText(Res.get("setting.preferences.refererId.prompt"));*/
|
||||
ignoreDustThresholdInputTextField.setText(String.valueOf(preferences.getIgnoreDustThreshold()));
|
||||
clearDataAfterDaysInputTextField.setText(String.valueOf(preferences.getClearDataAfterDays()));
|
||||
userLanguageComboBox.setItems(languageCodes);
|
||||
userLanguageComboBox.getSelectionModel().select(preferences.getUserLanguage());
|
||||
userLanguageComboBox.setConverter(new StringConverter<>() {
|
||||
@ -889,6 +922,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
useCustomFee.selectedProperty().addListener(useCustomFeeCheckboxListener);
|
||||
//referralIdInputTextField.textProperty().addListener(referralIdListener);
|
||||
ignoreDustThresholdInputTextField.textProperty().addListener(ignoreDustThresholdListener);
|
||||
clearDataAfterDaysInputTextField.textProperty().addListener(clearDataAfterDaysListener);
|
||||
}
|
||||
|
||||
private Coin getTxFeeForWithdrawalPerVbyte() {
|
||||
@ -1165,6 +1199,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc
|
||||
useCustomFee.selectedProperty().removeListener(useCustomFeeCheckboxListener);
|
||||
//referralIdInputTextField.textProperty().removeListener(referralIdListener);
|
||||
ignoreDustThresholdInputTextField.textProperty().removeListener(ignoreDustThresholdListener);
|
||||
clearDataAfterDaysInputTextField.textProperty().removeListener(clearDataAfterDaysListener);
|
||||
}
|
||||
|
||||
private void deactivateDisplayCurrencies() {
|
||||
|
@ -1999,6 +1999,7 @@ message PreferencesPayload {
|
||||
bool deny_api_taker = 60;
|
||||
bool notify_on_pre_release = 61;
|
||||
bool use_full_mode_dao_monitor = 62;
|
||||
int32 clear_data_after_days = 63;
|
||||
}
|
||||
|
||||
message AutoConfirmSettings {
|
||||
|
Loading…
Reference in New Issue
Block a user