Search in sources :

Example 51 with Offer

use of bisq.core.offer.Offer in project bisq-api by mrosseel.

the class BisqProxy method offerMake.

public CompletableFuture<Offer> offerMake(boolean fundUsingBisqWallet, String offerId, String accountId, OfferPayload.Direction direction, long amount, long minAmount, boolean useMarketBasedPrice, Double marketPriceMargin, String marketPair, long fiatPrice, Long buyerSecurityDeposit) {
    // exception from gui code is not clear enough, so this check is added. Missing money is another possible check but that's clear in the gui exception.
    final CompletableFuture<Offer> futureResult = new CompletableFuture<>();
    if (!fundUsingBisqWallet && null == offerId)
        return failFuture(futureResult, new ValidationException("Specify offerId of earlier prepared offer if you want to use dedicated wallet address."));
    final OfferBuilder offerBuilder = injector.getInstance(OfferBuilder.class);
    final Offer offer;
    try {
        offer = offerBuilder.build(offerId, accountId, direction, amount, minAmount, useMarketBasedPrice, marketPriceMargin, marketPair, fiatPrice, buyerSecurityDeposit);
    } catch (Exception e) {
        return failFuture(futureResult, e);
    }
    Coin reservedFundsForOffer = OfferUtil.isBuyOffer(direction) ? preferences.getBuyerSecurityDepositAsCoin() : Restrictions.getSellerSecurityDeposit();
    if (!OfferUtil.isBuyOffer(direction))
        reservedFundsForOffer = reservedFundsForOffer.add(Coin.valueOf(amount));
    // TODO check if there is sufficient money cause openOfferManager will log exception and pass just message
    // TODO openOfferManager should return CompletableFuture or at least send full exception to error handler
    openOfferManager.placeOffer(offer, reservedFundsForOffer, fundUsingBisqWallet, transaction -> futureResult.complete(offer), error -> {
        if (error.contains("Insufficient money"))
            futureResult.completeExceptionally(new InsufficientMoneyException(error));
        else if (error.contains("Amount is larger"))
            futureResult.completeExceptionally(new AmountTooHighException(error));
        else
            futureResult.completeExceptionally(new RuntimeException(error));
    });
    return futureResult;
}
Also used : Coin(org.bitcoinj.core.Coin) CompletableFuture(java.util.concurrent.CompletableFuture) ValidationException(javax.validation.ValidationException) OpenOffer(bisq.core.offer.OpenOffer) Offer(bisq.core.offer.Offer) PaymentAccountUtil.isPaymentAccountValidForOffer(bisq.core.payment.PaymentAccountUtil.isPaymentAccountValidForOffer) AddressEntryException(bisq.core.btc.AddressEntryException) InsufficientFundsException(bisq.core.btc.InsufficientFundsException) IOException(java.io.IOException) FileNotFoundException(java.io.FileNotFoundException) ValidationException(javax.validation.ValidationException)

Example 52 with Offer

use of bisq.core.offer.Offer in project bisq-api by mrosseel.

the class BisqProxy method offerTake.

// / START TODO REFACTOR OFFER TAKE DEPENDENCIES //////////////////////////
public CompletableFuture<Trade> offerTake(String offerId, String paymentAccountId, long amount, boolean useSavingsWallet) {
    final CompletableFuture<Trade> futureResult = new CompletableFuture<>();
    final Offer offer;
    try {
        offer = getOffer(offerId);
    } catch (NotFoundException e) {
        return failFuture(futureResult, e);
    }
    if (offer.getMakerNodeAddress().equals(p2PService.getAddress())) {
        return failFuture(futureResult, new OfferTakerSameAsMakerException("Taker's address same as maker's"));
    }
    // check the paymentAccountId is valid
    final PaymentAccount paymentAccount = getPaymentAccount(paymentAccountId);
    if (paymentAccount == null) {
        return failFuture(futureResult, new PaymentAccountNotFoundException("Could not find payment account with id: " + paymentAccountId));
    }
    // check the paymentAccountId is compatible with the offer
    if (!isPaymentAccountValidForOffer(offer, paymentAccount)) {
        final String errorMessage = "PaymentAccount is not valid for offer, needs " + offer.getCurrencyCode();
        return failFuture(futureResult, new IncompatiblePaymentAccountException(errorMessage));
    }
    // check the amount is within the range
    Coin coinAmount = Coin.valueOf(amount);
    // workaround because TradeTask does not have an error handler to notify us that something went wrong
    if (btcWalletService.getAvailableBalance().isLessThan(coinAmount)) {
        final String errorMessage = "Available balance " + btcWalletService.getAvailableBalance() + " is less than needed amount: " + coinAmount;
        return failFuture(futureResult, new InsufficientMoneyException(errorMessage));
    }
    // check that the price is correct ??
    // check taker fee
    // check security deposit for BTC buyer
    // check security deposit for BTC seller
    Coin securityDeposit = offer.getDirection() == OfferPayload.Direction.SELL ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit();
    Coin txFeeFromFeeService = feeService.getTxFee(600);
    Coin fundsNeededForTradeTemp = securityDeposit.add(txFeeFromFeeService).add(txFeeFromFeeService);
    final Coin fundsNeededForTrade;
    if (offer.isBuyOffer())
        fundsNeededForTrade = fundsNeededForTradeTemp.add(coinAmount);
    else
        fundsNeededForTrade = fundsNeededForTradeTemp;
    Coin takerFee = getTakerFee(coinAmount);
    checkNotNull(txFeeFromFeeService, "txFeeFromFeeService must not be null");
    checkNotNull(takerFee, "takerFee must not be null");
    tradeManager.onTakeOffer(coinAmount, txFeeFromFeeService, takerFee, isCurrencyForTakerFeeBtc(coinAmount), offer.getPrice().getValue(), fundsNeededForTrade, offer, paymentAccount.getId(), useSavingsWallet, futureResult::complete, error -> futureResult.completeExceptionally(new RuntimeException(error)));
    return futureResult;
}
Also used : PaymentAccount(bisq.core.payment.PaymentAccount) FileNotFoundException(java.io.FileNotFoundException) SellerAsMakerTrade(bisq.core.trade.SellerAsMakerTrade) BuyerAsMakerTrade(bisq.core.trade.BuyerAsMakerTrade) Trade(bisq.core.trade.Trade) Coin(org.bitcoinj.core.Coin) CompletableFuture(java.util.concurrent.CompletableFuture) OpenOffer(bisq.core.offer.OpenOffer) Offer(bisq.core.offer.Offer) PaymentAccountUtil.isPaymentAccountValidForOffer(bisq.core.payment.PaymentAccountUtil.isPaymentAccountValidForOffer)

Example 53 with Offer

use of bisq.core.offer.Offer in project bisq-api by mrosseel.

the class OfferBuilder method build.

public Offer build(String offerId, String accountId, OfferPayload.Direction direction, long amount, long minAmount, boolean useMarketBasedPrice, Double marketPriceMargin, String marketPair, long fiatPrice, Long buyerSecurityDeposit) throws NoAcceptedArbitratorException, PaymentAccountNotFoundException, IncompatiblePaymentAccountException {
    final List<NodeAddress> acceptedArbitratorAddresses = user.getAcceptedArbitratorAddresses();
    if (null == acceptedArbitratorAddresses || acceptedArbitratorAddresses.size() == 0) {
        throw new NoAcceptedArbitratorException("No arbitrator has been chosen");
    }
    // Checked that if fixed we have a fixed price, if percentage we have a percentage
    if (marketPriceMargin == null && useMarketBasedPrice) {
        throw new ValidationException("When choosing PERCENTAGE price, fill in percentageFromMarketPrice");
    } else if (0 == fiatPrice && !useMarketBasedPrice) {
        throw new ValidationException("When choosing FIXED price, fill in fixedPrice with a price > 0");
    }
    if (null == marketPriceMargin)
        marketPriceMargin = 0d;
    // fix marketPair if it's lowercase
    marketPair = marketPair.toUpperCase();
    checkMarketValidity(marketPair);
    Market market = new Market(marketPair);
    // if right side is fiat, then left is base currency.
    // else right side is base currency.
    final String currencyCode = market.getRsymbol();
    final boolean isFiatCurrency = CurrencyUtil.isFiatCurrency(currencyCode);
    String baseCurrencyCode = !isFiatCurrency ? currencyCode : market.getLsymbol();
    String counterCurrencyCode = !isFiatCurrency ? market.getLsymbol() : currencyCode;
    Optional<PaymentAccount> optionalAccount = getPaymentAccounts().stream().filter(account1 -> account1.getId().equals(accountId)).findFirst();
    if (!optionalAccount.isPresent()) {
        throw new PaymentAccountNotFoundException("Could not find payment account with id: " + accountId);
    }
    PaymentAccount paymentAccount = optionalAccount.get();
    // COPIED from CreateDataOfferModel: TODO refactor uit of GUI module  /////////////////////////////
    String countryCode = paymentAccount instanceof CountryBasedPaymentAccount ? ((CountryBasedPaymentAccount) paymentAccount).getCountry().code : null;
    ArrayList<String> acceptedCountryCodes = null;
    if (paymentAccount instanceof SepaAccount) {
        acceptedCountryCodes = new ArrayList<>();
        acceptedCountryCodes.addAll(((SepaAccount) paymentAccount).getAcceptedCountryCodes());
    } else if (paymentAccount instanceof CountryBasedPaymentAccount) {
        acceptedCountryCodes = new ArrayList<>();
        acceptedCountryCodes.add(((CountryBasedPaymentAccount) paymentAccount).getCountry().code);
    }
    String bankId = paymentAccount instanceof BankAccount ? ((BankAccount) paymentAccount).getBankId() : null;
    ArrayList<String> acceptedBanks = null;
    if (paymentAccount instanceof SpecificBanksAccount) {
        acceptedBanks = new ArrayList<>(((SpecificBanksAccount) paymentAccount).getAcceptedBanks());
    } else if (paymentAccount instanceof SameBankAccount) {
        acceptedBanks = new ArrayList<>();
        acceptedBanks.add(((SameBankAccount) paymentAccount).getBankId());
    }
    long maxTradeLimit = paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin(baseCurrencyCode).value;
    long maxTradePeriod = paymentAccount.getPaymentMethod().getMaxTradePeriod();
    boolean isPrivateOffer = false;
    boolean useAutoClose = false;
    boolean useReOpenAfterAutoClose = false;
    long lowerClosePrice = 0;
    long upperClosePrice = 0;
    String hashOfChallenge = null;
    HashMap<String, String> extraDataMap = null;
    if (isFiatCurrency) {
        extraDataMap = new HashMap<>();
        final String myWitnessHashAsHex = accountAgeWitnessService.getMyWitnessHashAsHex(paymentAccount.getPaymentAccountPayload());
        extraDataMap.put(OfferPayload.ACCOUNT_AGE_WITNESS_HASH, myWitnessHashAsHex);
    }
    // COPIED from CreateDataOfferModel /////////////////////////////
    updateMarketPriceAvailable(baseCurrencyCode);
    // TODO dummy values in this constructor !!!
    Coin coinAmount = Coin.valueOf(amount);
    if (null == buyerSecurityDeposit) {
        buyerSecurityDeposit = preferences.getBuyerSecurityDepositAsCoin().value;
    }
    OfferPayload offerPayload = new OfferPayload(null == offerId ? UUID.randomUUID().toString() : offerId, new Date().getTime(), p2PService.getAddress(), keyRing.getPubKeyRing(), direction, fiatPrice, marketPriceMargin, useMarketBasedPrice, amount, minAmount, baseCurrencyCode, counterCurrencyCode, acceptedArbitratorAddresses, user.getAcceptedMediatorAddresses(), paymentAccount.getPaymentMethod().getId(), paymentAccount.getId(), // will be filled in by BroadcastMakerFeeTx class
    null, countryCode, acceptedCountryCodes, bankId, acceptedBanks, Version.VERSION, btcWalletService.getLastBlockSeenHeight(), // default also used in code CreateOfferDataModel
    feeService.getTxFee(600).value, getMakerFee(coinAmount, marketPriceMargin).value, preferences.getPayFeeInBtc() || !isBsqForFeeAvailable(coinAmount, marketPriceMargin), buyerSecurityDeposit, Restrictions.getSellerSecurityDeposit().value, maxTradeLimit, maxTradePeriod, useAutoClose, useReOpenAfterAutoClose, upperClosePrice, lowerClosePrice, isPrivateOffer, hashOfChallenge, extraDataMap, Version.TRADE_PROTOCOL_VERSION);
    Offer offer = new Offer(offerPayload);
    offer.setPriceFeedService(priceFeedService);
    if (!isPaymentAccountValidForOffer(offer, paymentAccount)) {
        final String errorMessage = "PaymentAccount is not valid for offer, needs " + offer.getCurrencyCode();
        throw new IncompatiblePaymentAccountException(errorMessage);
    }
    if (null == getMakerFee(false, Coin.valueOf(amount), marketPriceMargin)) {
        throw new ValidationException("makerFee must not be null");
    }
    return offer;
}
Also used : BtcWalletService(bisq.core.btc.wallet.BtcWalletService) java.util(java.util) Coin(org.bitcoinj.core.Coin) Inject(com.google.inject.Inject) StringUtils(org.apache.commons.lang3.StringUtils) User(bisq.core.user.User) OfferPayload(bisq.core.offer.OfferPayload) Market(network.bisq.api.model.Market) CurrencyUtil(bisq.core.locale.CurrencyUtil) PaymentAccountUtil.isPaymentAccountValidForOffer(bisq.core.payment.PaymentAccountUtil.isPaymentAccountValidForOffer) Nullable(javax.annotation.Nullable) bisq.core.payment(bisq.core.payment) Version(bisq.common.app.Version) Offer(bisq.core.offer.Offer) P2PService(bisq.network.p2p.P2PService) BisqEnvironment(bisq.core.app.BisqEnvironment) MathUtils(bisq.common.util.MathUtils) BsqWalletService(bisq.core.btc.wallet.BsqWalletService) PriceFeedService(bisq.core.provider.price.PriceFeedService) ValidationException(javax.validation.ValidationException) NodeAddress(bisq.network.p2p.NodeAddress) Preferences(bisq.core.user.Preferences) FeeService(bisq.core.provider.fee.FeeService) KeyRing(bisq.common.crypto.KeyRing) Restrictions(bisq.core.btc.Restrictions) CoinUtil(bisq.core.util.CoinUtil) ValidationException(javax.validation.ValidationException) Coin(org.bitcoinj.core.Coin) NodeAddress(bisq.network.p2p.NodeAddress) Market(network.bisq.api.model.Market) PaymentAccountUtil.isPaymentAccountValidForOffer(bisq.core.payment.PaymentAccountUtil.isPaymentAccountValidForOffer) Offer(bisq.core.offer.Offer) OfferPayload(bisq.core.offer.OfferPayload)

Aggregations

Offer (bisq.core.offer.Offer)53 Coin (org.bitcoinj.core.Coin)18 Test (org.junit.Test)13 OfferPayload (bisq.core.offer.OfferPayload)12 PrepareForTest (org.powermock.core.classloader.annotations.PrepareForTest)12 Price (bisq.core.monetary.Price)9 OfferMaker.btcUsdOffer (bisq.core.offer.OfferMaker.btcUsdOffer)8 NodeAddress (bisq.network.p2p.NodeAddress)8 PaymentMethod (bisq.core.payment.payload.PaymentMethod)7 Contract (bisq.core.trade.Contract)7 Volume (bisq.core.monetary.Volume)6 PeerInfoIcon (bisq.desktop.components.PeerInfoIcon)6 Popup (bisq.desktop.main.overlays.popups.Popup)6 OpenOffer (bisq.core.offer.OpenOffer)5 PaymentAccount (bisq.core.payment.PaymentAccount)5 MainView (bisq.desktop.main.MainView)5 Button (javafx.scene.control.Button)5 TableCell (javafx.scene.control.TableCell)5 TableColumn (javafx.scene.control.TableColumn)5 BtcWalletService (bisq.core.btc.wallet.BtcWalletService)4