Merge branch 'mrosseel-api-pr1' into Development

This commit is contained in:
Manfred Karrer 2017-10-13 10:14:44 -05:00
commit 92434c4851
No known key found for this signature in database
GPG key ID: 401250966A6B2C46
5 changed files with 168 additions and 59 deletions

View file

@ -97,17 +97,17 @@
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.9</version>
<version>2.8.10</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.9</version>
<version>2.8.10</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.9</version>
<version>2.8.10</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>

View file

@ -0,0 +1,132 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package io.bisq.core.offer;
import io.bisq.common.util.MathUtils;
import io.bisq.core.app.BisqEnvironment;
import io.bisq.core.btc.wallet.BsqWalletService;
import io.bisq.core.provider.fee.FeeService;
import io.bisq.core.user.Preferences;
import io.bisq.core.util.CoinUtil;
import org.bitcoinj.core.Coin;
import javax.annotation.Nullable;
/**
* This class holds utility methods for the creation of an Offer.
* Most of these are extracted here because they are used both in the GUI and in the API.
*
* Long-term there could be a GUI-agnostic OfferService which provides these and other functionalities to both the
* GUI and the API.
*/
public class OfferUtil {
/**
* Given the direction, is this a BUY?
*
* @param direction
* @return
*/
public static boolean isBuyOffer(OfferPayload.Direction direction) {
return direction == OfferPayload.Direction.BUY;
}
/**
* Returns the makerFee as Coin, this can be priced in BTC or BSQ.
*
* @param bsqWalletService
* @param preferences preferences are used to see if the user indicated a preference for paying fees in BTC
* @param amount
* @param marketPriceAvailable
* @param marketPriceMargin
* @return
*/
@Nullable
public static Coin getMakerFee(BsqWalletService bsqWalletService, Preferences preferences, Coin amount, boolean marketPriceAvailable, double marketPriceMargin) {
final boolean isCurrencyForMakerFeeBtc = isCurrencyForMakerFeeBtc(preferences, bsqWalletService, amount, marketPriceAvailable, marketPriceMargin);
return getMakerFee(isCurrencyForMakerFeeBtc,
amount,
marketPriceAvailable,
marketPriceMargin);
}
/**
* Calculates the maker fee for the given amount, marketPrice and marketPriceMargin.
*
* @param isCurrencyForMakerFeeBtc
* @param amount
* @param marketPriceAvailable
* @param marketPriceMargin
* @return
*/
@Nullable
public static Coin getMakerFee(boolean isCurrencyForMakerFeeBtc, @Nullable Coin amount, boolean marketPriceAvailable, double marketPriceMargin) {
if (amount != null) {
final Coin feePerBtc = CoinUtil.getFeePerBtc(FeeService.getMakerFeePerBtc(isCurrencyForMakerFeeBtc), amount);
double makerFeeAsDouble = (double) feePerBtc.value;
if (marketPriceAvailable) {
if (marketPriceMargin > 0)
makerFeeAsDouble = makerFeeAsDouble * Math.sqrt(marketPriceMargin * 100);
else
makerFeeAsDouble = 0;
// For BTC we round so min value change is 100 satoshi
if (isCurrencyForMakerFeeBtc)
makerFeeAsDouble = MathUtils.roundDouble(makerFeeAsDouble / 100, 0) * 100;
}
return CoinUtil.maxCoin(Coin.valueOf(MathUtils.doubleToLong(makerFeeAsDouble)), FeeService.getMinMakerFee(isCurrencyForMakerFeeBtc));
} else {
return null;
}
}
/**
* Checks if the maker fee should be paid in BTC, this can be the case due to user preference or because the user
* doesn't have enough BSQ.
*
* @param preferences
* @param bsqWalletService
* @param amount
* @param marketPriceAvailable
* @param marketPriceMargin
* @return
*/
public static boolean isCurrencyForMakerFeeBtc(Preferences preferences, BsqWalletService bsqWalletService, Coin amount, boolean marketPriceAvailable, double marketPriceMargin) {
return preferences.getPayFeeInBtc() ||
!isBsqForFeeAvailable(bsqWalletService, amount, marketPriceAvailable, marketPriceMargin);
}
/**
* Checks if the available BSQ balance is sufficient to pay for the offer's maker fee.
*
* @param bsqWalletService
* @param amount
* @param marketPriceAvailable
* @param marketPriceMargin
* @return
*/
public static boolean isBsqForFeeAvailable(BsqWalletService bsqWalletService, @Nullable Coin amount, boolean marketPriceAvailable, double marketPriceMargin) {
final Coin makerFee = getMakerFee(false, amount, marketPriceAvailable, marketPriceMargin);
final Coin availableBalance = bsqWalletService.getAvailableBalance();
return makerFee != null &&
BisqEnvironment.isBaseCurrencySupportingBsq() &&
availableBalance != null &&
!availableBalance.subtract(makerFee).isNegative();
}
}

View file

@ -285,7 +285,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
public void placeOffer(Offer offer,
Coin reservedFundsForOffer,
boolean useSavingsWallet,
TransactionResultHandler resultHandler) {
TransactionResultHandler resultHandler,
ErrorMessageHandler errorMessageHandler) {
PlaceOfferModel model = new PlaceOfferModel(offer,
reservedFundsForOffer,
useSavingsWallet,
@ -307,6 +308,9 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
} else {
log.debug("We have stopped already. We ignore that placeOfferProtocol.placeOffer.onResult call.");
}
},
error -> {
errorMessageHandler.handleErrorMessage(error);
}
);
placeOfferProtocol.placeOffer();

View file

@ -17,6 +17,7 @@
package io.bisq.core.offer.placeoffer;
import io.bisq.common.handlers.ErrorMessageHandler;
import io.bisq.common.taskrunner.TaskRunner;
import io.bisq.core.offer.placeoffer.tasks.AddOfferToRemoteOfferBook;
import io.bisq.core.offer.placeoffer.tasks.BroadcastMakerFeeTx;
@ -31,6 +32,7 @@ public class PlaceOfferProtocol {
private final PlaceOfferModel model;
private final TransactionResultHandler resultHandler;
private final ErrorMessageHandler errorMessageHandler;
///////////////////////////////////////////////////////////////////////////////////////////
@ -38,9 +40,11 @@ public class PlaceOfferProtocol {
///////////////////////////////////////////////////////////////////////////////////////////
public PlaceOfferProtocol(PlaceOfferModel model,
TransactionResultHandler resultHandler) {
TransactionResultHandler resultHandler,
ErrorMessageHandler errorMessageHandler) {
this.model = model;
this.resultHandler = resultHandler;
this.errorMessageHandler = errorMessageHandler;
}
@ -66,7 +70,7 @@ public class PlaceOfferProtocol {
},
log::error);
}
log.error(errorMessage);
errorMessageHandler.handleErrorMessage(errorMessage);
}
);
taskRunner.addTasks(

View file

@ -27,7 +27,6 @@ import io.bisq.common.locale.Res;
import io.bisq.common.locale.TradeCurrency;
import io.bisq.common.monetary.Price;
import io.bisq.common.monetary.Volume;
import io.bisq.common.util.MathUtils;
import io.bisq.common.util.Utilities;
import io.bisq.core.app.BisqEnvironment;
import io.bisq.core.btc.AddressEntry;
@ -39,6 +38,7 @@ import io.bisq.core.btc.wallet.BtcWalletService;
import io.bisq.core.filter.FilterManager;
import io.bisq.core.offer.Offer;
import io.bisq.core.offer.OfferPayload;
import io.bisq.core.offer.OfferUtil;
import io.bisq.core.offer.OpenOfferManager;
import io.bisq.core.payment.*;
import io.bisq.core.payment.payload.BankAccountPayload;
@ -47,7 +47,6 @@ import io.bisq.core.provider.price.PriceFeedService;
import io.bisq.core.trade.handlers.TransactionResultHandler;
import io.bisq.core.user.Preferences;
import io.bisq.core.user.User;
import io.bisq.core.util.CoinUtil;
import io.bisq.gui.common.model.ActivatableDataModel;
import io.bisq.gui.main.overlays.notifications.Notification;
import io.bisq.gui.util.BSFormatter;
@ -59,7 +58,6 @@ import javafx.collections.SetChangeListener;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import javax.annotation.Nullable;
import java.util.*;
import java.util.stream.Collectors;
@ -411,7 +409,8 @@ class CreateOfferDataModel extends ActivatableDataModel {
openOfferManager.placeOffer(offer,
reservedFundsForOffer,
useSavingsWallet,
resultHandler);
resultHandler,
log::error);
}
void onPaymentAccountSelected(PaymentAccount paymentAccount) {
@ -507,10 +506,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
return direction;
}
String getOfferId() {
return offerId;
}
AddressEntry getAddressEntry() {
return addressEntry;
}
@ -544,22 +539,10 @@ class CreateOfferDataModel extends ActivatableDataModel {
return marketPriceMargin;
}
boolean isCurrencyForMakerFeeBtc() {
return preferences.getPayFeeInBtc() || !isBsqForFeeAvailable();
}
boolean isMakerFeeValid() {
return preferences.getPayFeeInBtc() || isBsqForFeeAvailable();
}
boolean isBsqForFeeAvailable() {
return BisqEnvironment.isBaseCurrencySupportingBsq() &&
getMakerFee(false) != null &&
bsqWalletService.getAvailableBalance() != null &&
getMakerFee(false) != null &&
!bsqWalletService.getAvailableBalance().subtract(getMakerFee(false)).isNegative();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Utils
@ -613,8 +596,8 @@ class CreateOfferDataModel extends ActivatableDataModel {
return isBuyOffer() ? buyerSecurityDeposit.get() : sellerSecurityDeposit;
}
boolean isBuyOffer() {
return direction == OfferPayload.Direction.BUY;
public boolean isBuyOffer() {
return OfferUtil.isBuyOffer(getDirection());
}
private void updateBalance() {
@ -668,7 +651,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
}
public void swapTradeToSavings() {
log.error("swapTradeToSavings, offerid={}", offerId);
log.error("swapTradeToSavings, offerId={}", offerId);
btcWalletService.resetAddressEntriesForOpenOffer(offerId);
}
@ -706,32 +689,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
preferences.setBuyerSecurityDepositAsLong(buyerSecurityDeposit.value);
}
@Nullable
public Coin getMakerFee() {
return getMakerFee(isCurrencyForMakerFeeBtc());
}
@Nullable
Coin getMakerFee(boolean isCurrencyForMakerFeeBtc) {
Coin amount = this.amount.get();
if (amount != null) {
final Coin feePerBtc = CoinUtil.getFeePerBtc(FeeService.getMakerFeePerBtc(isCurrencyForMakerFeeBtc), amount);
double makerFeeAsDouble = (double) feePerBtc.value;
if (marketPriceAvailable) {
if (marketPriceMargin > 0)
makerFeeAsDouble = makerFeeAsDouble * Math.sqrt(marketPriceMargin * 100);
else
makerFeeAsDouble = 0;
// For BTC we round so min value change is 100 satoshi
if (isCurrencyForMakerFeeBtc)
makerFeeAsDouble = MathUtils.roundDouble(makerFeeAsDouble / 100, 0) * 100;
}
return CoinUtil.maxCoin(Coin.valueOf(MathUtils.doubleToLong(makerFeeAsDouble)), FeeService.getMinMakerFee(isCurrencyForMakerFeeBtc));
} else {
return null;
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
@ -757,10 +714,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
this.minAmount.set(minAmount);
}
void setDirection(OfferPayload.Direction direction) {
this.direction = direction;
}
ReadOnlyStringProperty getTradeCurrencyCode() {
return tradeCurrencyCode;
}
@ -800,4 +753,20 @@ class CreateOfferDataModel extends ActivatableDataModel {
public void setMarketPriceAvailable(boolean marketPriceAvailable) {
this.marketPriceAvailable = marketPriceAvailable;
}
public Coin getMakerFee(boolean isCurrencyForMakerFeeBtc) {
return OfferUtil.getMakerFee(isCurrencyForMakerFeeBtc, amount.get(), marketPriceAvailable, marketPriceMargin);
}
public Coin getMakerFee() {
return OfferUtil.getMakerFee(bsqWalletService, preferences, amount.get(), marketPriceAvailable, marketPriceMargin);
}
public boolean isCurrencyForMakerFeeBtc() {
return OfferUtil.isCurrencyForMakerFeeBtc(preferences, bsqWalletService, amount.get(), marketPriceAvailable, marketPriceMargin);
}
public boolean isBsqForFeeAvailable() {
return OfferUtil.isBsqForFeeAvailable(bsqWalletService, amount.get(), marketPriceAvailable, marketPriceMargin);
}
}