Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use percentage based value for security deposits #2498

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion common/src/main/proto/pb.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1278,7 +1278,7 @@ message PreferencesPayload {
string bitcoin_nodes = 27;
repeated string ignore_traders_list = 28;
string directory_chooser_path = 29;
int64 buyer_security_deposit_as_long = 30;
int64 buyer_security_deposit_as_long = 30; // Deprectated: Superseded by buyerSecurityDepositAsPercent
bool use_animations = 31;
PaymentAccount selectedPayment_account_for_createOffer = 32;
bool pay_fee_in_Btc = 33;
Expand All @@ -1298,6 +1298,7 @@ message PreferencesPayload {
string rpc_user = 47;
string rpc_pw = 48;
string take_offer_selected_payment_account_id = 49;
double buyer_security_deposit_as_percent = 50;
}

///////////////////////////////////////////////////////////////////////////////////////////
Expand Down
36 changes: 20 additions & 16 deletions core/src/main/java/bisq/core/btc/wallet/Restrictions.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@

public class Restrictions {
private static Coin MIN_TRADE_AMOUNT;
private static Coin MAX_BUYER_SECURITY_DEPOSIT;
private static Coin MIN_BUYER_SECURITY_DEPOSIT;
private static Coin DEFAULT_BUYER_SECURITY_DEPOSIT;
// For the seller we use a fixed one as there is no way the seller can cancel the trade
// To make it editable would just increase complexity.
private static Coin SELLER_SECURITY_DEPOSIT;
Expand All @@ -48,32 +46,38 @@ public static boolean isDust(Coin amount) {

public static Coin getMinTradeAmount() {
if (MIN_TRADE_AMOUNT == null)
MIN_TRADE_AMOUNT = Coin.valueOf(10_000); // 2 USD @ 20000 USD/BTC
MIN_TRADE_AMOUNT = Coin.valueOf(10_000); // 0,4 USD @ 4000 USD/BTC
return MIN_TRADE_AMOUNT;
}

// Can be reduced but not increased. Otherwise would break existing offers!
public static Coin getMaxBuyerSecurityDeposit() {
if (MAX_BUYER_SECURITY_DEPOSIT == null)
MAX_BUYER_SECURITY_DEPOSIT = Coin.valueOf(5_000_000); // 1000 USD @ 20000 USD/BTC
return MAX_BUYER_SECURITY_DEPOSIT;
public static double getDefaultBuyerSecurityDepositAsPercent() {
return 0.02; // 2% of trade amount. For a 1 BTC trade it is about 80 USD @ 4000 USD/BTC.
}

public static Coin getMinBuyerSecurityDeposit() {
public static double getMinBuyerSecurityDepositAsPercent() {
return 0.0005; // 0.05% of trade amount. For a 1 BTC trade it is about 2 USD @ 4000 USD/BTC but MIN_BUYER_SECURITY_DEPOSIT would require 0.001 BTC anyway (4 USD)
}

public static double getMaxBuyerSecurityDepositAsPercent() {
return 0.1; // 10% of trade amount. For a 1 BTC trade it is about 400 USD @ 4000 USD/BTC
}

// We use MIN_BUYER_SECURITY_DEPOSIT as well as lower bound in case of small trade amounts.
// So 0.0005 BTC is the min. buyer security deposit even with amount of 0.0001 BTC and 0.05% percentage value.
public static Coin getMinBuyerSecurityDepositAsCoin() {
if (MIN_BUYER_SECURITY_DEPOSIT == null)
MIN_BUYER_SECURITY_DEPOSIT = Coin.valueOf(50_000); // 10 USD @ 20000 USD/BTC
MIN_BUYER_SECURITY_DEPOSIT = Coin.parseCoin("0.001"); // 0.001 BTC about 4 USD @ 4000 USD/BTC
return MIN_BUYER_SECURITY_DEPOSIT;
}

public static Coin getDefaultBuyerSecurityDeposit() {
if (DEFAULT_BUYER_SECURITY_DEPOSIT == null)
DEFAULT_BUYER_SECURITY_DEPOSIT = Coin.valueOf(1_000_000); // 200 EUR @ 20000 USD/BTC
return DEFAULT_BUYER_SECURITY_DEPOSIT;

public static double getSellerSecurityDepositAsPercent() {
return 0.005; // 0.5% of trade amount.
}

public static Coin getSellerSecurityDeposit() {
public static Coin getMinSellerSecurityDepositAsCoin() {
if (SELLER_SECURITY_DEPOSIT == null)
SELLER_SECURITY_DEPOSIT = Coin.valueOf(300_000); // 60 USD @ 20000 USD/BTC
SELLER_SECURITY_DEPOSIT = Coin.parseCoin("0.005"); // 0.005 BTC about 20 USD @ 4000 USD/BTC
return SELLER_SECURITY_DEPOSIT;
}
}
14 changes: 7 additions & 7 deletions core/src/main/java/bisq/core/offer/OfferUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -347,18 +347,18 @@ public static Map<String, String> getExtraDataMap(AccountAgeWitnessService accou

public static void validateOfferData(FilterManager filterManager,
P2PService p2PService,
Coin buyerSecurityDepositAsCoin,
double buyerSecurityDeposit,
PaymentAccount paymentAccount,
String currencyCode,
Coin makerFeeAsCoin) {
checkNotNull(makerFeeAsCoin, "makerFee must not be null");
checkNotNull(p2PService.getAddress(), "Address must not be null");
checkArgument(buyerSecurityDepositAsCoin.compareTo(Restrictions.getMaxBuyerSecurityDeposit()) <= 0,
"securityDeposit must be not exceed " +
Restrictions.getMaxBuyerSecurityDeposit().toFriendlyString());
checkArgument(buyerSecurityDepositAsCoin.compareTo(Restrictions.getMinBuyerSecurityDeposit()) >= 0,
"securityDeposit must be not be less than " +
Restrictions.getMinBuyerSecurityDeposit().toFriendlyString());
checkArgument(buyerSecurityDeposit <= Restrictions.getMaxBuyerSecurityDepositAsPercent(),
"securityDeposit must not exceed " +
Restrictions.getMaxBuyerSecurityDepositAsPercent());
checkArgument(buyerSecurityDeposit >= Restrictions.getMinBuyerSecurityDepositAsPercent(),
"securityDeposit must not be less than " +
Restrictions.getMinBuyerSecurityDepositAsPercent());
checkArgument(!filterManager.isCurrencyBanned(currencyCode),
Res.get("offerbook.warning.currencyBanned"));
checkArgument(!filterManager.isPaymentMethodBanned(paymentAccount.getPaymentMethod()),
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/bisq/core/trade/Trade.java
Original file line number Diff line number Diff line change
Expand Up @@ -619,9 +619,9 @@ public void onComplete() {
///////////////////////////////////////////////////////////////////////////////////////////

public void setState(State state) {
log.info("Set new state at {} (id={}): {}", this.getClass().getSimpleName(), getShortId(), state);
log.debug("Set new state at {} (id={}): {}", this.getClass().getSimpleName(), getShortId(), state);
if (state.getPhase().ordinal() < this.state.getPhase().ordinal()) {
final String message = "We got a state change to a previous phase.\n" +
String message = "We got a state change to a previous phase.\n" +
"Old state is: " + this.state + ". New state is: " + state;
log.warn(message);
}
Expand Down
21 changes: 11 additions & 10 deletions core/src/main/java/bisq/core/user/Preferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@
import bisq.common.storage.Storage;
import bisq.common.util.Utilities;

import org.bitcoinj.core.Coin;

import javax.inject.Inject;
import javax.inject.Named;

Expand Down Expand Up @@ -487,10 +485,10 @@ public void setWithdrawalTxFeeInBytes(long withdrawalTxFeeInBytes) {
withdrawalTxFeeInBytesProperty.set(withdrawalTxFeeInBytes);
}

public void setBuyerSecurityDepositAsLong(long buyerSecurityDepositAsLong) {
prefPayload.setBuyerSecurityDepositAsLong(Math.min(Restrictions.getMaxBuyerSecurityDeposit().value,
Math.max(Restrictions.getMinBuyerSecurityDeposit().value,
buyerSecurityDepositAsLong)));
public void setBuyerSecurityDepositAsPercent(double buyerSecurityDepositAsPercent) {
double max = Restrictions.getMaxBuyerSecurityDepositAsPercent();
double min = Restrictions.getMinBuyerSecurityDepositAsPercent();
prefPayload.setBuyerSecurityDepositAsPercent(Math.min(max, Math.max(min, buyerSecurityDepositAsPercent)));
persist();
}

Expand Down Expand Up @@ -696,8 +694,9 @@ public LongProperty withdrawalTxFeeInBytesProperty() {
return withdrawalTxFeeInBytesProperty;
}

public Coin getBuyerSecurityDepositAsCoin() {
return Coin.valueOf(prefPayload.getBuyerSecurityDepositAsLong());
public double getBuyerSecurityDepositAsPercent() {
double value = prefPayload.getBuyerSecurityDepositAsPercent();
return value == 0 ? Restrictions.getDefaultBuyerSecurityDepositAsPercent() : value;
}

//TODO remove and use isPayFeeInBtc instead
Expand Down Expand Up @@ -775,8 +774,6 @@ private interface ExcludesDelegateMethods {

void setWithdrawalTxFeeInBytes(long withdrawalTxFeeInBytes);

void setBuyerSecurityDepositAsLong(long buyerSecurityDepositAsLong);

void setSelectedPaymentAccountForCreateOffer(@Nullable PaymentAccount paymentAccount);

void setBsqBlockChainExplorer(BlockChainExplorer bsqBlockChainExplorer);
Expand Down Expand Up @@ -832,5 +829,9 @@ private interface ExcludesDelegateMethods {
void setRpcPw(String value);

void setTakeOfferSelectedPaymentAccountId(String value);

void setBuyerSecurityDepositAsPercent(double buyerSecurityDepositAsPercent);

double getBuyerSecurityDepositAsPercent();
}
}
12 changes: 9 additions & 3 deletions core/src/main/java/bisq/core/user/PreferencesPayload.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,10 @@ public final class PreferencesPayload implements PersistableEnvelope {
private String bitcoinNodes = "";
private List<String> ignoreTradersList = new ArrayList<>();
private String directoryChooserPath;
private long buyerSecurityDepositAsLong = Restrictions.getDefaultBuyerSecurityDeposit().value;

@Deprecated // Superseded by buyerSecurityDepositAsPercent
private long buyerSecurityDepositAsLong;

private boolean useAnimations;
@Nullable
private PaymentAccount selectedPaymentAccountForCreateOffer;
Expand Down Expand Up @@ -117,6 +120,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
String rpcPw;
@Nullable
String takeOfferSelectedPaymentAccountId;
private double buyerSecurityDepositAsPercent = Restrictions.getDefaultBuyerSecurityDepositAsPercent();


///////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -172,7 +176,8 @@ public Message toProtoMessage() {
.setUseMarketNotifications(useMarketNotifications)
.setUsePriceNotifications(usePriceNotifications)
.setUseStandbyMode(useStandbyMode)
.setIsDaoFullNode(isDaoFullNode);
.setIsDaoFullNode(isDaoFullNode)
.setBuyerSecurityDepositAsPercent(buyerSecurityDepositAsPercent);
Optional.ofNullable(backupDirectory).ifPresent(builder::setBackupDirectory);
Optional.ofNullable(preferredTradeCurrency).ifPresent(e -> builder.setPreferredTradeCurrency((PB.TradeCurrency) e.toProtoMessage()));
Optional.ofNullable(offerBookChartScreenCurrencyCode).ifPresent(builder::setOfferBookChartScreenCurrencyCode);
Expand Down Expand Up @@ -253,6 +258,7 @@ public static PersistableEnvelope fromProto(PB.PreferencesPayload proto, CorePro
proto.getIsDaoFullNode(),
proto.getRpcUser().isEmpty() ? null : proto.getRpcUser(),
proto.getRpcPw().isEmpty() ? null : proto.getRpcPw(),
proto.getTakeOfferSelectedPaymentAccountId().isEmpty() ? null : proto.getTakeOfferSelectedPaymentAccountId());
proto.getTakeOfferSelectedPaymentAccountId().isEmpty() ? null : proto.getTakeOfferSelectedPaymentAccountId(),
proto.getBuyerSecurityDepositAsPercent());
}
}
20 changes: 20 additions & 0 deletions core/src/main/java/bisq/core/util/CoinUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,24 @@ public static Coin maxCoin(Coin a, Coin b) {
public static double getFeePerByte(Coin miningFee, int txSize) {
return MathUtils.roundDouble(((double) miningFee.value / (double) txSize), 2);
}

/**
* @param value Btc amount to be converted to percent value. E.g. 0.01 BTC is 1% (of 1 BTC)
* @return The percentage value as double (e.g. 1% is 0.01)
*/
public static double getAsPercentPerBtc(Coin value) {
double asDouble = (double) value.value;
double btcAsDouble = (double) Coin.COIN.value;
return MathUtils.roundDouble(asDouble / btcAsDouble, 4);
}

/**
* @param percent The percentage value as double (e.g. 1% is 0.01)
* @param amount The amount as Coin for the percentage calculation
* @return The percentage as Coin (e.g. 1% of 1 BTC is 0.01 BTC)
*/
public static Coin getPercentOfAmountAsCoin(double percent, Coin amount) {
double amountAsDouble = (double) amount.value;
return Coin.valueOf(Math.round(percent * amountAsDouble));
}
}
5 changes: 3 additions & 2 deletions core/src/main/resources/i18n/displayStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ createOffer.amountPriceBox.amountDescription=Amount of BTC to {0}
createOffer.amountPriceBox.buy.volumeDescription=Amount in {0} to spend
createOffer.amountPriceBox.sell.volumeDescription=Amount in {0} to receive
createOffer.amountPriceBox.minAmountDescription=Minimum amount of BTC
createOffer.securityDeposit.prompt=Security deposit in BTC
createOffer.securityDeposit.prompt=Security deposit
createOffer.fundsBox.title=Fund your offer
createOffer.fundsBox.offerFee=Trade fee
createOffer.fundsBox.networkFee=Mining fee
Expand Down Expand Up @@ -416,7 +416,8 @@ createOffer.priceOutSideOfDeviation=The price you have entered is outside the ma
createOffer.changePrice=Change price
createOffer.tac=With publishing this offer I agree to trade with any trader who fulfills the conditions as defined in this screen.
createOffer.currencyForFee=Trade fee
createOffer.setDeposit=Set buyer's security deposit
createOffer.setDeposit=Set buyer's security deposit (%)
createOffer.securityDepositInfo=Your buyer''s security deposit will be {0}


####################################################################
Expand Down
2 changes: 1 addition & 1 deletion desktop/src/main/java/bisq/desktop/bisq.css
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ bg color of non edit textFields: fafafa
-fx-pref-width: 30;
}

.jfx-badge .label {
.jfx-badge .badge-pane .label {
-fx-font-weight: bold;
-fx-font-size: 0.692em;
-fx-text-fill: -bs-rd-white;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,25 +157,27 @@ public final StringProperty textProperty() {

private void setActionHandlers(Node node) {

currentIcon.setManaged(true);
currentIcon.setVisible(true);

// As we don't use binding here we need to recreate it on mouse over to reflect the current state
currentIcon.setOnMouseEntered(e -> {
hidePopover = false;
showPopOver(node);
});
currentIcon.setOnMouseExited(e -> {
if (popover != null)
popover.hide();
hidePopover = true;
UserThread.runAfter(() -> {
if (hidePopover) {
if (node != null) {
currentIcon.setManaged(true);
currentIcon.setVisible(true);

// As we don't use binding here we need to recreate it on mouse over to reflect the current state
currentIcon.setOnMouseEntered(e -> {
hidePopover = false;
showPopOver(node);
});
currentIcon.setOnMouseExited(e -> {
if (popover != null)
popover.hide();
hidePopover = false;
}
}, 250, TimeUnit.MILLISECONDS);
});
hidePopover = true;
UserThread.runAfter(() -> {
if (hidePopover) {
popover.hide();
hidePopover = false;
}
}, 250, TimeUnit.MILLISECONDS);
});
}
}

private void showPopOver(Node node) {
Expand Down
34 changes: 34 additions & 0 deletions desktop/src/main/java/bisq/desktop/components/NewBadge.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package bisq.desktop.components;

import bisq.core.locale.Res;
import bisq.core.user.Preferences;

import com.jfoenix.controls.JFXBadge;

import javafx.scene.Node;

import javafx.collections.MapChangeListener;

public class NewBadge extends JFXBadge {

private final String key;

public NewBadge(Node control, String key, Preferences preferences) {
super(control);

this.key = key;

setText(Res.get("shared.new"));
getStyleClass().add("new");

setEnabled(!preferences.getDontShowAgainMap().containsKey(key));
refreshBadge();

preferences.getDontShowAgainMapAsObservable().addListener((MapChangeListener<? super String, ? super Boolean>) change -> {
if (change.getKey().equals(key)) {
setEnabled(!change.wasAdded());
refreshBadge();
}
});
}
}
Loading