<commit_before>/*
 * 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.TxFeeEstimationService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.Restrictions;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.monetary.Price;
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.user.Preferences;
import bisq.core.user.User;
import bisq.core.util.coin.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 OfferUtil offerUtil;
    private final TxFeeEstimationService txFeeEstimationService;
    private final PriceFeedService priceFeedService;
    private final P2PService p2PService;
    private final PubKeyRing pubKeyRing;
    private final User user;
    private final BtcWalletService btcWalletService;


    ///////////////////////////////////////////////////////////////////////////////////////////
    // Constructor, Initialization
    ///////////////////////////////////////////////////////////////////////////////////////////

    @Inject
    public CreateOfferService(OfferUtil offerUtil,
                              TxFeeEstimationService txFeeEstimationService,
                              PriceFeedService priceFeedService,
                              P2PService p2PService,
                              PubKeyRing pubKeyRing,
                              User user,
                              BtcWalletService btcWalletService) {
        this.offerUtil = offerUtil;
        this.txFeeEstimationService = txFeeEstimationService;
        this.priceFeedService = priceFeedService;
        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,
                                   Coin txFee,
                                   boolean useMarketBasedPrice,
                                   double marketPriceMargin,
                                   double buyerSecurityDepositAsDouble,
                                   PaymentAccount paymentAccount) {

        log.info("create and get offer with offerId={}, \n" +
                        "currencyCode={}, \n" +
                        "direction={}, \n" +
                        "price={}, \n" +
                        "useMarketBasedPrice={}, \n" +
                        "marketPriceMargin={}, \n" +
                        "amount={}, \n" +
                        "minAmount={}, \n" +
                        "buyerSecurityDeposit={}",
                offerId,
                currencyCode,
                direction,
                price.getValue(),
                useMarketBasedPrice,
                marketPriceMargin,
                amount.value,
                minAmount.value,
                buyerSecurityDepositAsDouble);

        // Log an approximate api CLI 'createoffer' dev/test param list.
        log.info("cli's createoffer positional option names: paymentAccountId direction currencyCode amount minAmount"
                + " useMarketBasedPrice fixedPrice|marketPriceMargin buyerSecurityDeposit");
        log.info("cli's createoffer positional option values: {} " +
                        "{} " +
                        "{} " +
                        "{} " +
                        "{} " +
                        "{} " +
                        "{} " +
                        "{}",
                paymentAccount.getId(),
                direction.name(),
                currencyCode,
                amount.value,
                minAmount.value,
                useMarketBasedPrice,
                (useMarketBasedPrice == true ? marketPriceMargin : price.getValue()),
                buyerSecurityDepositAsDouble);

        long creationTime = new Date().getTime();
        NodeAddress makerAddress = p2PService.getAddress();
        boolean useMarketBasedPriceValue = useMarketBasedPrice &&
                isMarketPriceAvailable(currencyCode) &&
                !paymentAccount.isHalCashAccount();

        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) :<commit_msg>Avoid unnecessary comparisons in boolean expressions<commit_after>/*
 * 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.TxFeeEstimationService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.Restrictions;
import bisq.core.locale.CurrencyUtil;
import bisq.core.locale.Res;
import bisq.core.monetary.Price;
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.user.Preferences;
import bisq.core.user.User;
import bisq.core.util.coin.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 OfferUtil offerUtil;
    private final TxFeeEstimationService txFeeEstimationService;
    private final PriceFeedService priceFeedService;
    private final P2PService p2PService;
    private final PubKeyRing pubKeyRing;
    private final User user;
    private final BtcWalletService btcWalletService;


    ///////////////////////////////////////////////////////////////////////////////////////////
    // Constructor, Initialization
    ///////////////////////////////////////////////////////////////////////////////////////////

    @Inject
    public CreateOfferService(OfferUtil offerUtil,
                              TxFeeEstimationService txFeeEstimationService,
                              PriceFeedService priceFeedService,
                              P2PService p2PService,
                              PubKeyRing pubKeyRing,
                              User user,
                              BtcWalletService btcWalletService) {
        this.offerUtil = offerUtil;
        this.txFeeEstimationService = txFeeEstimationService;
        this.priceFeedService = priceFeedService;
        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,
                                   Coin txFee,
                                   boolean useMarketBasedPrice,
                                   double marketPriceMargin,
                                   double buyerSecurityDepositAsDouble,
                                   PaymentAccount paymentAccount) {

        log.info("create and get offer with offerId={}, \n" +
                        "currencyCode={}, \n" +
                        "direction={}, \n" +
                        "price={}, \n" +
                        "useMarketBasedPrice={}, \n" +
                        "marketPriceMargin={}, \n" +
                        "amount={}, \n" +
                        "minAmount={}, \n" +
                        "buyerSecurityDeposit={}",
                offerId,
                currencyCode,
                direction,
                price.getValue(),
                useMarketBasedPrice,
                marketPriceMargin,
                amount.value,
                minAmount.value,
                buyerSecurityDepositAsDouble);

        // Log an approximate api CLI 'createoffer' dev/test param list.
        log.info("cli's createoffer positional option names: paymentAccountId direction currencyCode amount minAmount"
                + " useMarketBasedPrice fixedPrice|marketPriceMargin buyerSecurityDeposit");
        log.info("cli's createoffer positional option values: {} " +
                        "{} " +
                        "{} " +
                        "{} " +
                        "{} " +
                        "{} " +
                        "{} " +
                        "{}",
                paymentAccount.getId(),
                direction.name(),
                currencyCode,
                amount.value,
                minAmount.value,
                useMarketBasedPrice,
                (useMarketBasedPrice ? marketPriceMargin : price.getValue()),
                buyerSecurityDepositAsDouble);

        long creationTime = new Date().getTime();
        NodeAddress makerAddress = p2PService.getAddress();
        boolean useMarketBasedPriceValue = useMarketBasedPrice &&
                isMarketPriceAvailable(currencyCode) &&
                !paymentAccount.isHalCashAccount();

        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) :
{'fraction_non_alphanumeric': 0.12644553701267225, 'fraction_numerical': 0.00290838584585555, 'mean_word_length': 1.725934314835787, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 20, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1215180', 'n_tokens_mistral': 3610, 'n_tokens_neox': 3446, 'n_words': 804}