Add timeout to broadcast callbacks in tasks to avoid timeout errors.

Add minValue to BtcValidator.
Fix LTC fees.
Log all onStoredInMailbox and onArrived handler calls.
Fix translations.
This commit is contained in:
Manfred Karrer 2017-06-24 15:03:12 +02:00
parent 67e8a1c74d
commit 4bd299427c
34 changed files with 348 additions and 160 deletions

View File

@ -27,7 +27,7 @@ import java.util.stream.Collectors;
public class CurrencyUtil {
private static String baseCurrencyCode = "BTC";
public static void setBaseCurrencyNetwork(String baseCurrencyCode) {
public static void setBaseCurrencyCode(String baseCurrencyCode) {
CurrencyUtil.baseCurrencyCode = baseCurrencyCode;
}

View File

@ -28,6 +28,7 @@ public abstract class Task<T extends Model> {
private final TaskRunner taskHandler;
protected final T model;
protected String errorMessage = "An error occurred at task: " + getClass().getSimpleName();
protected boolean completed;
public Task(TaskRunner taskHandler, T model) {
this.taskHandler = taskHandler;
@ -53,6 +54,7 @@ public abstract class Task<T extends Model> {
}
protected void complete() {
completed = true;
taskHandler.handleComplete();
}

View File

@ -358,7 +358,11 @@ createOffer.fixed=Fixed
createOffer.percentage=Percentage
createOffer.timeoutAtPublishing=A timeout occurred at publishing the offer.
createOffer.errorInfo=\n\nThe maker fee is already paid. In the worst case you have lost that fee. We are sorry about that but keep in mind it is a very small amount.\nPlease try to restart you application and check your network connection to see if you can resolve the issue.
createOffer.tooLowSecDeposit.warning=You have set the security deposit to a lower value than the recommended default value of {0}.\nAre you sure you want to use a lower security deposit?\nIt gives you less protection in case the trading peer does not follow the trade protocol.
createOffer.tooLowSecDeposit.warning=You have set the security deposit to a lower value than the recommended default value of {0}.\n\
Are you sure you want to use a lower security deposit?
createOffer.tooLowSecDeposit.makerIsSeller=It gives you less protection in case the trading peer does not follow the trade protocol.
createOffer.tooLowSecDeposit.makerIsBuyer=It gives less protection for the trading peer that you follow the trade protocol as you have less deposit at risk. \
Other users might prefer to take other offers instead of yours.
createOffer.resetToDefault=No, reset to the default value
createOffer.useLowerValue=Yes, use my lower value
createOffer.priceOutSideOfDeviation=The price you have entered is outside the max. allowed deviation from the market price.\nThe max. allowed deviation is {0} and can be adjusted in the preferences.
@ -1553,8 +1557,9 @@ validation.zero=Input of 0 is not allowed.
validation.negative=A negative value is not allowed.
validation.fiat.toSmall=Input smaller than minimum possible amount is not allowed.
validation.fiat.toLarge=Input larger than maximum possible amount is not allowed.
validation.btc.toSmall=Input results in a bitcoin value with a fraction of the smallest unit (Satoshi).
validation.btc.fraction=Input results in a bitcoin value with a fraction of the smallest unit (Satoshi).
validation.btc.toLarge=Input larger than {0} is not allowed.
validation.btc.toSmall=Input smaller than {0} is not allowed.
validation.securityDeposit.toSmall=Input smaller than {0} is not allowed.
validation.passwordTooShort=The password you entered is too short. It needs to have min. 8 characters.
validation.passwordTooLong=The password you entered is too long. It cannot be longer than 50 characters.

View File

@ -1358,7 +1358,7 @@ validation.zero=Eingabe von 0 ist nicht erlaubt.
validation.negative=Ein negativer Wert ist nicht erlaubt.
validation.fiat.toSmall=Eingabe kleiner als der minimal mögliche Betrag ist nicht erlaubt.
validation.fiat.toLarge=Eingabe größer als der maximal mögliche Betrag ist nicht erlaubt.
validation.btc.toSmall=Eingabe führt zu einem Bitcoinwert mit einem Bruchteil der kleinsten Einheit (Satoshi).
validation.btc.fraction=Eingabe führt zu einem Bitcoinwert mit einem Bruchteil der kleinsten Einheit (Satoshi).
validation.btc.toLarge=Eingabe größer als {0} ist nicht erlaubt.
validation.securityDeposit.toSmall=Eingabe kleiner als {0} ist nicht erlaubt.
validation.passwordTooShort=Das eingegebene Passwort ist zu kurz. Es muss wenigstens 8 Zeichen haben.

View File

@ -1358,7 +1358,7 @@ validation.zero=El 0 no es un valor permitido.
validation.negative=No se permiten entradas negativas.
validation.fiat.toSmall=No se permite introducir un valor menor que el mínimo posible
validation.fiat.toLarge=No se permiten entradas más gandes que la mayor posible.
validation.btc.toSmall=La entrada resulta en un valor de bitcoin con la menor fracción posible (satoshi).
validation.btc.fraction=La entrada resulta en un valor de bitcoin con la menor fracción posible (satoshi).
validation.btc.toLarge=No se permiten valores mayores que {0}.
validation.securityDeposit.toSmall=No se permiten valores menores que {0}.
validation.passwordTooShort=La clave introducida es demasiado corta. Se precisan al menos 8 caracteres.

View File

@ -1375,7 +1375,7 @@ validation.zero=Unos 0 nije dozvoljen.
validation.negative=Negativna vrednost nije dozvoljena.
validation.fiat.toSmall=Unos manji od minimalnog mogućeg iznosa nije dozvoljen.
validation.fiat.toLarge=Unos veći od maksimalnog mogućeg iznosa nije dozvoljen.
validation.btc.toSmall=Unos ishodi bitkoin vrednosti manjoj od najmanje jedinice (Satoši).
validation.btc.fraction=Unos ishodi bitkoin vrednosti manjoj od najmanje jedinice (Satoši).
validation.btc.toLarge=Unos veći od {0} nije dozvoljen.
validation.securityDeposit.toSmall=Unos manji od {0} nije dozvoljen.
validation.passwordTooShort=Lozinka koju ste uneli je previše kratka. Mora da sadrži minimum 8 karaktera.

View File

@ -241,19 +241,21 @@ public class DisputeManager implements PersistedDataHost {
new SendMailboxMessageListener() {
@Override
public void onArrived() {
log.info("Message arrived at peer. tradeId={}", disputeCommunicationMessage.getTradeId());
disputeCommunicationMessage.setArrived(true);
resultHandler.handleResult();
}
@Override
public void onStoredInMailbox() {
log.info("Message stored in mailbox. tradeId={}", disputeCommunicationMessage.getTradeId());
disputeCommunicationMessage.setStoredInMailbox(true);
resultHandler.handleResult();
}
@Override
public void onFault(String errorMessage) {
log.error("sendEncryptedMessage failed");
log.error("sendEncryptedMailboxMessage failed. disputeCommunicationMessage=" + disputeCommunicationMessage);
faultHandler.handleFault("Sending dispute message failed: " + errorMessage, new MessageDeliveryFailedException());
}
}
@ -329,17 +331,19 @@ public class DisputeManager implements PersistedDataHost {
new SendMailboxMessageListener() {
@Override
public void onArrived() {
log.info("Message arrived at peer. tradeId={}", disputeCommunicationMessage.getTradeId());
disputeCommunicationMessage.setArrived(true);
}
@Override
public void onStoredInMailbox() {
log.info("Message stored in mailbox. tradeId={}", disputeCommunicationMessage.getTradeId());
disputeCommunicationMessage.setStoredInMailbox(true);
}
@Override
public void onFault(String errorMessage) {
log.error("sendEncryptedMessage failed");
log.error("sendEncryptedMailboxMessage failed. disputeCommunicationMessage=" + disputeCommunicationMessage);
}
}
);
@ -391,17 +395,19 @@ public class DisputeManager implements PersistedDataHost {
new SendMailboxMessageListener() {
@Override
public void onArrived() {
log.info("Message arrived at peer. tradeId={}", disputeCommunicationMessage.getTradeId());
disputeCommunicationMessage.setArrived(true);
}
@Override
public void onStoredInMailbox() {
log.info("Message stored in mailbox. tradeId={}", disputeCommunicationMessage.getTradeId());
disputeCommunicationMessage.setStoredInMailbox(true);
}
@Override
public void onFault(String errorMessage) {
log.error("sendEncryptedMessage failed");
log.error("sendEncryptedMailboxMessage failed. disputeCommunicationMessage=" + disputeCommunicationMessage);
}
}
);
@ -441,17 +447,19 @@ public class DisputeManager implements PersistedDataHost {
new SendMailboxMessageListener() {
@Override
public void onArrived() {
log.info("Message arrived at peer. tradeId={}", disputeCommunicationMessage.getTradeId());
disputeCommunicationMessage.setArrived(true);
}
@Override
public void onStoredInMailbox() {
log.info("Message stored in mailbox. tradeId={}", disputeCommunicationMessage.getTradeId());
disputeCommunicationMessage.setStoredInMailbox(true);
}
@Override
public void onFault(String errorMessage) {
log.error("sendEncryptedMessage failed");
log.error("sendEncryptedMailboxMessage failed. disputeCommunicationMessage=" + disputeCommunicationMessage);
}
}
);
@ -462,26 +470,27 @@ public class DisputeManager implements PersistedDataHost {
PubKeyRing peersPubKeyRing = dispute.isDisputeOpenerIsBuyer() ? contract.getSellerPubKeyRing() : contract.getBuyerPubKeyRing();
NodeAddress peerNodeAddress = dispute.isDisputeOpenerIsBuyer() ? contract.getSellerNodeAddress() : contract.getBuyerNodeAddress();
log.trace("sendPeerPublishedPayoutTxMessage to peerAddress " + peerNodeAddress);
final PeerPublishedDisputePayoutTxMessage message = new PeerPublishedDisputePayoutTxMessage(transaction.bitcoinSerialize(),
dispute.getTradeId(),
p2PService.getAddress(),
UUID.randomUUID().toString());
p2PService.sendEncryptedMailboxMessage(peerNodeAddress,
peersPubKeyRing,
new PeerPublishedDisputePayoutTxMessage(transaction.bitcoinSerialize(),
dispute.getTradeId(),
p2PService.getAddress(),
UUID.randomUUID().toString()),
message,
new SendMailboxMessageListener() {
@Override
public void onArrived() {
log.info("Message arrived at peer. tradeId={}", message.getTradeId());
}
@Override
public void onStoredInMailbox() {
log.info("Message stored in mailbox. tradeId={}", message.getTradeId());
}
@Override
public void onFault(String errorMessage) {
log.error("sendEncryptedMessage failed");
log.error("sendEncryptedMailboxMessage failed. message=" + message);
}
}
);

View File

@ -21,14 +21,10 @@ import io.bisq.core.app.BisqEnvironment;
import org.bitcoinj.core.Coin;
public class Restrictions {
private static Coin MIN_TRADE_AMOUNT;
private static Coin MAX_BUYER_SECURITY_DEPOSIT;
private static Coin MIN_BUYER_SECURITY_DEPOSIT;
private static Coin DEFAULT_BUYER_SECURITY_DEPOSIT;
//TODO maybe move to separate class for constant values which might be changed in future by DAO voting?
// For the seller we use a fixed one as there is no way the seller can cancel the trade
// To make it editable would just increase complexity.
private static Coin SELLER_SECURITY_DEPOSIT;
@ -53,13 +49,13 @@ public class Restrictions {
if (MIN_TRADE_AMOUNT == null)
switch (BisqEnvironment.getBaseCurrencyNetwork().getCurrencyCode()) {
case "BTC":
MIN_TRADE_AMOUNT = Coin.valueOf(10_000); // 0.25 EUR cent @ 2500 EUR/BTC
MIN_TRADE_AMOUNT = Coin.valueOf(10_000); // 0.25 EUR @ 2500 EUR/BTC
break;
case "LTC":
MIN_TRADE_AMOUNT = Coin.valueOf(625_000); // 0.25 EUR cent @ 40 EUR/LTC
MIN_TRADE_AMOUNT = Coin.valueOf(100_000); // 0.04 EUR @ 40 EUR/LTC
break;
case "DOGE":
MIN_TRADE_AMOUNT = Coin.valueOf(8_000_000_000L);// 0.24 USD at DOGE price 0.003 USD;
MIN_TRADE_AMOUNT = Coin.valueOf(1_000_000_000L); // 0.03 EUR at DOGE price 0.003 EUR;
break;
}
return MIN_TRADE_AMOUNT;
@ -67,25 +63,66 @@ public class Restrictions {
public static Coin getMaxBuyerSecurityDeposit() {
if (MAX_BUYER_SECURITY_DEPOSIT == null)
MAX_BUYER_SECURITY_DEPOSIT = getMinTradeAmount().multiply(2000); // about 500 EUR
switch (BisqEnvironment.getBaseCurrencyNetwork().getCurrencyCode()) {
case "BTC":
MAX_BUYER_SECURITY_DEPOSIT = Coin.valueOf(20_000_000); // 500 EUR @ 2500 EUR/BTC
break;
case "LTC":
MAX_BUYER_SECURITY_DEPOSIT = Coin.valueOf(1_200_000_000); // 500 EUR @ 40 EUR/LTC
break;
case "DOGE":
MAX_BUYER_SECURITY_DEPOSIT = Coin.valueOf(20_000_000_000_000L); // 500 EUR @ 0.0025 EUR/DOGE;
break;
}
return MAX_BUYER_SECURITY_DEPOSIT;
}
public static Coin getMinBuyerSecurityDeposit() {
if (MIN_BUYER_SECURITY_DEPOSIT == null)
MIN_BUYER_SECURITY_DEPOSIT = getMinTradeAmount().multiply(10); // about 2.5 eur
switch (BisqEnvironment.getBaseCurrencyNetwork().getCurrencyCode()) {
case "BTC":
MIN_BUYER_SECURITY_DEPOSIT = Coin.valueOf(100_000); // 2.5 EUR @ 2500 EUR/BTC
break;
case "LTC":
MIN_BUYER_SECURITY_DEPOSIT = Coin.valueOf(6_000_000); // 2.5 EUR @ 40 EUR/LTC
break;
case "DOGE":
MIN_BUYER_SECURITY_DEPOSIT = Coin.valueOf(100_000_000_000L); // 2.5 EUR @ 0.0025 EUR/DOGE;
break;
}
return MIN_BUYER_SECURITY_DEPOSIT;
}
public static Coin getDefaultBuyerSecurityDeposit() {
if (DEFAULT_BUYER_SECURITY_DEPOSIT == null)
DEFAULT_BUYER_SECURITY_DEPOSIT = getMinTradeAmount().multiply(300); // about 75 eur
switch (BisqEnvironment.getBaseCurrencyNetwork().getCurrencyCode()) {
case "BTC":
DEFAULT_BUYER_SECURITY_DEPOSIT = Coin.valueOf(3_000_000); // 75 EUR @ 2500 EUR/BTC
break;
case "LTC":
DEFAULT_BUYER_SECURITY_DEPOSIT = Coin.valueOf(200_000_000); // 75 EUR @ 40 EUR/LTC
break;
case "DOGE":
DEFAULT_BUYER_SECURITY_DEPOSIT = Coin.valueOf(3_000_000_000_000L); // 75 EUR @ 0.0025 EUR/DOGE;
break;
}
return DEFAULT_BUYER_SECURITY_DEPOSIT;
}
public static Coin getSellerSecurityDeposit() {
if (SELLER_SECURITY_DEPOSIT == null)
SELLER_SECURITY_DEPOSIT = getMinTradeAmount().multiply(100); // about 25 eur
switch (BisqEnvironment.getBaseCurrencyNetwork().getCurrencyCode()) {
case "BTC":
SELLER_SECURITY_DEPOSIT = Coin.valueOf(1_000_000); // 25 EUR @ 2500 EUR/BTC
break;
case "LTC":
SELLER_SECURITY_DEPOSIT = Coin.valueOf(60_000_000); // 25 EUR @ 40 EUR/LTC
break;
case "DOGE":
SELLER_SECURITY_DEPOSIT = Coin.valueOf(1_000_000_000_000L); // 25 EUR @ 0.0025 EUR/DOGE;
break;
}
return SELLER_SECURITY_DEPOSIT;
}
}

View File

@ -418,8 +418,9 @@ public class WalletConfig extends AbstractIdleService {
vChain = new BlockChain(params, vStore);
vPeerGroup = createPeerGroup();
if (this.userAgent != null)
vPeerGroup.setUserAgent(userAgent, version);
// protect privacy and don't send agent info
/*if (this.userAgent != null)
vPeerGroup.setUserAgent(userAgent, version);*/
// Set up peer addresses or discovery first, so if wallet extensions try to broadcast a transaction
// before we're actually connected the broadcast waits for an appropriate number of connections.

View File

@ -18,6 +18,8 @@
package io.bisq.core.offer.placeoffer.tasks;
import com.google.common.util.concurrent.FutureCallback;
import io.bisq.common.Timer;
import io.bisq.common.UserThread;
import io.bisq.common.taskrunner.Task;
import io.bisq.common.taskrunner.TaskRunner;
import io.bisq.core.offer.Offer;
@ -42,59 +44,77 @@ public class BroadcastMakerFeeTx extends Task<PlaceOfferModel> {
protected void run() {
try {
runInterceptHook();
model.getTradeWalletService().broadcastTx(model.getTransaction(), new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.debug("Broadcast of offer fee payment succeeded: transaction = " + transaction.toString());
final Transaction transaction = model.getTransaction();
Timer timeoutTimer = UserThread.runAfter(() -> {
log.warn("Broadcast not completed after 5 sec. We go on with the trade protocol.");
model.getOffer().setState(Offer.State.OFFER_FEE_PAID);
complete();
}, 5);
if (model.getTransaction().getHashAsString().equals(transaction.getHashAsString())) {
model.getOffer().setState(Offer.State.OFFER_FEE_PAID);
// No tx malleability happened after broadcast (still not in blockchain)
complete();
} else {
log.warn("Tx malleability happened after broadcast. We publish the changed offer to the P2P network again.");
// Tx malleability happened after broadcast. We first remove the malleable offer.
// Then we publish the changed offer to the P2P network again after setting the new TxId.
// Normally we use a delay for broadcasting to the peers, but at shut down we want to get it fast out
model.getOfferBookService().removeOffer(model.getOffer().getOfferPayload(),
() -> {
log.debug("We store now the changed txID to the offer and add that again.");
// We store now the changed txID to the offer and add that again.
model.getOffer().setOfferFeePaymentTxId(transaction.getHashAsString());
model.setTransaction(transaction);
model.getOfferBookService().addOffer(model.getOffer(),
BroadcastMakerFeeTx.this::complete,
model.getTradeWalletService().broadcastTx(model.getTransaction(),
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction tx) {
if (!completed) {
timeoutTimer.stop();
log.debug("Broadcast of offer fee payment succeeded: transaction = " + tx.toString());
if (transaction.getHashAsString().equals(tx.getHashAsString())) {
model.getOffer().setState(Offer.State.OFFER_FEE_PAID);
// No tx malleability happened after broadcast (still not in blockchain)
complete();
} else {
log.warn("Tx malleability happened after broadcast. We publish the changed offer to the P2P network again.");
// Tx malleability happened after broadcast. We first remove the malleable offer.
// Then we publish the changed offer to the P2P network again after setting the new TxId.
// Normally we use a delay for broadcasting to the peers, but at shut down we want to get it fast out
model.getOfferBookService().removeOffer(model.getOffer().getOfferPayload(),
() -> {
log.debug("We store now the changed txID to the offer and add that again.");
// We store now the changed txID to the offer and add that again.
model.getOffer().setOfferFeePaymentTxId(tx.getHashAsString());
model.setTransaction(tx);
model.getOfferBookService().addOffer(model.getOffer(),
BroadcastMakerFeeTx.this::complete,
errorMessage -> {
log.error("addOffer failed");
addOfferFailed = true;
updateStateOnFault();
model.getOffer().setErrorMessage("An error occurred when adding the offer to the P2P network.\n" +
"Error message:\n"
+ errorMessage);
failed(errorMessage);
});
},
errorMessage -> {
log.error("addOffer failed");
addOfferFailed = true;
log.error("removeOffer failed");
removeOfferFailed = true;
updateStateOnFault();
model.getOffer().setErrorMessage("An error occurred when adding the offer to the P2P network.\n" +
model.getOffer().setErrorMessage("An error occurred when removing the offer from the P2P network.\n" +
"Error message:\n"
+ errorMessage);
failed(errorMessage);
});
},
errorMessage -> {
log.error("removeOffer failed");
removeOfferFailed = true;
updateStateOnFault();
model.getOffer().setErrorMessage("An error occurred when removing the offer from the P2P network.\n" +
"Error message:\n"
+ errorMessage);
failed(errorMessage);
});
}
}
}
} else {
log.warn("We got the callback called after the timeout has been triggered a complete().");
}
}
@Override
public void onFailure(@NotNull Throwable t) {
updateStateOnFault();
model.getOffer().setErrorMessage("An error occurred.\n" +
"Error message:\n"
+ t.getMessage());
failed(t);
}
});
@Override
public void onFailure(@NotNull Throwable t) {
if (!completed) {
timeoutTimer.stop();
updateStateOnFault();
model.getOffer().setErrorMessage("An error occurred.\n" +
"Error message:\n"
+ t.getMessage());
failed(t);
} else {
log.warn("We got the callback called after the timeout has been triggered a complete().");
}
}
});
} catch (Throwable t) {
model.getOffer().setErrorMessage("An error occurred.\n" +
"Error message:\n"

View File

@ -89,10 +89,11 @@ public class FeeService {
txFeePerByte = BTC_DEFAULT_TX_FEE;
break;
case "LTC":
MIN_MAKER_FEE_IN_BASE_CUR = 12_500; // 0.25 USD at LTC price 40 USD for 50 LTC
MIN_TAKER_FEE_IN_BASE_CUR = 12_500;
DEFAULT_MAKER_FEE_IN_BASE_CUR = 125_000; // 2.5 USD at LTC price 40 USD
DEFAULT_TAKER_FEE_IN_BASE_CUR = 187_500; // 3.6 USD at LTC price 40 USD
// > 0.00 100 000
MIN_MAKER_FEE_IN_BASE_CUR = 600_000; // 0.25 USD at LTC price 40 USD for 50 LTC
MIN_TAKER_FEE_IN_BASE_CUR = 600_000;
DEFAULT_MAKER_FEE_IN_BASE_CUR = 120_000; // 2.5 USD at LTC price 40 USD
DEFAULT_TAKER_FEE_IN_BASE_CUR = 180_000; // 3.6 USD at LTC price 40 USD
txFeePerByte = LTC_DEFAULT_TX_FEE;
break;
case "DOGE":

View File

@ -60,20 +60,21 @@ public class BuyerSendCounterCurrencyTransferStartedMessage extends TradeTask {
new SendMailboxMessageListener() {
@Override
public void onArrived() {
log.debug("Message arrived at peer. tradeId={}, message{}", id, message);
log.info("Message arrived at peer. tradeId={}", id);
trade.setState(Trade.State.BUYER_SAW_ARRIVED_FIAT_PAYMENT_INITIATED_MSG);
complete();
}
@Override
public void onStoredInMailbox() {
log.debug("Message stored in mailbox. tradeId={}, message{}", id, message);
log.info("Message stored in mailbox. tradeId={}", id);
trade.setState(Trade.State.BUYER_STORED_IN_MAILBOX_FIAT_PAYMENT_INITIATED_MSG);
complete();
}
@Override
public void onFault(String errorMessage) {
log.error("sendEncryptedMailboxMessage failed. message=" + message);
trade.setState(Trade.State.BUYER_SEND_FAILED_FIAT_PAYMENT_INITIATED_MSG);
appendToErrorMessage("Sending message failed: message=" + message + "\nerrorMessage=" + errorMessage);
failed(errorMessage);

View File

@ -18,6 +18,8 @@
package io.bisq.core.trade.protocol.tasks.buyer_as_taker;
import com.google.common.util.concurrent.FutureCallback;
import io.bisq.common.Timer;
import io.bisq.common.UserThread;
import io.bisq.common.crypto.Hash;
import io.bisq.common.taskrunner.TaskRunner;
import io.bisq.core.btc.AddressEntry;
@ -40,6 +42,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
@Slf4j
public class BuyerAsTakerSignAndPublishDepositTx extends TradeTask {
@SuppressWarnings({"WeakerAccess", "unused"})
public BuyerAsTakerSignAndPublishDepositTx(TaskRunner taskHandler, Trade trade) {
super(taskHandler, trade);
@ -75,6 +78,13 @@ public class BuyerAsTakerSignAndPublishDepositTx extends TradeTask {
checkArgument(Arrays.equals(buyerMultiSigPubKey, buyerMultiSigAddressEntry.getPubKey()),
"buyerMultiSigPubKey from AddressEntry must match the one from the trade data. trade id =" + id);
Timer timeoutTimer = UserThread.runAfter(() -> {
log.warn("Broadcast not completed after 5 sec. We go on with the trade protocol.");
trade.setState(Trade.State.TAKER_PUBLISHED_DEPOSIT_TX);
complete();
}, 5);
Transaction depositTx = processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(
false,
contractHash,
@ -87,17 +97,25 @@ public class BuyerAsTakerSignAndPublishDepositTx extends TradeTask {
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.trace("takerSignAndPublishTx succeeded " + transaction);
trade.setDepositTx(transaction);
trade.setState(Trade.State.TAKER_PUBLISHED_DEPOSIT_TX);
complete();
if (!completed) {
timeoutTimer.stop();
log.trace("takerSignAndPublishTx succeeded " + transaction);
trade.setDepositTx(transaction);
trade.setState(Trade.State.TAKER_PUBLISHED_DEPOSIT_TX);
complete();
} else {
log.warn("We got the callback called after the timeout has been triggered a complete().");
}
}
@Override
public void onFailure(@NotNull Throwable t) {
failed(t);
if (!completed) {
timeoutTimer.stop();
failed(t);
} else {
log.warn("We got the callback called after the timeout has been triggered a complete().");
}
}
});
trade.setDepositTx(depositTx);

View File

@ -76,20 +76,21 @@ public class MakerSendPublishDepositTxRequest extends TradeTask {
new SendMailboxMessageListener() {
@Override
public void onArrived() {
log.debug("Message arrived at peer. tradeId={}, message{}", id, message);
log.info("Message arrived at peer. tradeId={}", id);
trade.setState(Trade.State.MAKER_SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST);
complete();
}
@Override
public void onStoredInMailbox() {
log.debug("Message stored in mailbox. tradeId={}, message{}", id, message);
log.info("Message stored in mailbox. tradeId={}", id);
trade.setState(Trade.State.MAKER_STORED_IN_MAILBOX_PUBLISH_DEPOSIT_TX_REQUEST);
complete();
}
@Override
public void onFault(String errorMessage) {
log.error("sendEncryptedMailboxMessage failed. message=" + message);
trade.setState(Trade.State.MAKER_SEND_FAILED_PUBLISH_DEPOSIT_TX_REQUEST);
appendToErrorMessage("Sending message failed: message=" + message + "\nerrorMessage=" + errorMessage);
failed(errorMessage);

View File

@ -18,6 +18,8 @@
package io.bisq.core.trade.protocol.tasks.seller;
import com.google.common.util.concurrent.FutureCallback;
import io.bisq.common.Timer;
import io.bisq.common.UserThread;
import io.bisq.common.taskrunner.TaskRunner;
import io.bisq.core.trade.Trade;
import io.bisq.core.trade.protocol.tasks.TradeTask;
@ -50,20 +52,36 @@ public class SellerBroadcastPayoutTx extends TradeTask {
trade.setState(Trade.State.SELLER_PUBLISHED_PAYOUT_TX);
complete();
} else {
processModel.getTradeWalletService().broadcastTx(payoutTx, new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.debug("BroadcastTx succeeded. Transaction:" + transaction);
trade.setState(Trade.State.SELLER_PUBLISHED_PAYOUT_TX);
complete();
}
Timer timeoutTimer = UserThread.runAfter(() -> {
log.warn("Broadcast not completed after 5 sec. We go on with the trade protocol.");
trade.setState(Trade.State.SELLER_PUBLISHED_PAYOUT_TX);
complete();
}, 5);
processModel.getTradeWalletService().broadcastTx(payoutTx,
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
if (!completed) {
timeoutTimer.stop();
log.debug("BroadcastTx succeeded. Transaction:" + transaction);
trade.setState(Trade.State.SELLER_PUBLISHED_PAYOUT_TX);
complete();
} else {
log.warn("We got the callback called after the timeout has been triggered a complete().");
}
}
@Override
public void onFailure(@NotNull Throwable t) {
log.error("BroadcastTx failed. Error:" + t.getMessage());
failed(t);
}
});
@Override
public void onFailure(@NotNull Throwable t) {
if (!completed) {
timeoutTimer.stop();
log.error("BroadcastTx failed. Error:" + t.getMessage());
failed(t);
} else {
log.warn("We got the callback called after the timeout has been triggered a complete().");
}
}
});
}
} catch (Throwable t) {
failed(t);

View File

@ -46,7 +46,6 @@ public class SellerSendPayoutTxPublishedMessage extends TradeTask {
processModel.getMyNodeAddress(),
UUID.randomUUID().toString()
);
log.info("Send message to peer. tradeId={}, message{}", id, message);
trade.setState(Trade.State.SELLER_SENT_PAYOUT_TX_PUBLISHED_MSG);
processModel.getP2PService().sendEncryptedMailboxMessage(
trade.getTradingPeerNodeAddress(),
@ -55,20 +54,21 @@ public class SellerSendPayoutTxPublishedMessage extends TradeTask {
new SendMailboxMessageListener() {
@Override
public void onArrived() {
log.debug("Message arrived at peer. tradeId={}, message{}", id, message);
log.info("Message arrived at peer. tradeId={}", id);
trade.setState(Trade.State.SELLER_SAW_ARRIVED_PAYOUT_TX_PUBLISHED_MSG);
complete();
}
@Override
public void onStoredInMailbox() {
log.debug("Message stored in mailbox. tradeId={}, message{}", id, message);
log.info("Message stored in mailbox. tradeId={}", id);
trade.setState(Trade.State.SELLER_STORED_IN_MAILBOX_PAYOUT_TX_PUBLISHED_MSG);
complete();
}
@Override
public void onFault(String errorMessage) {
log.error("sendEncryptedMailboxMessage failed. message=" + message);
trade.setState(Trade.State.SELLER_SEND_FAILED_PAYOUT_TX_PUBLISHED_MSG);
appendToErrorMessage("Sending message failed: message=" + message + "\nerrorMessage=" + errorMessage);
failed(errorMessage);

View File

@ -18,6 +18,8 @@
package io.bisq.core.trade.protocol.tasks.seller_as_taker;
import com.google.common.util.concurrent.FutureCallback;
import io.bisq.common.Timer;
import io.bisq.common.UserThread;
import io.bisq.common.crypto.Hash;
import io.bisq.common.taskrunner.TaskRunner;
import io.bisq.core.btc.AddressEntry;
@ -75,6 +77,13 @@ public class SellerAsTakerSignAndPublishDepositTx extends TradeTask {
walletService.saveAddressEntryList();
TradingPeer tradingPeer = processModel.getTradingPeer();
Timer timeoutTimer = UserThread.runAfter(() -> {
log.warn("Broadcast not completed after 5 sec. We go on with the trade protocol.");
trade.setState(Trade.State.TAKER_PUBLISHED_DEPOSIT_TX);
complete();
}, 5);
Transaction depositTx = processModel.getTradeWalletService().takerSignsAndPublishesDepositTx(
true,
contractHash,
@ -87,17 +96,26 @@ public class SellerAsTakerSignAndPublishDepositTx extends TradeTask {
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.trace("takerSignAndPublishTx succeeded " + transaction);
if (!completed) {
timeoutTimer.stop();
log.trace("takerSignAndPublishTx succeeded " + transaction);
trade.setDepositTx(transaction);
trade.setState(Trade.State.TAKER_PUBLISHED_DEPOSIT_TX);
trade.setDepositTx(transaction);
trade.setState(Trade.State.TAKER_PUBLISHED_DEPOSIT_TX);
complete();
complete();
} else {
log.warn("We got the callback called after the timeout has been triggered a complete().");
}
}
@Override
public void onFailure(@NotNull Throwable t) {
failed(t);
if (!completed) {
timeoutTimer.stop();
failed(t);
} else {
log.warn("We got the callback called after the timeout has been triggered a complete().");
}
}
});
trade.setDepositTx(depositTx);

View File

@ -18,6 +18,8 @@
package io.bisq.core.trade.protocol.tasks.taker;
import com.google.common.util.concurrent.FutureCallback;
import io.bisq.common.Timer;
import io.bisq.common.UserThread;
import io.bisq.common.taskrunner.TaskRunner;
import io.bisq.core.arbitration.Arbitrator;
import io.bisq.core.btc.AddressEntry;
@ -102,27 +104,45 @@ public class CreateTakerFeeTx extends TradeTask {
// We need to create another instance, otherwise the tx would trigger an invalid state exception
// if it gets committed 2 times
tradeWalletService.commitTx(tradeWalletService.getClonedTransaction(signedTx));
Timer timeoutTimer = UserThread.runAfter(() -> {
log.warn("Broadcast not completed after 5 sec. We go on with the trade protocol.");
trade.setTakerFeeTxId(signedTx.getHashAsString());
processModel.setTakeOfferFeeTx(signedTx);
complete();
}, 5);
bsqWalletService.broadcastTx(signedTx, new FutureCallback<Transaction>() {
@Override
public void onSuccess(@Nullable Transaction transaction) {
if (transaction != null) {
checkArgument(transaction.equals(signedTx));
trade.setTakerFeeTxId(transaction.getHashAsString());
processModel.setTakeOfferFeeTx(transaction);
if (!completed) {
timeoutTimer.stop();
if (transaction != null) {
checkArgument(transaction.equals(signedTx));
trade.setTakerFeeTxId(transaction.getHashAsString());
processModel.setTakeOfferFeeTx(transaction);
complete();
log.debug("Successfully sent tx with id " + transaction.getHashAsString());
complete();
log.debug("Successfully sent tx with id " + transaction.getHashAsString());
}
} else {
log.warn("We got the callback called after the timeout has been triggered a complete().");
}
}
@Override
public void onFailure(@NotNull Throwable t) {
log.error(t.toString());
t.printStackTrace();
trade.setErrorMessage("An error occurred.\n" +
"Error message:\n"
+ t.getMessage());
failed(t);
if (!completed) {
timeoutTimer.stop();
log.error(t.toString());
t.printStackTrace();
trade.setErrorMessage("An error occurred.\n" +
"Error message:\n"
+ t.getMessage());
failed(t);
} else {
log.warn("We got the callback called after the timeout has been triggered a complete().");
}
}
});
}

View File

@ -18,6 +18,8 @@
package io.bisq.core.trade.protocol.tasks.taker;
import com.google.common.util.concurrent.FutureCallback;
import io.bisq.common.Timer;
import io.bisq.common.UserThread;
import io.bisq.common.taskrunner.TaskRunner;
import io.bisq.core.trade.Trade;
import io.bisq.core.trade.protocol.tasks.TradeTask;
@ -36,20 +38,36 @@ public class TakerPublishTakerFeeTx extends TradeTask {
protected void run() {
try {
runInterceptHook();
Timer timeoutTimer = UserThread.runAfter(() -> {
log.warn("Broadcast not completed after 5 sec. We go on with the trade protocol.");
trade.setState(Trade.State.TAKER_PUBLISHED_TAKER_FEE_TX);
complete();
}, 5);
processModel.getTradeWalletService().broadcastTx(processModel.resolveTakeOfferFeeTx(trade),
new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.debug("Trading fee published successfully. Transaction ID = " + transaction.getHashAsString());
trade.setState(Trade.State.TAKER_PUBLISHED_TAKER_FEE_TX);
complete();
if (!completed) {
timeoutTimer.stop();
log.debug("Trading fee published successfully. Transaction ID = " + transaction.getHashAsString());
trade.setState(Trade.State.TAKER_PUBLISHED_TAKER_FEE_TX);
complete();
} else {
log.warn("We got the callback called after the timeout has been triggered a complete().");
}
}
@Override
public void onFailure(@NotNull Throwable t) {
appendToErrorMessage("Trading fee payment failed. Maybe your network connection was lost. Please try again.");
failed(t);
if (!completed) {
timeoutTimer.stop();
appendToErrorMessage("Trading fee payment failed. Maybe your network connection was lost. Please try again.");
failed(t);
} else {
log.warn("We got the callback called after the timeout has been triggered a complete().");
}
}
});
} catch (Throwable t) {

View File

@ -51,20 +51,21 @@ public class TakerSendDepositTxPublishedMessage extends TradeTask {
new SendMailboxMessageListener() {
@Override
public void onArrived() {
log.debug("Message arrived at peer. tradeId={}, message{}", id, message);
log.info("Message arrived at peer. tradeId={}", id);
trade.setState(Trade.State.TAKER_SAW_ARRIVED_DEPOSIT_TX_PUBLISHED_MSG);
complete();
}
@Override
public void onStoredInMailbox() {
log.debug("Message stored in mailbox. tradeId={}, message{}", id, message);
log.info("Message stored in mailbox. tradeId={}", id);
trade.setState(Trade.State.TAKER_STORED_IN_MAILBOX_DEPOSIT_TX_PUBLISHED_MSG);
complete();
}
@Override
public void onFault(String errorMessage) {
log.error("sendEncryptedMailboxMessage failed. message=" + message);
trade.setState(Trade.State.TAKER_SEND_FAILED_DEPOSIT_TX_PUBLISHED_MSG);
appendToErrorMessage("Sending message failed: message=" + message + "\nerrorMessage=" + errorMessage);
failed();

View File

@ -57,10 +57,10 @@ public final class Preferences implements PersistedDataHost {
));
private static final ArrayList<BlockChainExplorer> LTC_MAIN_NET_EXPLORERS = new ArrayList<>(Arrays.asList(
new BlockChainExplorer("Blockcypher", "https://live.blockcypher.com/ltc/tx", "https://live.blockcypher.com/ltc/address"),
new BlockChainExplorer("CryptoID", "https://chainz.cryptoid.info/ltc/tx.dws?", "https://chainz.cryptoid.info/ltc/address.dws?"),
new BlockChainExplorer("SoChain", "https://chain.so/tx/LTC/", "https://chain.so/address/LTC/"),
new BlockChainExplorer("Abe Search", "http://explorer.litecoin.net/tx/", "http://explorer.litecoin.net/address/"),
new BlockChainExplorer("Blockcypher", "https://live.blockcypher.com/ltc/tx", "https://live.blockcypher.com/ltc/address"),
new BlockChainExplorer("SoChain", "https://chain.so/tx/LTC/", "https://chain.so/address/LTC/"),
new BlockChainExplorer("Blockr.io", "http://ltc.blockr.io/tx/info/", "http://ltc.blockr.io/address/info/")
));

View File

@ -166,11 +166,10 @@ public class BisqApp extends Application {
Security.addProvider(new BouncyCastleProvider());
final BaseCurrencyNetwork baseCurrencyNetwork = BisqEnvironment.getBaseCurrencyNetwork();
Res.setBaseCurrencyCode(baseCurrencyNetwork.getCurrencyCode());
final String currencyCode = baseCurrencyNetwork.getCurrencyCode();
Res.setBaseCurrencyCode(currencyCode);
Res.setBaseCurrencyName(baseCurrencyNetwork.getCurrencyName());
CurrencyUtil.setBaseCurrencyNetwork(baseCurrencyNetwork.getCurrencyCode());
CurrencyUtil.setBaseCurrencyCode(currencyCode);
try {
// Guice

View File

@ -268,7 +268,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
// As we use the best fee estimation (for 1 confirmation) that risk should not be too critical as long there are
// not too many inputs.
// trade fee tx: 226 bytes (1 input) - 374 bytes (2 inputs)
// trade fee tx: 226 bytes (1 input) - 374 bytes (2 inputs) (148 byte per input)
// Set the default values (in rare cases if the fee request was not done yet we get the hard coded default values)
// But offer creation happens usually after that so we should have already the value from the estimation service.

View File

@ -387,8 +387,6 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
model.getMakerFee(),
model.getTxFee()
);
//TODO remove
log.error(message);
new Popup<>().headLine(Res.get("createOffer.createOfferFundWalletInfo.headline"))
.instruction(message)
.dontShowAgainId(key)

View File

@ -521,6 +521,8 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
if (dataModel.paymentAccount != null)
btcValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimitAsCoin());
btcValidator.setMinValue(Restrictions.getMinTradeAmount());
final boolean isBuy = dataModel.getDirection() == OfferPayload.Direction.BUY;
directionLabel = isBuy ? Res.get("shared.buyBitcoin") : Res.get("shared.sellBitcoin");
amountDescription = Res.get("createOffer.amountPriceBox.amountDescription",
@ -733,9 +735,12 @@ class CreateOfferViewModel extends ActivatableWithDataModel<CreateOfferDataModel
String key = "buyerSecurityDepositLowerAsDefault";
if (preferences.showAgain(key) &&
btcFormatter.parseToCoin(buyerSecurityDeposit.get()).compareTo(defaultSecurityDeposit) < 0) {
final String postfix = dataModel.isBuyOffer() ?
Res.get("createOffer.tooLowSecDeposit.makerIsBuyer") :
Res.get("createOffer.tooLowSecDeposit.makerIsSeller");
new Popup<>()
.warning(Res.get("createOffer.tooLowSecDeposit.warning",
btcFormatter.formatCoinWithCode(defaultSecurityDeposit)))
btcFormatter.formatCoinWithCode(defaultSecurityDeposit)) + "\n\n" + postfix)
.width(800)
.actionButtonText(Res.get("createOffer.resetToDefault"))
.onAction(() -> {

View File

@ -410,8 +410,6 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
model.getTakerFee(),
model.getTxFee()
);
//TODO remove
log.error(message);
key = "takeOfferFundWalletInfo";
new Popup<>().headLine(Res.get("takeOffer.takeOfferFundWalletInfo.headline"))
.instruction(message)

View File

@ -182,6 +182,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
errorMessage.set(offer.getErrorMessage());
btcValidator.setMaxValue(offer.getAmount());
btcValidator.setMinValue(offer.getMinAmount());
}
@ -208,8 +209,6 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
dataModel.onPaymentAccountSelected(paymentAccount);
if (offer != null)
btcValidator.setMaxValue(offer.getAmount());
}
public void onShowPayFundsScreen() {

View File

@ -130,20 +130,21 @@ public class SendPrivateNotificationWindow extends Overlay<SendPrivateNotificati
new SendMailboxMessageListener() {
@Override
public void onArrived() {
log.trace("PrivateNotificationMessage arrived at peer.");
log.info("PrivateNotificationMessage arrived at peer.");
new Popup<>().feedback(Res.get("shared.messageArrived"))
.onClose(SendPrivateNotificationWindow.this::hide).show();
}
@Override
public void onStoredInMailbox() {
log.trace("PrivateNotificationMessage was stored in mailbox.");
log.info("PrivateNotificationMessage was stored in mailbox.");
new Popup<>().feedback(Res.get("shared.messageStoredInMailbox"))
.onClose(SendPrivateNotificationWindow.this::hide).show();
}
@Override
public void onFault(String errorMessage) {
log.error("sendEncryptedMailboxMessage failed. message=" + message);
new Popup<>().feedback(Res.get("shared.messageSendingFailed", errorMessage))
.onClose(SendPrivateNotificationWindow.this::hide).show();
}

View File

@ -130,7 +130,7 @@ public class SellerStep3View extends TradeStepView {
if (myPaymentAccountPayload instanceof CryptoCurrencyAccountPayload) {
myPaymentDetails = ((CryptoCurrencyAccountPayload) myPaymentAccountPayload).getAddress();
peersPaymentDetails = ((CryptoCurrencyAccountPayload) peersPaymentAccountPayload).getAddress();
myTitle = Res.get("portfolio.pending.step3_seller.yourAddress");
myTitle = Res.get("portfolio.pending.step3_seller.yourAddress", nameByCode);
peersTitle = Res.get("portfolio.pending.step3_seller.buyersAddress", nameByCode);
isBlockChain = true;
} else {
@ -276,7 +276,7 @@ public class SellerStep3View extends TradeStepView {
Optional<String> optionalHolderName = getOptionalHolderName();
if (optionalHolderName.isPresent()) {
//noinspection UnusedAssignment
message = message + Res.get("portfolio.pending.step3_seller.bankCheck" + optionalHolderName.get(), part);
message = message + Res.get("portfolio.pending.step3_seller.bankCheck", optionalHolderName.get(), part);
}
}
//noinspection ConstantConditions

View File

@ -88,7 +88,7 @@ public class BsqValidator extends AltcoinValidator {
BigDecimal bd = new BigDecimal(input);
final BigDecimal satoshis = bd.movePointRight(3);
if (satoshis.scale() > 0)
return new ValidationResult(false, Res.get("validation.btc.toSmall"));
return new ValidationResult(false, Res.get("validation.btc.fraction"));
else
return new ValidationResult(true);
}

View File

@ -31,6 +31,8 @@ public class BtcValidator extends NumberValidator {
protected final BSFormatter formatter;
@Nullable
protected Coin minValue;
@Nullable
protected Coin maxValue;
@ -40,6 +42,10 @@ public class BtcValidator extends NumberValidator {
this.formatter = formatter;
}
public void setMinValue(@NotNull Coin minValue) {
this.minValue = minValue;
}
public void setMaxValue(@NotNull Coin maxValue) {
this.maxValue = maxValue;
}
@ -57,6 +63,7 @@ public class BtcValidator extends NumberValidator {
.and(validateIfNotNegative(input))
.and(validateIfNotFractionalBtcValue(input))
.and(validateIfNotExceedsMaxBtcValue(input))
.and(validateIfNotUnderMinValue(input))
.and(validateIfAboveDust(input));
}
@ -75,7 +82,7 @@ public class BtcValidator extends NumberValidator {
BigDecimal bd = new BigDecimal(input);
final BigDecimal satoshis = bd.movePointRight(8);
if (satoshis.scale() > 0)
return new ValidationResult(false, Res.get("validation.btc.toSmall"));
return new ValidationResult(false, Res.get("validation.btc.fraction"));
else
return new ValidationResult(true);
}
@ -91,4 +98,16 @@ public class BtcValidator extends NumberValidator {
return new ValidationResult(false, Res.get("validation.invalidInput", t.getMessage()));
}
}
protected ValidationResult validateIfNotUnderMinValue(String input) {
try {
final Coin coin = Coin.parseCoin(input);
if (minValue != null && coin.compareTo(minValue) < 0)
return new ValidationResult(false, Res.get("validation.btc.toSmall", formatter.formatCoinWithCode(minValue)));
else
return new ValidationResult(true);
} catch (Throwable t) {
return new ValidationResult(false, Res.get("validation.invalidInput", t.getMessage()));
}
}
}

View File

@ -30,6 +30,7 @@ public class SecurityDepositValidator extends BtcValidator {
public SecurityDepositValidator(BSFormatter formatter) {
super(formatter);
setMaxValue(Restrictions.getMaxBuyerSecurityDeposit());
setMinValue(Restrictions.getMinBuyerSecurityDeposit());
}

View File

@ -76,11 +76,10 @@ public class SeedNode {
Security.addProvider(new BouncyCastleProvider());
final BaseCurrencyNetwork baseCurrencyNetwork = BisqEnvironment.getBaseCurrencyNetwork();
Res.setBaseCurrencyCode(baseCurrencyNetwork.getCurrencyCode());
final String currencyCode = baseCurrencyNetwork.getCurrencyCode();
Res.setBaseCurrencyCode(currencyCode);
Res.setBaseCurrencyName(baseCurrencyNetwork.getCurrencyName());
CurrencyUtil.setBaseCurrencyNetwork(baseCurrencyNetwork.getCurrencyCode());
CurrencyUtil.setBaseCurrencyCode(currencyCode);
seedNodeModule = new SeedNodeModule(bisqEnvironment);
injector = Guice.createInjector(seedNodeModule);

View File

@ -84,11 +84,10 @@ public class Statistics {
Security.addProvider(new BouncyCastleProvider());
final BaseCurrencyNetwork baseCurrencyNetwork = BisqEnvironment.getBaseCurrencyNetwork();
Res.setBaseCurrencyCode(baseCurrencyNetwork.getCurrencyCode());
final String currencyCode = baseCurrencyNetwork.getCurrencyCode();
Res.setBaseCurrencyCode(currencyCode);
Res.setBaseCurrencyName(baseCurrencyNetwork.getCurrencyName());
CurrencyUtil.setBaseCurrencyNetwork(baseCurrencyNetwork.getCurrencyCode());
CurrencyUtil.setBaseCurrencyCode(currencyCode);
statisticsModule = new StatisticsModule(bisqEnvironment);
injector = Guice.createInjector(statisticsModule);