support local, stagenet, and mainnet xmr network configuration (#335)

remove btc wallet
disable local zmq
This commit is contained in:
woodser 2022-07-07 09:10:59 -04:00 committed by GitHub
parent b4112e50e9
commit e2208355b1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
74 changed files with 595 additions and 899 deletions

View file

@ -357,23 +357,25 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
settingsButtonWithBadge.getStyleClass().add("new");
navigation.addListener((viewPath, data) -> {
if (viewPath.size() != 2 || viewPath.indexOf(MainView.class) != 0)
return;
UserThread.execute(() -> {
if (viewPath.size() != 2 || viewPath.indexOf(MainView.class) != 0)
return;
Class<? extends View> viewClass = viewPath.tip();
View view = viewLoader.load(viewClass);
contentContainer.getChildren().setAll(view.getRoot());
Class<? extends View> viewClass = viewPath.tip();
View view = viewLoader.load(viewClass);
contentContainer.getChildren().setAll(view.getRoot());
try {
navButtons.getToggles().stream()
.filter(toggle -> toggle instanceof NavButton)
.filter(button -> viewClass == ((NavButton) button).viewClass)
.findFirst()
.orElseThrow(() -> new HavenoException("No button matching %s found", viewClass))
.setSelected(true);
} catch (HavenoException e) {
navigation.navigateTo(MainView.class, MarketView.class, OfferBookChartView.class);
}
try {
navButtons.getToggles().stream()
.filter(toggle -> toggle instanceof NavButton)
.filter(button -> viewClass == ((NavButton) button).viewClass)
.findFirst()
.orElseThrow(() -> new HavenoException("No button matching %s found", viewClass))
.setSelected(true);
} catch (HavenoException e) {
navigation.navigateTo(MainView.class, MarketView.class, OfferBookChartView.class);
}
});
});
VBox splashScreen = createSplashScreen();
@ -431,13 +433,14 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
return new ListCell<>() {
@Override
protected void updateItem(PriceFeedComboBoxItem item, boolean empty) {
super.updateItem(item, empty);
if (!empty && item != null) {
textProperty().bind(item.displayStringProperty);
} else {
textProperty().unbind();
}
UserThread.execute(() -> {
super.updateItem(item, empty);
if (!empty && item != null) {
textProperty().bind(item.displayStringProperty);
} else {
textProperty().unbind();
}
});
}
};
}
@ -763,8 +766,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> {
buttonWithBadge.textProperty().bind(badgeNumber);
buttonWithBadge.setEnabled(badgeEnabled.get());
badgeEnabled.addListener((observable, oldValue, newValue) -> {
buttonWithBadge.setEnabled(newValue);
buttonWithBadge.refreshBadge();
UserThread.execute(() -> {
buttonWithBadge.setEnabled(newValue);
buttonWithBadge.refreshBadge();
});
});
buttonWithBadge.setPosition(Pos.TOP_RIGHT);

View file

@ -20,7 +20,7 @@ package bisq.desktop.main.account.register;
import bisq.desktop.common.model.ActivatableViewModel;
import bisq.desktop.util.GUIUtil;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.locale.LanguageUtil;
import bisq.core.support.dispute.agent.DisputeAgent;
import bisq.core.support.dispute.agent.DisputeAgentManager;
@ -51,7 +51,7 @@ public abstract class AgentRegistrationViewModel<R extends DisputeAgent, T exten
private final T disputeAgentManager;
protected final User user;
protected final P2PService p2PService;
protected final BtcWalletService walletService;
protected final XmrWalletService xmrWalletService;
protected final KeyRing keyRing;
final BooleanProperty registrationEditDisabled = new SimpleBooleanProperty(true);
@ -73,12 +73,12 @@ public abstract class AgentRegistrationViewModel<R extends DisputeAgent, T exten
public AgentRegistrationViewModel(T disputeAgentManager,
User user,
P2PService p2PService,
BtcWalletService walletService,
XmrWalletService xmrWalletService,
KeyRing keyRing) {
this.disputeAgentManager = disputeAgentManager;
this.user = user;
this.p2PService = p2PService;
this.walletService = walletService;
this.xmrWalletService = xmrWalletService;
this.keyRing = keyRing;
mapChangeListener = change -> {

View file

@ -19,8 +19,7 @@ package bisq.desktop.main.account.register.arbitrator;
import bisq.desktop.main.account.register.AgentRegistrationViewModel;
import bisq.core.btc.model.AddressEntry;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.support.dispute.arbitration.arbitrator.Arbitrator;
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
import bisq.core.user.User;
@ -30,7 +29,6 @@ import bisq.network.p2p.P2PService;
import bisq.common.crypto.KeyRing;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.Date;
@ -40,19 +38,17 @@ public class ArbitratorRegistrationViewModel extends AgentRegistrationViewModel<
public ArbitratorRegistrationViewModel(ArbitratorManager arbitratorManager,
User user,
P2PService p2PService,
BtcWalletService walletService,
XmrWalletService xmrWalletService,
KeyRing keyRing) {
super(arbitratorManager, user, p2PService, walletService, keyRing);
super(arbitratorManager, user, p2PService, xmrWalletService, keyRing);
}
@Override
protected Arbitrator getDisputeAgent(String registrationSignature,
String emailAddress) {
AddressEntry arbitratorAddressEntry = walletService.getArbitratorAddressEntry();
return new Arbitrator(
p2PService.getAddress(),
arbitratorAddressEntry.getPubKey(),
arbitratorAddressEntry.getAddressString(),
xmrWalletService.getWallet().getPrimaryAddress(), // TODO: how is arbitrator address used?
keyRing.getPubKeyRing(),
new ArrayList<>(languageCodes),
new Date().getTime(),

View file

@ -19,7 +19,7 @@ package bisq.desktop.main.account.register.mediator;
import bisq.desktop.main.account.register.AgentRegistrationViewModel;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.support.dispute.mediation.mediator.Mediator;
import bisq.core.support.dispute.mediation.mediator.MediatorManager;
import bisq.core.user.User;
@ -39,9 +39,9 @@ class MediatorRegistrationViewModel extends AgentRegistrationViewModel<Mediator,
public MediatorRegistrationViewModel(MediatorManager mediatorManager,
User user,
P2PService p2PService,
BtcWalletService walletService,
XmrWalletService xmrWalletService,
KeyRing keyRing) {
super(mediatorManager, user, p2PService, walletService, keyRing);
super(mediatorManager, user, p2PService, xmrWalletService, keyRing);
}
@Override

View file

@ -20,7 +20,7 @@ package bisq.desktop.main.account.register.refundagent;
import bisq.desktop.main.account.register.AgentRegistrationViewModel;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.XmrWalletService;
import bisq.core.support.dispute.refund.refundagent.RefundAgent;
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
import bisq.core.user.User;
@ -40,9 +40,9 @@ public class RefundAgentRegistrationViewModel extends AgentRegistrationViewModel
public RefundAgentRegistrationViewModel(RefundAgentManager arbitratorManager,
User user,
P2PService p2PService,
BtcWalletService walletService,
XmrWalletService xmrWalletService,
KeyRing keyRing) {
super(arbitratorManager, user, p2PService, walletService, keyRing);
super(arbitratorManager, user, p2PService, xmrWalletService, keyRing);
}
@Override

View file

@ -52,7 +52,6 @@ import bisq.core.util.coin.CoinUtil;
import bisq.network.p2p.P2PService;
import bisq.common.util.MathUtils;
import bisq.common.util.Tuple2;
import bisq.common.util.Utilities;
import org.bitcoinj.core.Coin;
@ -263,9 +262,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
priceFeedService.setCurrencyCode(tradeCurrencyCode.get());
// We request to get the actual estimated fee
requestTxFee(null);
// 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.
txFeeFromFeeService = feeService.getTxFee(feeTxVsize);
@ -317,16 +313,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
paymentAccount);
}
// This works only if we have already funds in the wallet
public void updateEstimatedFeeAndTxVsize() {
Tuple2<Coin, Integer> estimatedFeeAndTxVsize = createOfferService.getEstimatedFeeAndTxVsize(amount.get(),
direction,
buyerSecurityDeposit.get(),
createOfferService.getSellerSecurityDepositAsDouble(buyerSecurityDeposit.get()));
txFeeFromFeeService = estimatedFeeAndTxVsize.first;
feeTxVsize = estimatedFeeAndTxVsize.second;
}
void onPlaceOffer(Offer offer, TransactionResultHandler resultHandler) {
openOfferManager.placeOffer(offer,
useSavingsWallet,
@ -439,15 +425,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
this.marketPriceMargin = marketPriceMargin;
}
void requestTxFee(@Nullable Runnable actionHandler) {
feeService.requestFees(() -> {
txFeeFromFeeService = feeService.getTxFee(feeTxVsize);
calculateTotalToPay();
if (actionHandler != null)
actionHandler.run();
});
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////////////////

View file

@ -37,7 +37,6 @@ import bisq.core.monetary.Price;
import bisq.core.monetary.Volume;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferDirection;
import bisq.core.offer.OfferPayload;
import bisq.core.offer.OfferRestrictions;
import bisq.core.offer.OfferUtil;
import bisq.core.payment.PaymentAccount;
@ -674,8 +673,6 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
}
void onShowPayFundsScreen(Runnable actionHandler) {
dataModel.updateEstimatedFeeAndTxVsize();
dataModel.requestTxFee(actionHandler);
showPayFundsScreenDisplayed.set(true);
updateSpinnerInfo();
}

View file

@ -24,7 +24,6 @@ import bisq.desktop.main.overlays.popups.Popup;
import bisq.desktop.util.GUIUtil;
import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.btc.TxFeeEstimationService;
import bisq.core.btc.listeners.XmrBalanceListener;
import bisq.core.btc.model.XmrAddressEntry;
import bisq.core.btc.wallet.Restrictions;
@ -36,7 +35,6 @@ import bisq.core.monetary.Price;
import bisq.core.monetary.Volume;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferDirection;
import bisq.core.offer.OfferPayload;
import bisq.core.offer.OfferUtil;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountUtil;
@ -52,7 +50,6 @@ import bisq.core.util.VolumeUtil;
import bisq.core.util.coin.CoinUtil;
import bisq.network.p2p.P2PService;
import bisq.common.util.Tuple2;
import org.bitcoinj.core.Coin;
@ -93,7 +90,6 @@ class TakeOfferDataModel extends OfferDataModel {
private final MempoolService mempoolService;
private final FilterManager filterManager;
final Preferences preferences;
private final TxFeeEstimationService txFeeEstimationService;
private final PriceFeedService priceFeedService;
private final AccountAgeWitnessService accountAgeWitnessService;
private final Navigation navigation;
@ -138,7 +134,6 @@ class TakeOfferDataModel extends OfferDataModel {
MempoolService mempoolService,
FilterManager filterManager,
Preferences preferences,
TxFeeEstimationService txFeeEstimationService,
PriceFeedService priceFeedService,
AccountAgeWitnessService accountAgeWitnessService,
Navigation navigation,
@ -153,7 +148,6 @@ class TakeOfferDataModel extends OfferDataModel {
this.mempoolService = mempoolService;
this.filterManager = filterManager;
this.preferences = preferences;
this.txFeeEstimationService = txFeeEstimationService;
this.priceFeedService = priceFeedService;
this.accountAgeWitnessService = accountAgeWitnessService;
this.navigation = navigation;
@ -277,7 +271,6 @@ class TakeOfferDataModel extends OfferDataModel {
// We don't want that the fee gets updated anymore after we show the funding screen.
void onShowPayFundsScreen() {
estimateTxVsize();
freezeFee = true;
calculateTotalToPay();
}
@ -347,50 +340,6 @@ class TakeOfferDataModel extends OfferDataModel {
}
}
// This works only if have already funds in the wallet
// TODO: There still are issues if we get funded by very small inputs which are causing higher tx fees and the
// changed total required amount is not updated. That will cause a InsufficientMoneyException and the user need to
// start over again. To reproduce keep adding 0.002 BTC amounts while in the funding screen.
// It would require a listener on changed balance and a new fee estimation with a correct recalculation of the required funds.
// Another edge case not handled correctly is: If there are many small inputs and user add a large input later the
// fee estimation is based on the large tx with many inputs but the actual tx will get created with the large input, thus
// leading to a smaller tx and too high fees. Simply updating the fee estimation would lead to changed required funds
// and if funds get higher (if tx get larger) the user would get confused (adding small inputs would increase total required funds).
// So that would require more thoughts how to deal with all those cases.
public void estimateTxVsize() {
int txVsize = 0;
if (xmrWalletService.getWallet().getUnlockedBalance(0).compareTo(new BigInteger("0")) > 0) {
Coin fundsNeededForTrade = getFundsNeededForTrade();
if (isBuyOffer())
fundsNeededForTrade = fundsNeededForTrade.add(amount.get());
// As taker we pay 3 times the fee and currently the fee is the same for all 3 txs (trade fee tx, deposit
// tx and payout tx).
// We should try to change that in future to have the deposit and payout tx with a fixed fee as the vsize is
// there more deterministic.
// The trade fee tx can be in the worst case very large if there are many inputs so if we take that tx alone
// for the fee estimation we would overpay a lot.
// On the other side if we have the best case of a 1 input tx fee tx then it is only 175 vbytes but the
// other 2 txs are different (233 and 169 vbytes) and may get a lower fee/vbyte as intended.
// We apply following model to not overpay too much but be on the safe side as well.
// We sum the taker fee tx and the deposit tx together as it can be assumed that both be in the same block and
// as they are dependent txs the miner will pick both if the fee in total is good enough.
// We make sure that the fee is sufficient to meet our intended fee/vbyte for the larger deposit tx with 233 vbytes.
Tuple2<Coin, Integer> estimatedFeeAndTxVsize = txFeeEstimationService.getEstimatedFeeAndTxVsizeForTaker(fundsNeededForTrade,
getTakerFee());
txFeeFromFeeService = estimatedFeeAndTxVsize.first;
feeTxVsize = estimatedFeeAndTxVsize.second;
} else {
feeTxVsize = 233;
txFeeFromFeeService = txFeePerVbyteFromFeeService.multiply(feeTxVsize);
log.info("We cannot do the fee estimation because there are no funds in the wallet.\nThis is expected " +
"if the user has not funded their wallet yet.\n" +
"In that case we use an estimated tx vsize of 233 vbytes.\n" +
"txFee based on estimated vsize of {} vbytes. feeTxVsize = {} vbytes. Actual tx vsize = {} vbytes. TxFee is {} ({} sat/vbyte)",
feeTxVsize, feeTxVsize, txVsize, txFeeFromFeeService.toFriendlyString(), feeService.getTxFeePerVbyte());
}
}
public void onPaymentAccountSelected(PaymentAccount paymentAccount) {
if (paymentAccount != null) {
this.paymentAccount = paymentAccount;

View file

@ -20,22 +20,16 @@ package bisq.desktop.main.overlays.windows;
import bisq.desktop.Navigation;
import bisq.desktop.components.AutoTooltipButton;
import bisq.desktop.components.BusyAnimation;
import bisq.desktop.components.TitledGroupBg;
import bisq.desktop.components.TxIdTextField;
import bisq.desktop.main.overlays.Overlay;
import bisq.desktop.util.DisplayUtils;
import bisq.desktop.util.GUIUtil;
import bisq.desktop.util.Layout;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.locale.BankUtil;
import bisq.core.locale.CountryUtil;
import bisq.core.locale.Res;
import bisq.core.monetary.Price;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferDirection;
import bisq.core.offer.OfferPayload;
import bisq.core.offer.OfferUtil;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.user.User;
@ -80,7 +74,6 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
private final User user;
private final KeyRing keyRing;
private final Navigation navigation;
private final BtcWalletService btcWalletService;
private Offer offer;
private Coin tradeAmount;
private Price tradePrice;
@ -97,13 +90,11 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
public OfferDetailsWindow(@Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter,
User user,
KeyRing keyRing,
Navigation navigation,
BtcWalletService btcWalletService) {
Navigation navigation) {
this.formatter = formatter;
this.user = user;
this.keyRing = keyRing;
this.navigation = navigation;
this.btcWalletService = btcWalletService;
type = Type.Confirmation;
}
@ -321,7 +312,6 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
rows++;
}
TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.details"), Layout.GROUP_DISTANCE);
addConfirmationLabelTextFieldWithCopyIcon(gridPane, rowIndex, Res.get("shared.offerId"), offer.getId(),
Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE);
addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, Res.get("offerDetailsWindow.makersOnion"),
@ -337,21 +327,6 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> {
formatter.formatCoinWithCode(offer.getSellerSecurityDeposit());
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), value);
// At create offer we do not show the makerFeeTxId
if (!placeOfferHandlerOptional.isPresent()) {
TxIdTextField makerFeeTxIdTextField = addLabelTxIdTextField(gridPane, ++rowIndex,
Res.get("shared.makerFeeTxId"), offer.getOfferFeePaymentTxId()).second;
int finalRows = rows;
OfferUtil.getInvalidMakerFeeTxErrorMessage(offer, btcWalletService)
.ifPresent(errorMsg -> {
makerFeeTxIdTextField.getTextField().setId("address-text-field-error");
GridPane.setRowSpan(titledGroupBg, finalRows + 1);
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.errorMessage"),
errorMsg.replace("\n\n", "\n"));
});
}
if (countryCode != null && !isF2F)
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.countryBank"),
CountryUtil.getNameAndCode(countryCode));

View file

@ -184,29 +184,31 @@ public class MarketPricePresentation {
}
private void setMarketPriceInItems() {
priceFeedComboBoxItems.forEach(item -> {
String currencyCode = item.currencyCode;
MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode);
String priceString;
if (marketPrice != null && marketPrice.isPriceAvailable()) {
priceString = FormattingUtils.formatMarketPrice(marketPrice.getPrice(), currencyCode);
item.setPriceAvailable(true);
item.setExternallyProvidedPrice(marketPrice.isExternallyProvidedPrice());
} else {
priceString = Res.get("shared.na");
item.setPriceAvailable(false);
}
item.setDisplayString(CurrencyUtil.getCurrencyPair(currencyCode) + ": " + priceString);
UserThread.execute(() -> {
priceFeedComboBoxItems.forEach(item -> {
String currencyCode = item.currencyCode;
MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode);
String priceString;
if (marketPrice != null && marketPrice.isPriceAvailable()) {
priceString = FormattingUtils.formatMarketPrice(marketPrice.getPrice(), currencyCode);
item.setPriceAvailable(true);
item.setExternallyProvidedPrice(marketPrice.isExternallyProvidedPrice());
} else {
priceString = Res.get("shared.na");
item.setPriceAvailable(false);
}
item.setDisplayString(CurrencyUtil.getCurrencyPair(currencyCode) + ": " + priceString);
final String code = item.currencyCode;
if (selectedPriceFeedComboBoxItemProperty.get() != null &&
selectedPriceFeedComboBoxItemProperty.get().currencyCode.equals(code)) {
isFiatCurrencyPriceFeedSelected.set(CurrencyUtil.isFiatCurrency(code) && CurrencyUtil.getFiatCurrency(code).isPresent() && item.isPriceAvailable() && item.isExternallyProvidedPrice());
isCryptoCurrencyPriceFeedSelected.set(CurrencyUtil.isCryptoCurrency(code) && CurrencyUtil.getCryptoCurrency(code).isPresent() && item.isPriceAvailable() && item.isExternallyProvidedPrice());
isExternallyProvidedPrice.set(item.isExternallyProvidedPrice());
isPriceAvailable.set(item.isPriceAvailable());
marketPriceUpdated.set(marketPriceUpdated.get() + 1);
}
final String code = item.currencyCode;
if (selectedPriceFeedComboBoxItemProperty.get() != null &&
selectedPriceFeedComboBoxItemProperty.get().currencyCode.equals(code)) {
isFiatCurrencyPriceFeedSelected.set(CurrencyUtil.isFiatCurrency(code) && CurrencyUtil.getFiatCurrency(code).isPresent() && item.isPriceAvailable() && item.isExternallyProvidedPrice());
isCryptoCurrencyPriceFeedSelected.set(CurrencyUtil.isCryptoCurrency(code) && CurrencyUtil.getCryptoCurrency(code).isPresent() && item.isPriceAvailable() && item.isExternallyProvidedPrice());
isExternallyProvidedPrice.set(item.isExternallyProvidedPrice());
isPriceAvailable.set(item.isPriceAvailable());
marketPriceUpdated.set(marketPriceUpdated.get() + 1);
}
});
});
}