Move mining fee payment to taker. Refactor package io.bitsquare.pricefeed to io.bitsquare.provider.price. Rename option priceFeedProviders to providers

This commit is contained in:
Manfred Karrer 2016-12-05 17:25:50 +01:00
parent d5817020a6
commit 963086106f
65 changed files with 636 additions and 281 deletions

View file

@ -2,5 +2,5 @@ package io.bitsquare.app;
public class DevFlags {
public static final boolean STRESS_TEST_MODE = false;
public static final boolean DEV_MODE = STRESS_TEST_MODE || true;
public static final boolean DEV_MODE = STRESS_TEST_MODE || false;
}

View file

@ -7,7 +7,7 @@ public class AppOptionKeys {
public static final String APP_NAME_KEY = "appName";
public static final String APP_DATA_DIR_KEY = "appDataDir";
public static final String MAX_MEMORY = "maxMemory";
public static final String PRICE_FEED_PROVIDERS = "priceFeedProviders";
public static final String PROVIDERS = "providers";
public static final String BTC_NODES = "btcNodes";
public static final String USE_TOR_FOR_BTC = "useTorForBtc";
}

View file

@ -77,7 +77,7 @@ public class BitsquareEnvironment extends StandardEnvironment {
private final String userDataDir;
private final String appDataDir;
private final String btcNetworkDir;
private final String logLevel, priceFeedProviders;
private final String logLevel, providers;
private BitcoinNetwork bitcoinNetwork;
private final String btcNodes, seedNodes, ignoreDevMsg, useTorForBtc,
myAddress, banList, dumpStatistics, maxMemory, socks5ProxyBtcAddress, socks5ProxyHttpAddress;
@ -145,8 +145,8 @@ public class BitsquareEnvironment extends StandardEnvironment {
maxMemory = commandLineProperties.containsProperty(AppOptionKeys.MAX_MEMORY) ?
(String) commandLineProperties.getProperty(AppOptionKeys.MAX_MEMORY) :
"";
priceFeedProviders = commandLineProperties.containsProperty(AppOptionKeys.PRICE_FEED_PROVIDERS) ?
(String) commandLineProperties.getProperty(AppOptionKeys.PRICE_FEED_PROVIDERS) :
providers = commandLineProperties.containsProperty(AppOptionKeys.PROVIDERS) ?
(String) commandLineProperties.getProperty(AppOptionKeys.PROVIDERS) :
"";
seedNodes = commandLineProperties.containsProperty(NetworkOptionKeys.SEED_NODES_KEY) ?
@ -244,7 +244,7 @@ public class BitsquareEnvironment extends StandardEnvironment {
setProperty(AppOptionKeys.APP_NAME_KEY, appName);
setProperty(AppOptionKeys.MAX_MEMORY, maxMemory);
setProperty(AppOptionKeys.USER_DATA_DIR_KEY, userDataDir);
setProperty(AppOptionKeys.PRICE_FEED_PROVIDERS, priceFeedProviders);
setProperty(AppOptionKeys.PROVIDERS, providers);
setProperty(AppOptionKeys.BTC_NODES, btcNodes);
setProperty(AppOptionKeys.USE_TOR_FOR_BTC, useTorForBtc);

View file

@ -109,7 +109,7 @@ public abstract class BitsquareExecutable {
parser.accepts(AppOptionKeys.DUMP_STATISTICS, description("If set to true the trade statistics are stored as json file in the data dir.", false))
.withRequiredArg()
.ofType(boolean.class);
parser.accepts(AppOptionKeys.PRICE_FEED_PROVIDERS, description("Custom price feed providers (comma separated)", false))
parser.accepts(AppOptionKeys.PROVIDERS, description("Custom providers (comma separated)", false))
.withRequiredArg();
parser.accepts(BtcOptionKeys.BTC_NETWORK, description("Bitcoin network", BitcoinNetwork.DEFAULT))

View file

@ -21,10 +21,9 @@ import com.google.inject.Singleton;
import io.bitsquare.app.AppModule;
import io.bitsquare.app.AppOptionKeys;
import io.bitsquare.btc.blockchain.BlockchainService;
import io.bitsquare.btc.blockchain.providers.BlockTrailProvider;
import io.bitsquare.btc.blockchain.providers.BlockrIOProvider;
import io.bitsquare.btc.blockchain.providers.TradeBlockProvider;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.http.HttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
@ -54,7 +53,7 @@ public class BitcoinModule extends AppModule {
bindConstant().annotatedWith(named(AppOptionKeys.BTC_NODES)).to(env.getRequiredProperty(AppOptionKeys.BTC_NODES));
bindConstant().annotatedWith(named(AppOptionKeys.USE_TOR_FOR_BTC)).to(env.getRequiredProperty(AppOptionKeys.USE_TOR_FOR_BTC));
bindConstant().annotatedWith(named(AppOptionKeys.PRICE_FEED_PROVIDERS)).to(env.getRequiredProperty(AppOptionKeys.PRICE_FEED_PROVIDERS));
bindConstant().annotatedWith(named(AppOptionKeys.PROVIDERS)).to(env.getRequiredProperty(AppOptionKeys.PROVIDERS));
bind(AddressEntryList.class).in(Singleton.class);
bind(TradeWalletService.class).in(Singleton.class);
@ -63,11 +62,8 @@ public class BitcoinModule extends AppModule {
bind(PriceFeedService.class).in(Singleton.class);
bind(BlockrIOProvider.class).in(Singleton.class);
bind(BlockTrailProvider.class).in(Singleton.class);
bind(TradeBlockProvider.class).in(Singleton.class);
bind(FeeService.class).in(Singleton.class);
bind(HttpClient.class).in(Singleton.class);
}
}

View file

@ -28,6 +28,7 @@ public class FeePolicy {
// http://www.cointape.com
// http://p2sh.info/dashboard/db/fee-estimation
// https://bitcoinfees.github.io/#1d
// https://estimatefee.appspot.com/
// Average values are 10-100 satoshis/byte in january 2016
//
// Our trade transactions have a fixed set of inputs and outputs making the size very predictable
@ -49,7 +50,7 @@ public class FeePolicy {
// The BitcoinJ fee calculation use kb so a tx size < 1kb will still pay the fee for a kb tx.
// Our payout tx has about 370 bytes so we get a fee/kb value of about 90 satoshi/byte making it high priority
// Other payout transactions (E.g. arbitrators many collected transactions) will go with 30 satoshi/byte if > 1kb
private static Coin NON_TRADE_FEE_PER_KB = DevFlags.STRESS_TEST_MODE ? Coin.valueOf(5_000) : Coin.valueOf(20_000); // 0.0002 BTC about 0.08 EUR @ 400 EUR/BTC
private static Coin NON_TRADE_FEE_PER_KB = Coin.valueOf(40_000); // 0.0004 BTC about 0.16 EUR @ 400 EUR/BTC
public static void setNonTradeFeePerKb(Coin nonTradeFeePerKb) {
NON_TRADE_FEE_PER_KB = nonTradeFeePerKb;
@ -59,18 +60,6 @@ public class FeePolicy {
return NON_TRADE_FEE_PER_KB;
}
// 0.0005 BTC 0.05% of 1 BTC about 0.2 EUR @ 400 EUR/BTC
public static Coin getCreateOfferFee() {
// We need to pay the quite high miner fee of 30_000 from the trading fee tx so 30_000 us our lower limit
// The arbitrator receive only 0.0002 BTC - less than the miners
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(10_000) : Coin.valueOf(50_000);
}
// 0.001 BTC 0.1% of 1 BTC about 0.4 EUR @ 400 EUR/BTC
public static Coin getTakeOfferFee() {
return DevFlags.STRESS_TEST_MODE ? Coin.valueOf(10_000) : Coin.valueOf(100_000);
}
// TODO will be increased once we get higher limits
// 0.01 BTC; about 4 EUR @ 400 EUR/BTC

View file

@ -1,57 +0,0 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc;
import com.google.inject.Inject;
import org.bitcoinj.core.Coin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FeeService {
private static final Logger log = LoggerFactory.getLogger(FeeService.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public FeeService() {
}
int counter = 0;
public Coin getTxFee() {
counter += 100;
// log.error("getTxFee " + (20_000 + counter));
//return Coin.valueOf(20_000 + counter);
return Coin.valueOf(20_000);
}
public Coin getTxFeeForWithdrawal() {
return Coin.valueOf(20_000);
}
public Coin getCreateOfferFee() {
return Coin.valueOf(50_000);
}
public Coin getTakeOfferFee() {
return Coin.valueOf(100_000);
}
}

View file

@ -145,10 +145,7 @@ public class TradeWalletService {
boolean useSavingsWallet, Coin tradingFee, Coin txFee, String feeReceiverAddresses)
throws InsufficientMoneyException, AddressFormatException {
Transaction tradingFeeTx = new Transaction(params);
Preconditions.checkArgument(Restrictions.isAboveFixedTxFeeForTradesAndDust(tradingFee, txFee),
"You cannot send an amount which are smaller than the fee + dust output.");
Coin outPutAmount = tradingFee.subtract(txFee);
tradingFeeTx.addOutput(outPutAmount, new Address(params, feeReceiverAddresses));
tradingFeeTx.addOutput(tradingFee, new Address(params, feeReceiverAddresses));
// the reserved amount we need for the trade we send to our trade reservedForTradeAddress
tradingFeeTx.addOutput(reservedFundsForOffer, reservedForTradeAddress);
@ -1123,12 +1120,12 @@ public class TradeWalletService {
}
private static void printTxWithInputs(String tracePrefix, Transaction tx) {
log.trace(tracePrefix + ": " + tx.toString());
log.info(tracePrefix + ": " + tx.toString());
for (TransactionInput input : tx.getInputs()) {
if (input.getConnectedOutput() != null)
log.trace(tracePrefix + " input value: " + input.getConnectedOutput().getValue().toFriendlyString());
log.info(tracePrefix + " input value: " + input.getConnectedOutput().getValue().toFriendlyString());
else
log.trace(tracePrefix + ": Transaction already has inputs but we don't have the connected outputs, so we don't know the value.");
log.info(tracePrefix + ": Transaction already has inputs but we don't have the connected outputs, so we don't know the value.");
}
}

View file

@ -1,26 +1,14 @@
package io.bitsquare.btc.blockchain;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.SettableFuture;
import com.google.inject.Inject;
import io.bitsquare.app.Log;
import io.bitsquare.btc.blockchain.providers.BlockTrailProvider;
import io.bitsquare.btc.blockchain.providers.BlockchainTxProvider;
import io.bitsquare.btc.blockchain.providers.BlockrIOProvider;
import io.bitsquare.btc.blockchain.providers.TradeBlockProvider;
import org.bitcoinj.core.Coin;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
public class BlockchainService {
private static final Logger log = LoggerFactory.getLogger(BlockchainService.class);
private final ArrayList<BlockchainTxProvider> blockchainTxProviders;
// Once needed will be moved to Providers so we stick with out hidden service routing
/*private final ArrayList<BlockchainTxProvider> blockchainTxProviders;
@Inject
public BlockchainService(BlockrIOProvider blockrIOProvider, BlockTrailProvider blockTrailProvider, TradeBlockProvider tradeBlockProvider) {
@ -33,8 +21,8 @@ public class BlockchainService {
final SettableFuture<Coin> resultFuture = SettableFuture.create();
for (BlockchainTxProvider provider : blockchainTxProviders) {
GetFeeRequest getFeeRequest = new GetFeeRequest();
SettableFuture<Coin> future = getFeeRequest.request(transactionId, provider);
GetTransactionRequest getTransactionRequest = new GetTransactionRequest();
SettableFuture<Coin> future = getTransactionRequest.request(transactionId, provider);
Futures.addCallback(future, new FutureCallback<Coin>() {
public void onSuccess(Coin fee) {
if (!resultFuture.isDone()) {
@ -52,5 +40,5 @@ public class BlockchainService {
});
}
return resultFuture;
}
}*/
}

View file

@ -13,13 +13,13 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
class GetFeeRequest {
private static final Logger log = LoggerFactory.getLogger(GetFeeRequest.class);
class GetTransactionRequest {
private static final Logger log = LoggerFactory.getLogger(GetTransactionRequest.class);
private static final ListeningExecutorService executorService = Utilities.getListeningExecutorService("GetFeeRequest", 3, 5, 10 * 60);
private Timer timer;
private int faults;
public GetFeeRequest() {
public GetTransactionRequest() {
}
public SettableFuture<Coin> request(String transactionId, BlockchainTxProvider provider) {

View file

@ -1,6 +1,6 @@
package io.bitsquare.btc.blockchain.providers;
import io.bitsquare.btc.HttpClientProvider;
import io.bitsquare.btc.provider.HttpClientProvider;
import io.bitsquare.http.HttpClient;
import io.bitsquare.http.HttpException;
import org.bitcoinj.core.Coin;

View file

@ -1,7 +0,0 @@
package io.bitsquare.btc.pricefeed;
class PriceRequestException extends Exception {
public PriceRequestException(String message) {
super(message);
}
}

View file

@ -1,4 +1,4 @@
package io.bitsquare.btc;
package io.bitsquare.btc.provider;
import io.bitsquare.http.HttpClient;

View file

@ -0,0 +1,62 @@
package io.bitsquare.btc.provider;
import com.google.inject.Inject;
import io.bitsquare.app.AppOptionKeys;
import io.bitsquare.network.NetworkOptionKeys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Named;
import java.util.Random;
public class ProvidersRepository {
private static final Logger log = LoggerFactory.getLogger(ProvidersRepository.class);
private final String[] providerArray;
private String baseUrl;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public ProvidersRepository(@Named(AppOptionKeys.PROVIDERS) String providers,
@Named(NetworkOptionKeys.USE_LOCALHOST) boolean useLocalhost) {
if (providers.isEmpty()) {
if (useLocalhost) {
// If we run in localhost mode we don't have the tor node running, so we need a clearnet host
// providers = "http://95.85.11.205:8080/";
// Use localhost for using a locally running priceprovider
providers = "http://localhost:8080/, http://95.85.11.205:8080/";
//providers = "http://localhost:8080/";
} else {
providers = "http://t4wlzy7l6k4hnolg.onion/, http://g27szt7aw2vrtowe.onion/";
}
}
providerArray = providers.replace(" ", "").split(",");
int index = new Random().nextInt(providerArray.length);
baseUrl = providerArray[index];
log.info("baseUrl for PriceFeedService: " + baseUrl);
}
public String getBaseUrl() {
return baseUrl;
}
public boolean hasMoreProviders() {
return providerArray.length > 1;
}
public void setNewRandomBaseUrl() {
String newBaseUrl;
do {
int index = new Random().nextInt(providerArray.length);
newBaseUrl = providerArray[index];
}
while (baseUrl.equals(newBaseUrl));
baseUrl = newBaseUrl;
log.info("Try new baseUrl after error: " + baseUrl);
}
}

View file

@ -0,0 +1,18 @@
package io.bitsquare.btc.provider.fee;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FeeData {
private static final Logger log = LoggerFactory.getLogger(FeeData.class);
public final long txFee;
public final long createOfferFee;
public final long takeOfferFee;
public FeeData(long txFee, long createOfferFee, long takeOfferFee) {
this.txFee = txFee;
this.createOfferFee = createOfferFee;
this.takeOfferFee = takeOfferFee;
}
}

View file

@ -0,0 +1,43 @@
package io.bitsquare.btc.provider.fee;
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import io.bitsquare.app.Version;
import io.bitsquare.btc.provider.HttpClientProvider;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.http.HttpClient;
import io.bitsquare.http.HttpException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class FeeProvider extends HttpClientProvider {
private static final Logger log = LoggerFactory.getLogger(FeeProvider.class);
private final String uid;
public FeeProvider(HttpClient httpClient, String baseUrl) {
super(httpClient, baseUrl, false);
uid = UUID.randomUUID().toString();
}
public Tuple2<Map<String, Long>, FeeData> getFees() throws IOException, HttpException {
String json = httpClient.requestWithGET("getFees", "User-Agent", "Bitsquare/" + Version.VERSION + ", uid:" + uid);
LinkedTreeMap<String, Object> linkedTreeMap = new Gson().fromJson(json, LinkedTreeMap.class);
Map<String, Long> tsMap = new HashMap<>();
tsMap.put("bitcoinFeesTs", ((Double) linkedTreeMap.get("bitcoinFeesTs")).longValue());
LinkedTreeMap<String, Double> dataMap = (LinkedTreeMap<String, Double>) linkedTreeMap.get("data");
FeeData feeData = new FeeData(dataMap.get("txFee").longValue(), dataMap.get("createOfferFee").longValue(), dataMap.get("takeOfferFee").longValue());
return new Tuple2<>(tsMap, feeData);
}
@Override
public String toString() {
return "FeeProvider";
}
}

View file

@ -0,0 +1,40 @@
package io.bitsquare.btc.provider.fee;
import com.google.common.util.concurrent.*;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.common.util.Utilities;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
public class FeeRequest {
private static final Logger log = LoggerFactory.getLogger(FeeRequest.class);
private static final ListeningExecutorService executorService = Utilities.getListeningExecutorService("FeeRequest", 3, 5, 10 * 60);
public FeeRequest() {
}
public SettableFuture<Tuple2<Map<String, Long>, FeeData>> getFees(FeeProvider provider) {
final SettableFuture<Tuple2<Map<String, Long>, FeeData>> resultFuture = SettableFuture.create();
ListenableFuture<Tuple2<Map<String, Long>, FeeData>> future = executorService.submit(() -> {
Thread.currentThread().setName("FeeRequest-" + provider.toString());
return provider.getFees();
});
Futures.addCallback(future, new FutureCallback<Tuple2<Map<String, Long>, FeeData>>() {
public void onSuccess(Tuple2<Map<String, Long>, FeeData> feeData) {
log.debug("Received feeData of {}\nfrom provider {}", feeData, provider);
resultFuture.set(feeData);
}
public void onFailure(@NotNull Throwable throwable) {
resultFuture.setException(throwable);
}
});
return resultFuture;
}
}

View file

@ -0,0 +1,126 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.btc.provider.fee;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.SettableFuture;
import com.google.inject.Inject;
import io.bitsquare.app.Log;
import io.bitsquare.btc.provider.ProvidersRepository;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.FaultHandler;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.http.HttpClient;
import org.bitcoinj.core.Coin;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.Map;
import static com.google.common.base.Preconditions.checkNotNull;
public class FeeService {
private static final Logger log = LoggerFactory.getLogger(FeeService.class);
public static final long MIN_TX_FEE = 40; // satoshi/byte
public static final long MAX_TX_FEE = 200;
public static final long DEFAULT_TX_FEE = 60;
public static final long MIN_CREATE_OFFER_FEE = 50_000;
public static final long MAX_CREATE_OFFER_FEE = 500_000;
public static final long DEFAULT_CREATE_OFFER_FEE = 50_000;
public static final long MIN_TAKE_OFFER_FEE = 100_000;
public static final long MAX_TAKE_OFFER_FEE = 1000_000;
public static final long DEFAULT_TAKE_OFFER_FEE = 100_000;
private final FeeProvider feeProvider;
private final ProvidersRepository providersRepository;
private final HttpClient httpClient;
private FeeData feeData;
private Map<String, Long> timeStampMap;
private long epochInSecondAtLastRequest;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public FeeService(HttpClient httpClient,
ProvidersRepository providersRepository) {
this.httpClient = httpClient;
this.providersRepository = providersRepository;
this.feeProvider = new FeeProvider(httpClient, providersRepository.getBaseUrl());
feeData = new FeeData(DEFAULT_TX_FEE, DEFAULT_CREATE_OFFER_FEE, DEFAULT_TAKE_OFFER_FEE);
}
public void onAllServicesInitialized() {
requestFees(null, null);
}
public void requestFees(@Nullable Runnable resultHandler, @Nullable FaultHandler faultHandler) {
//TODO add throttle
Log.traceCall();
FeeRequest feeRequest = new FeeRequest();
SettableFuture<Tuple2<Map<String, Long>, FeeData>> future = feeRequest.getFees(feeProvider);
Futures.addCallback(future, new FutureCallback<Tuple2<Map<String, Long>, FeeData>>() {
@Override
public void onSuccess(@Nullable Tuple2<Map<String, Long>, FeeData> result) {
UserThread.execute(() -> {
checkNotNull(result, "Result must not be null at getFees");
timeStampMap = result.first;
epochInSecondAtLastRequest = timeStampMap.get("bitcoinFeesTs");
feeData = result.second;
if (resultHandler != null)
resultHandler.run();
});
}
@Override
public void onFailure(@NotNull Throwable throwable) {
log.warn("Could not load fees. " + throwable.toString());
if (faultHandler != null)
UserThread.execute(() -> faultHandler.handleFault("Could not load fees", throwable));
}
});
}
public Coin getTxFee() {
// feeData.txFee is sat/byte but we want satoshi / kb
log.debug("getTxFee " + (feeData.txFee * 1000));
return Coin.valueOf(feeData.txFee * 1000);
}
// TODO needed?
public Coin getTxFeeForWithdrawal() {
return getTxFee();
}
public Coin getCreateOfferFee() {
return Coin.valueOf(feeData.createOfferFee);
}
public Coin getTakeOfferFee() {
return Coin.valueOf(feeData.takeOfferFee);
}
}

View file

@ -1,4 +1,4 @@
package io.bitsquare.btc.pricefeed;
package io.bitsquare.btc.provider.price;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View file

@ -1,22 +1,20 @@
package io.bitsquare.btc.pricefeed;
package io.bitsquare.btc.provider.price;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.SettableFuture;
import com.google.inject.Inject;
import io.bitsquare.app.AppOptionKeys;
import io.bitsquare.app.Log;
import io.bitsquare.btc.provider.ProvidersRepository;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.FaultHandler;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.http.HttpClient;
import io.bitsquare.network.NetworkOptionKeys;
import javafx.beans.property.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import javax.inject.Named;
import java.time.Instant;
import java.util.Date;
import java.util.HashMap;
@ -28,7 +26,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class PriceFeedService {
private static final Logger log = LoggerFactory.getLogger(PriceFeedService.class);
private HttpClient httpClient;
private final HttpClient httpClient;
private final ProvidersRepository providersRepository;
///////////////////////////////////////////////////////////////////////////////////////////
@ -60,8 +60,6 @@ public class PriceFeedService {
private final IntegerProperty currenciesUpdateFlag = new SimpleIntegerProperty(0);
private long epochInSecondAtLastRequest;
private Map<String, Long> timeStampMap = new HashMap<>();
private String baseUrl;
private final String[] priceFeedProviderArray;
///////////////////////////////////////////////////////////////////////////////////////////
@ -69,26 +67,10 @@ public class PriceFeedService {
///////////////////////////////////////////////////////////////////////////////////////////
@Inject
public PriceFeedService(HttpClient httpClient,
@Named(AppOptionKeys.PRICE_FEED_PROVIDERS) String priceFeedProviders,
@Named(NetworkOptionKeys.USE_LOCALHOST) boolean useLocalhost) {
public PriceFeedService(HttpClient httpClient, ProvidersRepository providersRepository) {
this.httpClient = httpClient;
if (priceFeedProviders.isEmpty()) {
if (useLocalhost) {
// If we run in localhost mode we don't have the tor node running, so we need a clearnet host
priceFeedProviders = "http://95.85.11.205:8080/";
// Use localhost for using a locally running priceprovider
// priceFeedProviders = "http://localhost:8080/";
} else {
priceFeedProviders = "http://t4wlzy7l6k4hnolg.onion/, http://g27szt7aw2vrtowe.onion/";
}
}
priceFeedProviderArray = priceFeedProviders.replace(" ", "").split(",");
int index = new Random().nextInt(priceFeedProviderArray.length);
baseUrl = priceFeedProviderArray[index];
log.info("baseUrl for PriceFeedService: " + baseUrl);
this.priceProvider = new PriceProvider(httpClient, baseUrl);
this.providersRepository = providersRepository;
this.priceProvider = new PriceProvider(httpClient, providersRepository.getBaseUrl());
}
@ -112,19 +94,9 @@ public class PriceFeedService {
}, (errorMessage, throwable) -> {
// Try other provider if more then 1 is available
if (priceFeedProviderArray.length > 1) {
String newBaseUrl;
do {
int index = new Random().nextInt(priceFeedProviderArray.length);
log.error(index + "");
newBaseUrl = priceFeedProviderArray[index];
log.error(newBaseUrl);
}
while (baseUrl.equals(newBaseUrl));
baseUrl = newBaseUrl;
log.info("Try new baseUrl after error: " + baseUrl);
this.priceProvider = new PriceProvider(httpClient, baseUrl);
if (providersRepository.hasMoreProviders()) {
providersRepository.setNewRandomBaseUrl();
priceProvider = new PriceProvider(httpClient, providersRepository.getBaseUrl());
request();
} else {
UserThread.runAfter(this::request, 120);

View file

@ -1,9 +1,9 @@
package io.bitsquare.btc.pricefeed;
package io.bitsquare.btc.provider.price;
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import io.bitsquare.app.Version;
import io.bitsquare.btc.HttpClientProvider;
import io.bitsquare.btc.provider.HttpClientProvider;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.http.HttpClient;
import io.bitsquare.http.HttpException;
@ -25,7 +25,7 @@ public class PriceProvider extends HttpClientProvider {
public Tuple2<Map<String, Long>, Map<String, MarketPrice>> getAll() throws IOException, HttpException {
Map<String, MarketPrice> marketPriceMap = new HashMap<>();
String json = httpClient.requestWithGET("all", "User-Agent", "Bitsquare/" + Version.VERSION + ", uid:" + uid);
String json = httpClient.requestWithGET("getAllMarketPrices", "User-Agent", "Bitsquare/" + Version.VERSION + ", uid:" + uid);
LinkedTreeMap<String, Object> map = new Gson().fromJson(json, LinkedTreeMap.class);
Map<String, Long> tsMap = new HashMap<>();
tsMap.put("btcAverageTs", ((Double) map.get("btcAverageTs")).longValue());

View file

@ -1,4 +1,4 @@
package io.bitsquare.btc.pricefeed;
package io.bitsquare.btc.provider.price;
import com.google.common.util.concurrent.*;
import io.bitsquare.common.util.Tuple2;
@ -9,7 +9,7 @@ import org.slf4j.LoggerFactory;
import java.util.Map;
class PriceRequest {
public class PriceRequest {
private static final Logger log = LoggerFactory.getLogger(PriceRequest.class);
private static final ListeningExecutorService executorService = Utilities.getListeningExecutorService("PriceRequest", 3, 5, 10 * 60);

View file

@ -0,0 +1,7 @@
package io.bitsquare.btc.provider.price;
public class PriceRequestException extends Exception {
public PriceRequestException(String message) {
super(message);
}
}

View file

@ -132,6 +132,7 @@ public class CurrencyUtil {
result.add(new CryptoCurrency("HODL", "HOdlcoin"));
result.add(new CryptoCurrency("HNC", "HunCoin"));
result.add(new CryptoCurrency("IOC", "I/O Coin"));
result.add(new CryptoCurrency("IOP", "Fermat"));
result.add(new CryptoCurrency("JPYT", "JPY Tether"));
result.add(new CryptoCurrency("JBS", "Jumbucks"));
result.add(new CryptoCurrency("LBC", "LBRY Credits"));

View file

@ -24,7 +24,7 @@ import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.AddressEntryException;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.common.handlers.ErrorMessageHandler;

View file

@ -18,7 +18,7 @@
package io.bitsquare.trade.closed;
import com.google.inject.Inject;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.storage.Storage;
import io.bitsquare.trade.Tradable;

View file

@ -18,7 +18,7 @@
package io.bitsquare.trade.failed;
import com.google.inject.Inject;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.storage.Storage;
import io.bitsquare.trade.TradableList;

View file

@ -20,8 +20,8 @@ package io.bitsquare.trade.offer;
import io.bitsquare.app.DevFlags;
import io.bitsquare.app.Version;
import io.bitsquare.btc.Restrictions;
import io.bitsquare.btc.pricefeed.MarketPrice;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.MarketPrice;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.common.crypto.PubKeyRing;
import io.bitsquare.common.handlers.ErrorMessageHandler;

View file

@ -19,7 +19,7 @@ package io.bitsquare.trade.offer;
import com.google.inject.name.Named;
import io.bitsquare.app.AppOptionKeys;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;

View file

@ -23,7 +23,7 @@ import io.bitsquare.app.Log;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.Timer;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.crypto.KeyRing;

View file

@ -19,7 +19,6 @@ package io.bitsquare.trade.protocol.placeoffer.tasks;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletService;
import io.bitsquare.common.taskrunner.Task;
import io.bitsquare.common.taskrunner.TaskRunner;
@ -56,7 +55,7 @@ public class CreateOfferFeeTx extends Task<PlaceOfferModel> {
walletService.getOrCreateAddressEntry(AddressEntry.Context.AVAILABLE).getAddress(),
model.reservedFundsForOffer,
model.useSavingsWallet,
FeePolicy.getCreateOfferFee(),
model.offer.getCreateOfferFee(),
model.offer.getTxFee(),
selectedArbitrator.getBtcAddress());

View file

@ -28,7 +28,7 @@ public class RestrictionsTest {
@Test
public void testIsMinSpendableAmount() {
Coin amount = null;
Coin txFee = new FeeService().getTxFee();
Coin txFee = Coin.valueOf(20000);
assertFalse("tx unfunded, pending", Restrictions.isAboveFixedTxFeeForTradesAndDust(amount, txFee));
amount = Coin.ZERO;

View file

@ -1,22 +1,14 @@
package io.bitsquare.btc.blockchain;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.SettableFuture;
import org.bitcoinj.core.Coin;
import org.jetbrains.annotations.NotNull;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static junit.framework.TestCase.assertTrue;
@Ignore
public class BlockchainServiceTest {
private static final Logger log = LoggerFactory.getLogger(BlockchainServiceTest.class);
@Test
/* @Test
public void testGetFee() throws InterruptedException {
BlockchainService blockchainService = new BlockchainService(null, null, null);
@ -35,5 +27,5 @@ public class BlockchainServiceTest {
}
});
Thread.sleep(5000);
}
}*/
}

View file

@ -1,5 +1,6 @@
package io.bitsquare.btc.pricefeed;
import io.bitsquare.btc.provider.price.PriceFeedService;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
@ -13,7 +14,7 @@ public class MarketPriceFeedServiceTest {
@Test
public void testGetPrice() throws InterruptedException {
PriceFeedService priceFeedService = new PriceFeedService(null, null, true);
PriceFeedService priceFeedService = new PriceFeedService(null, null);
priceFeedService.setCurrencyCode("EUR");
priceFeedService.init(tradeCurrency -> {
log.debug(tradeCurrency.toString());

View file

@ -20,7 +20,7 @@ package io.bitsquare.gui.main;
import io.bitsquare.BitsquareException;
import io.bitsquare.app.BitsquareApp;
import io.bitsquare.app.DevFlags;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.common.util.Tuple3;

View file

@ -33,8 +33,9 @@ import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.pricefeed.MarketPrice;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.btc.provider.price.MarketPrice;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.Clock;
import io.bitsquare.common.Timer;
import io.bitsquare.common.UserThread;
@ -106,14 +107,15 @@ public class MainViewModel implements ViewModel {
private final DisputeManager disputeManager;
final Preferences preferences;
private final AlertManager alertManager;
private PrivateNotificationManager privateNotificationManager;
private FilterManager filterManager;
private final PrivateNotificationManager privateNotificationManager;
private final FilterManager filterManager;
private final WalletPasswordWindow walletPasswordWindow;
private AddBitcoinNodesWindow addBitcoinNodesWindow;
private final AddBitcoinNodesWindow addBitcoinNodesWindow;
private final NotificationCenter notificationCenter;
private final TacWindow tacWindow;
private Clock clock;
private KeyRing keyRing;
private final Clock clock;
private final FeeService feeService;
private final KeyRing keyRing;
private final Navigation navigation;
private final BSFormatter formatter;
@ -180,7 +182,7 @@ public class MainViewModel implements ViewModel {
OpenOfferManager openOfferManager, DisputeManager disputeManager, Preferences preferences,
User user, AlertManager alertManager, PrivateNotificationManager privateNotificationManager,
FilterManager filterManager, WalletPasswordWindow walletPasswordWindow, AddBitcoinNodesWindow addBitcoinNodesWindow,
NotificationCenter notificationCenter, TacWindow tacWindow, Clock clock,
NotificationCenter notificationCenter, TacWindow tacWindow, Clock clock, FeeService feeService,
KeyRing keyRing, Navigation navigation, BSFormatter formatter) {
this.priceFeedService = priceFeedService;
this.user = user;
@ -200,6 +202,7 @@ public class MainViewModel implements ViewModel {
this.notificationCenter = notificationCenter;
this.tacWindow = tacWindow;
this.clock = clock;
this.feeService = feeService;
this.keyRing = keyRing;
this.navigation = navigation;
this.formatter = formatter;
@ -560,6 +563,8 @@ public class MainViewModel implements ViewModel {
p2PService.onAllServicesInitialized();
feeService.onAllServicesInitialized();
setupBtcNumPeersWatcher();
setupP2PNumPeersWatcher();
updateBalance();

View file

@ -20,10 +20,10 @@ package io.bitsquare.gui.main.funds.deposit;
import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.app.DevFlags;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.FeeService;
import io.bitsquare.btc.Restrictions;
import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.gui.common.view.ActivatableView;

View file

@ -20,7 +20,6 @@ package io.bitsquare.gui.main.funds.transactions;
import com.googlecode.jcsv.writer.CSVEntryConverter;
import de.jensd.fx.fontawesome.AwesomeIcon;
import io.bitsquare.arbitration.DisputeManager;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.WalletService;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.common.util.Tuple4;
@ -596,13 +595,15 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
// TODO fee is dynamic now
Coin txFee = Coin.valueOf(20_000);
Coin createOfferFee = Coin.valueOf(50_000);
Coin takeOfferFee = Coin.valueOf(100_000);
if (!dataByDayMap.containsKey(day)) {
int numOffers = 0;
int numTrades = 0;
if (amountAsCoin.compareTo(FeePolicy.getCreateOfferFee().subtract(txFee)) == 0)
if (amountAsCoin.compareTo(createOfferFee.subtract(txFee)) == 0)
numOffers++;
else if (amountAsCoin.compareTo(FeePolicy.getTakeOfferFee().subtract(txFee)) == 0)
else if (amountAsCoin.compareTo(takeOfferFee.subtract(txFee)) == 0)
numTrades++;
dataByDayMap.put(day, new Tuple4<>(item.getDate(), 1, numOffers, numTrades));
@ -611,9 +612,9 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
int prev = tuple.second;
int numOffers = tuple.third;
int numTrades = tuple.forth;
if (amountAsCoin.compareTo(FeePolicy.getCreateOfferFee().subtract(txFee)) == 0)
if (amountAsCoin.compareTo(createOfferFee.subtract(txFee)) == 0)
numOffers++;
else if (amountAsCoin.compareTo(FeePolicy.getTakeOfferFee().subtract(txFee)) == 0)
else if (amountAsCoin.compareTo(takeOfferFee.subtract(txFee)) == 0)
numTrades++;
dataByDayMap.put(day, new Tuple4<>(tuple.first, ++prev, numOffers, numTrades));

View file

@ -19,7 +19,7 @@ package io.bitsquare.gui.main.market.offerbook;
import com.google.common.math.LongMath;
import com.google.inject.Inject;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.ActivatableViewModel;
import io.bitsquare.gui.main.MainView;

View file

@ -19,7 +19,7 @@ package io.bitsquare.gui.main.market.trades;
import com.google.common.annotations.VisibleForTesting;
import com.google.inject.Inject;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.util.MathUtils;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.ActivatableViewModel;

View file

@ -17,7 +17,7 @@
package io.bitsquare.gui.main.offer;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.common.view.ViewLoader;

View file

@ -17,7 +17,7 @@
package io.bitsquare.gui.main.offer;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.UserThread;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.view.ActivatableView;

View file

@ -17,7 +17,7 @@
package io.bitsquare.gui.main.offer;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.common.view.ViewLoader;

View file

@ -21,16 +21,21 @@ import com.google.inject.Inject;
import io.bitsquare.app.DevFlags;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.btc.*;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.blockchain.BlockchainService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.ActivatableDataModel;
import io.bitsquare.gui.main.offer.createoffer.monetary.Price;
import io.bitsquare.gui.main.offer.createoffer.monetary.Volume;
import io.bitsquare.gui.main.overlays.notifications.Notification;
import io.bitsquare.gui.main.overlays.popups.Popup;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.locale.TradeCurrency;
@ -68,14 +73,15 @@ class CreateOfferDataModel extends ActivatableDataModel {
private final P2PService p2PService;
private final PriceFeedService priceFeedService;
final String shortOfferId;
private Navigation navigation;
private final FeeService feeService;
private final Navigation navigation;
private final BlockchainService blockchainService;
private final BSFormatter formatter;
private final String offerId;
private final AddressEntry addressEntry;
private final Coin createOfferFeeAsCoin, takeOfferAsCoin;
private final Coin txFeeAsCoin;
private final Coin securityDepositAsCoin;
private Coin createOfferFeeAsCoin, takerFeeAsCoin;
private Coin txFeeAsCoin;
private Coin securityDepositAsCoin;
private final BalanceListener balanceListener;
private final SetChangeListener<PaymentAccount> paymentAccountsChangeListener;
@ -128,6 +134,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
this.keyRing = keyRing;
this.p2PService = p2PService;
this.priceFeedService = priceFeedService;
this.feeService = feeService;
this.navigation = navigation;
this.blockchainService = blockchainService;
this.formatter = formatter;
@ -137,11 +144,6 @@ class CreateOfferDataModel extends ActivatableDataModel {
offerId = UUID.randomUUID().toString();
shortOfferId = offerId.substring(0, Math.min(8, offerId.length()));
addressEntry = walletService.getOrCreateAddressEntry(offerId, AddressEntry.Context.OFFER_FUNDING);
createOfferFeeAsCoin = feeService.getCreateOfferFee();
takeOfferAsCoin = feeService.getTakeOfferFee();
txFeeAsCoin = feeService.getTxFee();
// TODO
securityDepositAsCoin = FeePolicy.getSecurityDeposit();
useMarketBasedPrice.set(preferences.getUsePercentageBasedPrice());
@ -182,6 +184,21 @@ class CreateOfferDataModel extends ActivatableDataModel {
addBindings();
addListeners();
feeService.requestFees(() -> {
//TODO update doubleTxFeeAsCoin and txFeeAsCoin in view with binding
createOfferFeeAsCoin = feeService.getCreateOfferFee();
takerFeeAsCoin = feeService.getTakeOfferFee();
txFeeAsCoin = feeService.getTxFee();
calculateTotalToPay();
}, (errorMessage, throwable) -> new Popup<>().warning(errorMessage).show());
createOfferFeeAsCoin = feeService.getCreateOfferFee();
takerFeeAsCoin = feeService.getTakeOfferFee();
txFeeAsCoin = feeService.getTxFee();
// TODO
securityDepositAsCoin = FeePolicy.getSecurityDeposit();
if (!preferences.getUseStickyMarketPrice() && isTabSelected)
priceFeedService.setCurrencyCode(tradeCurrencyCode.get());
@ -322,7 +339,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
Version.VERSION,
txFeeAsCoin.value,
createOfferFeeAsCoin.value,
takeOfferAsCoin.value,
takerFeeAsCoin.value,
securityDepositAsCoin.value,
maxTradeLimit,
maxTradePeriod,
@ -332,7 +349,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
}
void onPlaceOffer(Offer offer, TransactionResultHandler resultHandler) {
openOfferManager.placeOffer(offer, totalToPayAsCoin.get().subtract(createOfferFeeAsCoin), useSavingsWallet, resultHandler);
openOfferManager.placeOffer(offer, totalToPayAsCoin.get().subtract(txFeeAsCoin).subtract(createOfferFeeAsCoin), useSavingsWallet, resultHandler);
}
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
@ -486,9 +503,8 @@ class CreateOfferDataModel extends ActivatableDataModel {
// created the offer and reserved his funds, so that would not work well with dynamic fees.
// The mining fee for the createOfferFee tx is deducted from the createOfferFee and not visible to the trader
if (direction != null && amount.get() != null) {
Coin feeAndSecDeposit = createOfferFeeAsCoin.add(securityDepositAsCoin);
Coin feeAndSecDepositAndAmount = feeAndSecDeposit.add(amount.get());
Coin required = direction == Offer.Direction.BUY ? feeAndSecDeposit : feeAndSecDepositAndAmount;
Coin feeAndSecDeposit = createOfferFeeAsCoin.add(txFeeAsCoin).add(securityDepositAsCoin);
Coin required = direction == Offer.Direction.BUY ? feeAndSecDeposit : feeAndSecDeposit.add(amount.get());
totalToPayAsCoin.set(required);
log.debug("totalToPayAsCoin " + totalToPayAsCoin.get().toFriendlyString());
updateBalance();
@ -538,6 +554,10 @@ class CreateOfferDataModel extends ActivatableDataModel {
return createOfferFeeAsCoin;
}
public Coin getTxFeeAsCoin() {
return txFeeAsCoin;
}
public Coin getSecurityDepositAsCoin() {
return securityDepositAsCoin;
}

View file

@ -345,7 +345,8 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
"The amount is the sum of:\n" +
tradeAmountText +
"- Security deposit: " + model.getSecurityDeposit() + "\n" +
"- Trading fee: " + model.getOfferFee() + "\n\n" +
"- Trading fee: " + model.getOfferFee() + "\n" +
"- Mining fee: " + model.getTxFee() + "\n\n" +
"You can choose between two options when funding your trade:\n" +
"- Use your Bitsquare wallet (convenient, but transactions may be linkable) OR\n" +
@ -1078,6 +1079,7 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
addPayInfoEntry(infoGridPane, i++, BSResources.get("createOffer.fundsBox.securityDeposit"), model.getSecurityDeposit());
addPayInfoEntry(infoGridPane, i++, BSResources.get("createOffer.fundsBox.offerFee"), model.getOfferFee());
addPayInfoEntry(infoGridPane, i++, BSResources.get("createOffer.fundsBox.networkFee"), model.getTxFee());
Separator separator = new Separator();
separator.setOrientation(Orientation.HORIZONTAL);
separator.setStyle("-fx-background: #666;");

View file

@ -18,8 +18,8 @@
package io.bitsquare.gui.main.offer.createoffer;
import io.bitsquare.app.DevFlags;
import io.bitsquare.btc.pricefeed.MarketPrice;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.MarketPrice;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.Timer;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.MathUtils;
@ -663,6 +663,10 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
return formatter.formatCoinWithCode(dataModel.getCreateOfferFeeAsCoin());
}
public String getTxFee() {
return formatter.formatCoinWithCode(dataModel.getTxFeeAsCoin());
}
public String getSecurityDeposit() {
return formatter.formatCoinWithCode(dataModel.getSecurityDepositAsCoin());
}

View file

@ -18,7 +18,6 @@
package io.bitsquare.gui.main.offer.offerbook;
import io.bitsquare.alert.PrivateNotificationManager;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.view.ActivatableViewAndModel;
import io.bitsquare.gui.common.view.FxmlView;
@ -395,7 +394,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
String key = "RemoveOfferWarning";
if (model.preferences.showAgain(key))
new Popup().warning("Are you sure you want to remove that offer?\n" +
"The offer fee of " + model.formatter.formatCoinWithCode(FeePolicy.getCreateOfferFee()) +
"The offer fee of " + model.formatter.formatCoinWithCode(offer.getCreateOfferFee()) +
" will be lost if you remove that offer.")
.actionButtonText("Remove offer")
.onAction(() -> doRemoveOffer(offer))

View file

@ -20,7 +20,7 @@ package io.bitsquare.gui.main.offer.offerbook;
import com.google.common.base.Joiner;
import com.google.inject.Inject;
import io.bitsquare.app.Version;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.filter.FilterManager;

View file

@ -20,10 +20,14 @@ package io.bitsquare.gui.main.offer.takeoffer;
import com.google.inject.Inject;
import io.bitsquare.app.DevFlags;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.btc.*;
import io.bitsquare.btc.AddressEntry;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.blockchain.BlockchainService;
import io.bitsquare.btc.listeners.BalanceListener;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.gui.common.model.ActivatableDataModel;
import io.bitsquare.gui.main.overlays.notifications.Notification;
import io.bitsquare.gui.main.overlays.popups.Popup;
@ -59,15 +63,16 @@ class TakeOfferDataModel extends ActivatableDataModel {
final TradeWalletService tradeWalletService;
final WalletService walletService;
private final User user;
private final FeeService feeService;
private final Preferences preferences;
private final PriceFeedService priceFeedService;
private final BlockchainService blockchainService;
private final BSFormatter formatter;
private Coin takerFeeAsCoin;
private final Coin txFeeAsCoin;
private final Coin doubleTxFeeAsCoin;
private final Coin securityDepositAsCoin;
private Coin txFeeAsCoin;
private Coin totalTxFeeAsCoin;
private Coin securityDepositAsCoin;
// Coin feeFromFundingTx = Coin.NEGATIVE_SATOSHI;
private Offer offer;
@ -106,19 +111,12 @@ class TakeOfferDataModel extends ActivatableDataModel {
this.tradeWalletService = tradeWalletService;
this.walletService = walletService;
this.user = user;
this.feeService = feeService;
this.preferences = preferences;
this.priceFeedService = priceFeedService;
this.blockchainService = blockchainService;
this.formatter = formatter;
// Taker pays 2 times the tx fee because the mining fee might be different when offerer created the offer
// and reserved his funds, so that would not work well with dynamic fees.
// The mining fee for the takeOfferFee tx is deducted from the createOfferFee and not visible to the trader
txFeeAsCoin = feeService.getTxFee();
doubleTxFeeAsCoin = txFeeAsCoin.add(txFeeAsCoin);
//TODO
securityDepositAsCoin = FeePolicy.getSecurityDeposit();
// isMainNet.set(preferences.getBitcoinNetwork() == BitcoinNetwork.MAINNET);
}
@ -177,6 +175,24 @@ class TakeOfferDataModel extends ActivatableDataModel {
if (DevFlags.DEV_MODE)
amountAsCoin.set(offer.getAmount());
// Taker pays 2 times the tx fee because the mining fee might be different when offerer created the offer
// and reserved his funds, so that would not work well with dynamic fees.
// The mining fee for the takeOfferFee tx is deducted from the createOfferFee and not visible to the trader
feeService.requestFees(() -> {
//TODO update doubleTxFeeAsCoin and txFeeAsCoin in view with binding
takerFeeAsCoin = feeService.getTakeOfferFee();
txFeeAsCoin = feeService.getTxFee();
totalTxFeeAsCoin = txFeeAsCoin.multiply(3);
calculateTotalToPay();
}, (errorMessage, throwable) -> new Popup<>().warning(errorMessage).show());
takerFeeAsCoin = feeService.getTakeOfferFee();
txFeeAsCoin = feeService.getTxFee();
totalTxFeeAsCoin = txFeeAsCoin.multiply(3);
//TODO
securityDepositAsCoin = FeePolicy.getSecurityDeposit();
calculateVolume();
calculateTotalToPay();
@ -236,7 +252,7 @@ class TakeOfferDataModel extends ActivatableDataModel {
txFeeAsCoin,
takerFeeAsCoin,
tradePrice.getValue(),
totalToPayAsCoin.get().subtract(takerFeeAsCoin),
totalToPayAsCoin.get().subtract(takerFeeAsCoin).subtract(txFeeAsCoin),
offer,
paymentAccount.getId(),
useSavingsWallet,
@ -327,7 +343,7 @@ class TakeOfferDataModel extends ActivatableDataModel {
// and reserved his funds, so that would not work well with dynamic fees.
// The mining fee for the takeOfferFee tx is deducted from the createOfferFee and not visible to the trader
if (offer != null && amountAsCoin.get() != null) {
Coin value = takerFeeAsCoin.add(doubleTxFeeAsCoin).add(securityDepositAsCoin);
Coin value = takerFeeAsCoin.add(totalTxFeeAsCoin).add(securityDepositAsCoin);
if (getDirection() == Offer.Direction.SELL)
totalToPayAsCoin.set(value);
else
@ -403,7 +419,7 @@ class TakeOfferDataModel extends ActivatableDataModel {
//noinspection SimplifiableIfStatement
if (amountAsCoin.get() != null && offer != null) {
Coin customAmount = offer.getAmount().subtract(amountAsCoin.get());
Coin dustAndFee = doubleTxFeeAsCoin.add(Transaction.MIN_NONDUST_OUTPUT);
Coin dustAndFee = totalTxFeeAsCoin.add(Transaction.MIN_NONDUST_OUTPUT);
return customAmount.isPositive() && customAmount.isLessThan(dustAndFee);
} else {
return true;
@ -430,8 +446,8 @@ class TakeOfferDataModel extends ActivatableDataModel {
return takerFeeAsCoin;
}
public Coin getTxFeeAsCoin() {
return doubleTxFeeAsCoin;
public Coin getTotalTxFeeAsCoin() {
return totalTxFeeAsCoin;
}
public AddressEntry getAddressEntry() {

View file

@ -18,7 +18,7 @@
package io.bitsquare.gui.main.offer.takeoffer;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.model.ActivatableWithDataModel;
import io.bitsquare.gui.common.model.ViewModel;
@ -578,7 +578,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
}
String getNetworkFee() {
return formatter.formatCoinWithCode(dataModel.getTxFeeAsCoin());
return formatter.formatCoinWithCode(dataModel.getTotalTxFeeAsCoin());
}
public String getSecurityDeposit() {

View file

@ -18,7 +18,7 @@
package io.bitsquare.gui.main.portfolio.openoffer;
import com.google.inject.Inject;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.ResultHandler;
import io.bitsquare.gui.common.model.ActivatableDataModel;

View file

@ -17,7 +17,6 @@
package io.bitsquare.gui.main.portfolio.openoffer;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.gui.Navigation;
import io.bitsquare.gui.common.view.ActivatableViewAndModel;
import io.bitsquare.gui.common.view.FxmlView;
@ -112,7 +111,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
String key = "RemoveOfferWarning";
if (preferences.showAgain(key))
new Popup().warning("Are you sure you want to remove that offer?\n" +
"The offer fee of " + model.formatter.formatCoinWithCode(FeePolicy.getCreateOfferFee()) + " will be lost if you remove that offer.")
"The offer fee of " + model.formatter.formatCoinWithCode(openOffer.getOffer().getCreateOfferFee()) + " will be lost if you remove that offer.")
.actionButtonText("Remove offer")
.onAction(() -> doRemoveOpenOffer(openOffer))
.closeButtonText("Don't remove the offer")

View file

@ -22,10 +22,9 @@ import io.bitsquare.app.Log;
import io.bitsquare.arbitration.Arbitrator;
import io.bitsquare.arbitration.Dispute;
import io.bitsquare.arbitration.DisputeManager;
import io.bitsquare.btc.FeePolicy;
import io.bitsquare.btc.FeeService;
import io.bitsquare.btc.TradeWalletService;
import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.common.crypto.KeyRing;
import io.bitsquare.common.handlers.ErrorMessageHandler;
import io.bitsquare.common.handlers.FaultHandler;
@ -218,7 +217,18 @@ public class PendingTradesDataModel extends ActivatableDataModel {
}
Coin getTotalFees() {
return feeService.getTxFee().add(isOfferer() ? FeePolicy.getCreateOfferFee() : FeePolicy.getTakeOfferFee());
Trade trade = getTrade();
if (trade != null) {
if (isOfferer()) {
Offer offer = trade.getOffer();
return offer.getCreateOfferFee().add(offer.getTxFee());
} else {
return trade.getTakeOfferFee().add(trade.getTxFee().multiply(3));
}
} else {
log.error("Trade is null at getTotalFees");
return Coin.ZERO;
}
}
public String getCurrencyCode() {

View file

@ -47,6 +47,7 @@ public class HttpClient {
}
public void setBaseUrl(String baseUrl) {
log.info("baseUrl for HttpClient: " + baseUrl);
this.baseUrl = baseUrl;
}
@ -54,7 +55,6 @@ public class HttpClient {
this.ignoreSocks5Proxy = ignoreSocks5Proxy;
}
public String requestWithGET(String param, @Nullable String headerKey, @Nullable String headerValue) throws IOException, HttpException {
checkNotNull(baseUrl, "baseUrl must be set before calling requestWithGET");

View file

@ -49,7 +49,7 @@
<module>seednode</module>
<module>monitor</module>
<module>statistics</module>
<module>pricefeed</module>
<module>provider</module>
</modules>
<build>

View file

@ -9,7 +9,7 @@
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>pricefeed</artifactId>
<artifactId>provider</artifactId>
<build>
@ -42,7 +42,7 @@
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>io.bitsquare.pricefeed.PriceFeedMain</mainClass>
<mainClass>io.bitsquare.provider.ProviderMain</mainClass>
</transformer>
</transformers>
<filters>
@ -66,7 +66,7 @@
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>bundled</shadedClassifierName>
<finalName>Pricefeed</finalName>
<finalName>provider</finalName>
</configuration>
</execution>
</executions>

View file

@ -15,9 +15,11 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.pricefeed;
package io.bitsquare.provider;
import io.bitsquare.http.HttpException;
import io.bitsquare.provider.fee.FeeRequestService;
import io.bitsquare.provider.price.PriceRequestService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -30,22 +32,39 @@ import java.security.spec.InvalidKeySpecException;
import static spark.Spark.get;
import static spark.Spark.port;
public class PriceFeedMain {
private static final Logger log = LoggerFactory.getLogger(PriceFeedMain.class);
public class ProviderMain {
private static final Logger log = LoggerFactory.getLogger(ProviderMain.class);
public ProviderMain() {
}
public static void main(String[] args) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, InvalidKeyException, HttpException {
port(8080);
handleGetAllMarketPrices(args);
handleGetFees();
}
private static void handleGetAllMarketPrices(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeyException {
if (args.length == 2) {
String bitcoinAveragePrivKey = args[0];
String bitcoinAveragePubKey = args[1];
PriceRequestService priceRequestService = new PriceRequestService(bitcoinAveragePrivKey, bitcoinAveragePubKey);
port(8080);
get("/all", (req, res) -> {
log.info("Incoming request from: " + req.userAgent());
get("/getAllMarketPrices", (req, res) -> {
log.info("Incoming getAllMarketPrices request from: " + req.userAgent());
return priceRequestService.getJson();
});
} else {
throw new IllegalArgumentException("You need to provide the BitcoinAverage API keys. Private key as first argument, public key as second argument.");
}
}
private static void handleGetFees() throws IOException {
FeeRequestService feeRequestService = new FeeRequestService();
get("/getFees", (req, res) -> {
log.info("Incoming getFees request from: " + req.userAgent());
return feeRequestService.getJson();
});
}
}

View file

@ -0,0 +1,105 @@
/*
* This file is part of Bitsquare.
*
* Bitsquare 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.
*
* Bitsquare 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 Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.provider.fee;
import io.bitsquare.btc.provider.fee.FeeService;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.http.HttpException;
import io.bitsquare.provider.fee.providers.BitcoinFeesProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
public class FeeRequestService {
private static final Logger log = LoggerFactory.getLogger(FeeRequestService.class);
private static final long INTERVAL_BTC_FEES_MS = 600_000; // 10 min
private final Timer timerBitcoinFeesLocal = new Timer();
private final BitcoinFeesProvider bitcoinFeesProvider;
private final Map<String, Long> allFeesMap = new ConcurrentHashMap<>();
private long bitcoinFeesTs;
private String json;
public FeeRequestService() throws IOException {
bitcoinFeesProvider = new BitcoinFeesProvider();
allFeesMap.put("txFee", FeeService.DEFAULT_TX_FEE);
allFeesMap.put("createOfferFee", FeeService.DEFAULT_CREATE_OFFER_FEE);
allFeesMap.put("takeOfferFee", FeeService.DEFAULT_TAKE_OFFER_FEE);
startRequests();
}
private void startRequests() throws IOException {
timerBitcoinFeesLocal.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
try {
requestBitcoinFeesLocalPrices();
} catch (HttpException | IOException e) {
log.warn(e.toString());
e.printStackTrace();
}
}
}, INTERVAL_BTC_FEES_MS, INTERVAL_BTC_FEES_MS);
try {
requestBitcoinFeesLocalPrices();
} catch (HttpException e) {
log.warn(e.toString());
e.printStackTrace();
}
}
private void requestBitcoinFeesLocalPrices() throws IOException, HttpException {
long ts = System.currentTimeMillis();
long result = bitcoinFeesProvider.getFee();
// log.info("requestBitcoinFeesLocalPrices took {} ms.", (System.currentTimeMillis() - ts));
if (result < FeeService.MIN_TX_FEE) {
log.warn("Response for fee is lower as min fee. Fee=" + result);
} else if (result > FeeService.MAX_TX_FEE) {
log.warn("Response for fee is larger as max fee. Fee=" + result);
} else {
bitcoinFeesTs = Instant.now().getEpochSecond();
allFeesMap.put("txFee", result);
writeToJson();
}
}
private void writeToJson() {
Map<String, Object> map = new HashMap<>();
map.put("bitcoinFeesTs", bitcoinFeesTs);
map.put("data", allFeesMap);
json = Utilities.objectToJson(map);
}
public String getJson() {
return json;
}
}

View file

@ -15,7 +15,7 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.pricefeed;
package io.bitsquare.provider.price;
@SuppressWarnings("FieldCanBeLocal")
public class PriceData {

View file

@ -15,13 +15,13 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.pricefeed;
package io.bitsquare.provider.price;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.http.HttpException;
import io.bitsquare.pricefeed.providers.BtcAverageProvider;
import io.bitsquare.pricefeed.providers.CoinmarketcapProvider;
import io.bitsquare.pricefeed.providers.PoloniexProvider;
import io.bitsquare.provider.price.providers.BtcAverageProvider;
import io.bitsquare.provider.price.providers.CoinmarketcapProvider;
import io.bitsquare.provider.price.providers.PoloniexProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -35,7 +35,7 @@ import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
class PriceRequestService {
public class PriceRequestService {
private static final Logger log = LoggerFactory.getLogger(PriceRequestService.class);
private static final long INTERVAL_BTC_AV_LOCAL_MS = 60_000; // 60 sec
@ -142,7 +142,9 @@ class PriceRequestService {
private void requestCoinmarketcapPrices() throws IOException, HttpException {
long ts = System.currentTimeMillis();
Map<String, PriceData> map = coinmarketcapProvider.request();
log.info("requestCoinmarketcapPrices took {} ms.", (System.currentTimeMillis() - ts));
// we don't replace prices which we got form the Poloniex request, just in case the Coinmarketcap data are
// received earlier at startup we allow them but Poloniex will overwrite them.
map.entrySet().stream()
@ -154,21 +156,27 @@ class PriceRequestService {
private void requestPoloniexPrices() throws IOException, HttpException {
long ts = System.currentTimeMillis();
poloniexMap = poloniexProvider.request();
log.info("requestPoloniexPrices took {} ms.", (System.currentTimeMillis() - ts));
allPricesMap.putAll(poloniexMap);
poloniexTs = Instant.now().getEpochSecond();
writeToJson();
}
private void requestBtcAverageLocalPrices() throws NoSuchAlgorithmException, InvalidKeyException, IOException, HttpException {
long ts = System.currentTimeMillis();
btcAverageLocalMap = btcAverageProvider.getLocal();
log.info("requestBtcAverageLocalPrices took {} ms.", (System.currentTimeMillis() - ts));
allPricesMap.putAll(btcAverageLocalMap);
btcAverageTs = Instant.now().getEpochSecond();
writeToJson();
}
private void requestBtcAverageGlobalPrices() throws NoSuchAlgorithmException, InvalidKeyException, IOException, HttpException {
long ts = System.currentTimeMillis();
Map<String, PriceData> map = btcAverageProvider.getGlobal();
log.info("requestBtcAverageGlobalPrices took {} ms.", (System.currentTimeMillis() - ts));
// we don't replace prices which we got form the local request, just in case the global data are received
// earlier at startup we allow them but the local request will overwrite them.
map.entrySet().stream()

View file

@ -15,13 +15,13 @@
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
*/
package io.bitsquare.pricefeed.providers;
package io.bitsquare.provider.price.providers;
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import io.bitsquare.http.HttpClient;
import io.bitsquare.http.HttpException;
import io.bitsquare.pricefeed.PriceData;
import io.bitsquare.provider.price.PriceData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;

View file

@ -1,4 +1,4 @@
package io.bitsquare.pricefeed.providers;
package io.bitsquare.provider.price.providers;
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
@ -6,7 +6,7 @@ import io.bitsquare.http.HttpClient;
import io.bitsquare.http.HttpException;
import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.pricefeed.PriceData;
import io.bitsquare.provider.price.PriceData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View file

@ -1,4 +1,4 @@
package io.bitsquare.pricefeed.providers;
package io.bitsquare.provider.price.providers;
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
@ -6,7 +6,7 @@ import io.bitsquare.http.HttpClient;
import io.bitsquare.http.HttpException;
import io.bitsquare.locale.CurrencyUtil;
import io.bitsquare.locale.TradeCurrency;
import io.bitsquare.pricefeed.PriceData;
import io.bitsquare.provider.price.PriceData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View file

@ -9,7 +9,7 @@ import io.bitsquare.app.Log;
import io.bitsquare.app.Version;
import io.bitsquare.arbitration.ArbitratorManager;
import io.bitsquare.btc.WalletService;
import io.bitsquare.btc.pricefeed.PriceFeedService;
import io.bitsquare.btc.provider.price.PriceFeedService;
import io.bitsquare.common.CommonOptionKeys;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.handlers.ResultHandler;