forked from bisq-network/bisq
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactorings for api support (bisq-network#3611)
* Remove trailing spaces * Add toProtoTradeStatistics2 method API will use getTradeStatistics and expect TradeStatistics2 not PersistableNetworkPayload * Add CreateOfferService class * Remove commented out code * User weaker access, add final * Add getRandomOfferId method * Add getSellerSecurityDeposit method * Add getEstimatedFeeAndTxSize method - Rename estimateTxSize to updateEstimatedFeeAndTxSize - Add getEstimatedFeeAndTxSize method to CreateOfferService - Add dependent methods and fields * Use methods from createOfferService - Use getBuyerSecurityDepositAsCoin and getSellerSecurityDepositAsCoin from CreateOfferService * Use txFeeFromFeeService from createOfferService - Use getEstimatedFeeAndTxSize from CreateOfferService for txFeeFromFeeService * Use getPriceAsLong from createOfferService * Use marketPriceMarginParam from createOfferService * Pass useMarketBasedPriceValue to getPriceAsLong * Use getMaxTradeLimit from createOfferService * Use createAndGetOffer from createOfferService * Remove unused fields * Add createOfferService, remove unused params * Use weaker access * Add null checks * Add log of params, Cleanup * Remove unused fields * Use weaker access * Remove trivial methods * Remove trivial methods, rename methods * Sort params for offer as they are used * Use getReservedFundsForOffer from createOfferService * Add MakerFeeProvider * Adjust to new super class params * Remove sellerSecurityDeposit field, refactor placeOffer * Adjust tests to new params
- Loading branch information
Showing
13 changed files
with
469 additions
and
221 deletions.
There are no files selected for viewing
350 changes: 350 additions & 0 deletions
350
core/src/main/java/bisq/core/offer/CreateOfferService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,350 @@ | ||
/* | ||
* 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 bisq.core.offer; | ||
|
||
import bisq.core.account.witness.AccountAgeWitnessService; | ||
import bisq.core.btc.TxFeeEstimationService; | ||
import bisq.core.btc.wallet.BsqWalletService; | ||
import bisq.core.btc.wallet.BtcWalletService; | ||
import bisq.core.btc.wallet.Restrictions; | ||
import bisq.core.filter.FilterManager; | ||
import bisq.core.locale.CurrencyUtil; | ||
import bisq.core.locale.Res; | ||
import bisq.core.monetary.Price; | ||
import bisq.core.payment.HalCashAccount; | ||
import bisq.core.payment.PaymentAccount; | ||
import bisq.core.payment.PaymentAccountUtil; | ||
import bisq.core.provider.price.MarketPrice; | ||
import bisq.core.provider.price.PriceFeedService; | ||
import bisq.core.trade.statistics.ReferralIdService; | ||
import bisq.core.user.Preferences; | ||
import bisq.core.user.User; | ||
import bisq.core.util.CoinUtil; | ||
|
||
import bisq.network.p2p.NodeAddress; | ||
import bisq.network.p2p.P2PService; | ||
|
||
import bisq.common.app.Version; | ||
import bisq.common.crypto.PubKeyRing; | ||
import bisq.common.util.Tuple2; | ||
import bisq.common.util.Utilities; | ||
|
||
import org.bitcoinj.core.Coin; | ||
|
||
import javax.inject.Inject; | ||
import javax.inject.Singleton; | ||
|
||
import com.google.common.collect.Lists; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Date; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.UUID; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
|
||
@Slf4j | ||
@Singleton | ||
public class CreateOfferService { | ||
private final TxFeeEstimationService txFeeEstimationService; | ||
private final MakerFeeProvider makerFeeProvider; | ||
private final BsqWalletService bsqWalletService; | ||
private final Preferences preferences; | ||
private final PriceFeedService priceFeedService; | ||
private final AccountAgeWitnessService accountAgeWitnessService; | ||
private final ReferralIdService referralIdService; | ||
private final FilterManager filterManager; | ||
private final P2PService p2PService; | ||
private final PubKeyRing pubKeyRing; | ||
private final User user; | ||
private final BtcWalletService btcWalletService; | ||
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////// | ||
// Constructor, Initialization | ||
/////////////////////////////////////////////////////////////////////////////////////////// | ||
|
||
@Inject | ||
public CreateOfferService(TxFeeEstimationService txFeeEstimationService, | ||
MakerFeeProvider makerFeeProvider, | ||
BsqWalletService bsqWalletService, | ||
Preferences preferences, | ||
PriceFeedService priceFeedService, | ||
AccountAgeWitnessService accountAgeWitnessService, | ||
ReferralIdService referralIdService, | ||
FilterManager filterManager, | ||
P2PService p2PService, | ||
PubKeyRing pubKeyRing, | ||
User user, | ||
BtcWalletService btcWalletService) { | ||
this.txFeeEstimationService = txFeeEstimationService; | ||
this.makerFeeProvider = makerFeeProvider; | ||
this.bsqWalletService = bsqWalletService; | ||
this.preferences = preferences; | ||
this.priceFeedService = priceFeedService; | ||
this.accountAgeWitnessService = accountAgeWitnessService; | ||
this.referralIdService = referralIdService; | ||
this.filterManager = filterManager; | ||
this.p2PService = p2PService; | ||
this.pubKeyRing = pubKeyRing; | ||
this.user = user; | ||
this.btcWalletService = btcWalletService; | ||
} | ||
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////// | ||
// API | ||
/////////////////////////////////////////////////////////////////////////////////////////// | ||
|
||
public String getRandomOfferId() { | ||
return Utilities.getRandomPrefix(5, 8) + "-" + | ||
UUID.randomUUID().toString() + "-" + | ||
Version.VERSION.replace(".", ""); | ||
} | ||
|
||
public Offer createAndGetOffer(String offerId, | ||
OfferPayload.Direction direction, | ||
String currencyCode, | ||
Coin amount, | ||
Coin minAmount, | ||
Price price, | ||
boolean useMarketBasedPrice, | ||
double marketPriceMargin, | ||
double buyerSecurityDepositAsDouble, | ||
PaymentAccount paymentAccount) { | ||
|
||
log.info("offerId={}, \n" + | ||
"currencyCode={}, \n" + | ||
"direction={}, \n" + | ||
"price={}, \n" + | ||
"useMarketBasedPrice={}, \n" + | ||
"marketPriceMargin={}, \n" + | ||
"amount={}, \n" + | ||
"minAmount={}, \n" + | ||
"buyerSecurityDeposit={}, \n" + | ||
"paymentAccount={}, \n", | ||
offerId, currencyCode, direction, price.getValue(), useMarketBasedPrice, marketPriceMargin, | ||
amount.value, minAmount.value, buyerSecurityDepositAsDouble, paymentAccount); | ||
|
||
// prints our param list for dev testing api | ||
log.info("{} " + | ||
"{} " + | ||
"{} " + | ||
"{} " + | ||
"{} " + | ||
"{} " + | ||
"{} " + | ||
"{} " + | ||
"{} " + | ||
"{}", | ||
offerId, currencyCode, direction.name(), price.getValue(), useMarketBasedPrice, marketPriceMargin, | ||
amount.value, minAmount.value, buyerSecurityDepositAsDouble, paymentAccount.getId()); | ||
|
||
long creationTime = new Date().getTime(); | ||
NodeAddress makerAddress = p2PService.getAddress(); | ||
boolean useMarketBasedPriceValue = useMarketBasedPrice && | ||
isMarketPriceAvailable(currencyCode) && | ||
!isHalCashAccount(paymentAccount); | ||
|
||
long priceAsLong = price != null && !useMarketBasedPriceValue ? price.getValue() : 0L; | ||
double marketPriceMarginParam = useMarketBasedPriceValue ? marketPriceMargin : 0; | ||
long amountAsLong = amount != null ? amount.getValue() : 0L; | ||
long minAmountAsLong = minAmount != null ? minAmount.getValue() : 0L; | ||
boolean isCryptoCurrency = CurrencyUtil.isCryptoCurrency(currencyCode); | ||
String baseCurrencyCode = isCryptoCurrency ? currencyCode : Res.getBaseCurrencyCode(); | ||
String counterCurrencyCode = isCryptoCurrency ? Res.getBaseCurrencyCode() : currencyCode; | ||
List<NodeAddress> acceptedArbitratorAddresses = user.getAcceptedArbitratorAddresses(); | ||
ArrayList<NodeAddress> arbitratorNodeAddresses = acceptedArbitratorAddresses != null ? | ||
Lists.newArrayList(acceptedArbitratorAddresses) : | ||
new ArrayList<>(); | ||
List<NodeAddress> acceptedMediatorAddresses = user.getAcceptedMediatorAddresses(); | ||
ArrayList<NodeAddress> mediatorNodeAddresses = acceptedMediatorAddresses != null ? | ||
Lists.newArrayList(acceptedMediatorAddresses) : | ||
new ArrayList<>(); | ||
String countryCode = PaymentAccountUtil.getCountryCode(paymentAccount); | ||
List<String> acceptedCountryCodes = PaymentAccountUtil.getAcceptedCountryCodes(paymentAccount); | ||
String bankId = PaymentAccountUtil.getBankId(paymentAccount); | ||
List<String> acceptedBanks = PaymentAccountUtil.getAcceptedBanks(paymentAccount); | ||
double sellerSecurityDeposit = getSellerSecurityDepositAsDouble(); | ||
Coin txFeeFromFeeService = getEstimatedFeeAndTxSize(amount, direction, buyerSecurityDepositAsDouble, sellerSecurityDeposit).first; | ||
Coin makerFeeAsCoin = getMakerFee(amount); | ||
boolean isCurrencyForMakerFeeBtc = OfferUtil.isCurrencyForMakerFeeBtc(preferences, bsqWalletService, amount); | ||
Coin buyerSecurityDepositAsCoin = getBuyerSecurityDeposit(amount, buyerSecurityDepositAsDouble); | ||
Coin sellerSecurityDepositAsCoin = getSellerSecurityDeposit(amount, sellerSecurityDeposit); | ||
long maxTradeLimit = getMaxTradeLimit(paymentAccount, currencyCode, direction); | ||
long maxTradePeriod = paymentAccount.getMaxTradePeriod(); | ||
|
||
// reserved for future use cases | ||
// Use null values if not set | ||
boolean isPrivateOffer = false; | ||
boolean useAutoClose = false; | ||
boolean useReOpenAfterAutoClose = false; | ||
long lowerClosePrice = 0; | ||
long upperClosePrice = 0; | ||
String hashOfChallenge = null; | ||
Map<String, String> extraDataMap = OfferUtil.getExtraDataMap(accountAgeWitnessService, | ||
referralIdService, | ||
paymentAccount, | ||
currencyCode, | ||
preferences); | ||
|
||
OfferUtil.validateOfferData(filterManager, | ||
p2PService, | ||
buyerSecurityDepositAsDouble, | ||
paymentAccount, | ||
currencyCode, | ||
makerFeeAsCoin); | ||
|
||
OfferPayload offerPayload = new OfferPayload(offerId, | ||
creationTime, | ||
makerAddress, | ||
pubKeyRing, | ||
OfferPayload.Direction.valueOf(direction.name()), | ||
priceAsLong, | ||
marketPriceMarginParam, | ||
useMarketBasedPriceValue, | ||
amountAsLong, | ||
minAmountAsLong, | ||
baseCurrencyCode, | ||
counterCurrencyCode, | ||
arbitratorNodeAddresses, | ||
mediatorNodeAddresses, | ||
paymentAccount.getPaymentMethod().getId(), | ||
paymentAccount.getId(), | ||
null, | ||
countryCode, | ||
acceptedCountryCodes, | ||
bankId, | ||
acceptedBanks, | ||
Version.VERSION, | ||
btcWalletService.getLastBlockSeenHeight(), | ||
txFeeFromFeeService.value, | ||
makerFeeAsCoin.value, | ||
isCurrencyForMakerFeeBtc, | ||
buyerSecurityDepositAsCoin.value, | ||
sellerSecurityDepositAsCoin.value, | ||
maxTradeLimit, | ||
maxTradePeriod, | ||
useAutoClose, | ||
useReOpenAfterAutoClose, | ||
upperClosePrice, | ||
lowerClosePrice, | ||
isPrivateOffer, | ||
hashOfChallenge, | ||
extraDataMap, | ||
Version.TRADE_PROTOCOL_VERSION); | ||
Offer offer = new Offer(offerPayload); | ||
offer.setPriceFeedService(priceFeedService); | ||
return offer; | ||
} | ||
|
||
public Tuple2<Coin, Integer> getEstimatedFeeAndTxSize(Coin amount, | ||
OfferPayload.Direction direction, | ||
double buyerSecurityDeposit, | ||
double sellerSecurityDeposit) { | ||
Coin reservedFundsForOffer = getReservedFundsForOffer(direction, amount, buyerSecurityDeposit, sellerSecurityDeposit); | ||
return txFeeEstimationService.getEstimatedFeeAndTxSizeForMaker(reservedFundsForOffer, getMakerFee(amount)); | ||
} | ||
|
||
public Coin getReservedFundsForOffer(OfferPayload.Direction direction, | ||
Coin amount, | ||
double buyerSecurityDeposit, | ||
double sellerSecurityDeposit) { | ||
|
||
Coin reservedFundsForOffer = getSecurityDeposit(direction, | ||
amount, | ||
buyerSecurityDeposit, | ||
sellerSecurityDeposit); | ||
if (!isBuyOffer(direction)) | ||
reservedFundsForOffer = reservedFundsForOffer.add(amount); | ||
|
||
return reservedFundsForOffer; | ||
} | ||
|
||
public Coin getSecurityDeposit(OfferPayload.Direction direction, | ||
Coin amount, | ||
double buyerSecurityDeposit, | ||
double sellerSecurityDeposit) { | ||
return isBuyOffer(direction) ? | ||
getBuyerSecurityDeposit(amount, buyerSecurityDeposit) : | ||
getSellerSecurityDeposit(amount, sellerSecurityDeposit); | ||
} | ||
|
||
public double getSellerSecurityDepositAsDouble() { | ||
return Restrictions.getSellerSecurityDepositAsPercent(); | ||
} | ||
|
||
public Coin getMakerFee(Coin amount) { | ||
return makerFeeProvider.getMakerFee(bsqWalletService, preferences, amount); | ||
} | ||
|
||
public long getMaxTradeLimit(PaymentAccount paymentAccount, | ||
String currencyCode, | ||
OfferPayload.Direction direction) { | ||
if (paymentAccount != null) { | ||
return accountAgeWitnessService.getMyTradeLimit(paymentAccount, currencyCode, direction); | ||
} else { | ||
return 0; | ||
} | ||
} | ||
|
||
public boolean isBuyOffer(OfferPayload.Direction direction) { | ||
return OfferUtil.isBuyOffer(direction); | ||
} | ||
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////// | ||
// Private | ||
/////////////////////////////////////////////////////////////////////////////////////////// | ||
|
||
private boolean isMarketPriceAvailable(String currencyCode) { | ||
MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode); | ||
return marketPrice != null && marketPrice.isExternallyProvidedPrice(); | ||
} | ||
|
||
private boolean isHalCashAccount(PaymentAccount paymentAccount) { | ||
return paymentAccount instanceof HalCashAccount; | ||
} | ||
|
||
private Coin getBuyerSecurityDeposit(Coin amount, double buyerSecurityDeposit) { | ||
Coin percentOfAmountAsCoin = CoinUtil.getPercentOfAmountAsCoin(buyerSecurityDeposit, amount); | ||
return getBoundedBuyerSecurityDeposit(percentOfAmountAsCoin); | ||
} | ||
|
||
private Coin getSellerSecurityDeposit(Coin amount, double sellerSecurityDeposit) { | ||
Coin amountAsCoin = amount; | ||
if (amountAsCoin == null) | ||
amountAsCoin = Coin.ZERO; | ||
|
||
Coin percentOfAmountAsCoin = CoinUtil.getPercentOfAmountAsCoin(sellerSecurityDeposit, amountAsCoin); | ||
return getBoundedSellerSecurityDeposit(percentOfAmountAsCoin); | ||
} | ||
|
||
private Coin getBoundedBuyerSecurityDeposit(Coin value) { | ||
// We need to ensure that for small amount values we don't get a too low BTC amount. We limit it with using the | ||
// MinBuyerSecurityDepositAsCoin from Restrictions. | ||
return Coin.valueOf(Math.max(Restrictions.getMinBuyerSecurityDepositAsCoin().value, value.value)); | ||
} | ||
|
||
private Coin getBoundedSellerSecurityDeposit(Coin value) { | ||
// We need to ensure that for small amount values we don't get a too low BTC amount. We limit it with using the | ||
// MinSellerSecurityDepositAsCoin from Restrictions. | ||
return Coin.valueOf(Math.max(Restrictions.getMinSellerSecurityDepositAsCoin().value, value.value)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* 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 bisq.core.offer; | ||
|
||
import bisq.core.btc.wallet.BsqWalletService; | ||
import bisq.core.user.Preferences; | ||
|
||
import org.bitcoinj.core.Coin; | ||
|
||
public class MakerFeeProvider { | ||
public Coin getMakerFee(BsqWalletService bsqWalletService, Preferences preferences, Coin amount) { | ||
return OfferUtil.getMakerFee(bsqWalletService, preferences, amount); | ||
} | ||
} |
Oops, something went wrong.