support reserving exact offer amount by splitting output

This commit is contained in:
woodser 2023-06-11 15:28:10 -04:00
parent 0bbb8a4183
commit 722b02f4c9
31 changed files with 424 additions and 173 deletions

View file

@ -95,7 +95,7 @@ class DepositListItem {
}
private void updateUsage(int subaddressIndex, List<MoneroTxWallet> cachedTxs) {
numTxsWithOutputs = XmrWalletService.getTxsWithIncomingOutputs(addressEntry.getSubaddressIndex(), cachedTxs).size();
numTxsWithOutputs = xmrWalletService.getTxsWithIncomingOutputs(addressEntry.getSubaddressIndex(), cachedTxs).size();
usage = subaddressIndex == 0 ? "Base address" : numTxsWithOutputs == 0 ? Res.get("funds.deposit.unused") : Res.get("funds.deposit.usedInTx", numTxsWithOutputs);
}
@ -143,7 +143,7 @@ class DepositListItem {
private MoneroTxWallet getTxWithFewestConfirmations(List<MoneroTxWallet> allIncomingTxs) {
// get txs with incoming outputs to subaddress index
List<MoneroTxWallet> txs = XmrWalletService.getTxsWithIncomingOutputs(addressEntry.getSubaddressIndex(), allIncomingTxs);
List<MoneroTxWallet> txs = xmrWalletService.getTxsWithIncomingOutputs(addressEntry.getSubaddressIndex(), allIncomingTxs);
// get tx with fewest confirmations
MoneroTxWallet highestTx = null;

View file

@ -312,9 +312,7 @@ public class DepositView extends ActivatableView<VBox, Void> {
txsWithIncomingOutputs = xmrWalletService.getTxsWithIncomingOutputs();
// add available address entries and base address
xmrWalletService.getAvailableAddressEntries()
.forEach(e -> observableList.add(new DepositListItem(e, xmrWalletService, formatter, txsWithIncomingOutputs)));
xmrWalletService.getAddressEntries(XmrAddressEntry.Context.BASE_ADDRESS)
xmrWalletService.getAddressEntries()
.forEach(e -> observableList.add(new DepositListItem(e, xmrWalletService, formatter, txsWithIncomingOutputs)));
}

View file

@ -128,6 +128,8 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
private final Predicate<ObjectProperty<Volume>> isNonZeroVolume = (v) -> v.get() != null && !v.get().isZero();
@Getter
protected long triggerPrice;
@Getter
protected boolean splitOutput;
///////////////////////////////////////////////////////////////////////////////////////////
@ -165,6 +167,8 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
shortOfferId = Utilities.getShortId(offerId);
addressEntry = xmrWalletService.getOrCreateAddressEntry(offerId, XmrAddressEntry.Context.OFFER_FUNDING);
splitOutput = preferences.getSplitOfferOutput();
useMarketBasedPrice.set(preferences.isUsePercentageBasedPrice());
buyerSecurityDepositPct.set(Restrictions.getMinBuyerSecurityDepositAsPercent());
@ -295,6 +299,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
openOfferManager.placeOffer(offer,
useSavingsWallet,
triggerPrice,
splitOutput,
resultHandler,
errorMessageHandler);
}
@ -459,6 +464,11 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
}
}
public boolean hasAvailableSplitOutput() {
BigInteger reserveAmount = totalToPay.get();
return openOfferManager.hasAvailableOutput(reserveAmount);
}
///////////////////////////////////////////////////////////////////////////////////////////
// Utils
///////////////////////////////////////////////////////////////////////////////////////////
@ -672,6 +682,10 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
this.triggerPrice = triggerPrice;
}
public void setSplitOutput(boolean splitOutput) {
this.splitOutput = splitOutput;
}
public boolean isUsingRoundedAtmCashAccount() {
return PaymentMethod.isRoundedForAtmCash(paymentAccount.getPaymentMethod().getId());
}

View file

@ -56,6 +56,7 @@ import haveno.desktop.main.overlays.windows.OfferDetailsWindow;
import haveno.desktop.main.overlays.windows.QRCodeWindow;
import haveno.desktop.main.portfolio.PortfolioView;
import haveno.desktop.main.portfolio.openoffer.OpenOffersView;
import haveno.desktop.util.FormBuilder;
import haveno.desktop.util.GUIUtil;
import haveno.desktop.util.Layout;
import javafx.beans.value.ChangeListener;
@ -70,6 +71,7 @@ import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
@ -134,6 +136,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
private TextField currencyTextField;
private AddressTextField addressTextField;
private BalanceTextField balanceTextField;
private CheckBox splitOutputCheckbox;
private FundsTextField totalToPayTextField;
private Label amountDescriptionLabel, priceCurrencyLabel, priceDescriptionLabel, volumeDescriptionLabel,
waitingForFundsLabel, marketBasedPriceLabel, percentagePriceDescriptionLabel, tradeFeeDescriptionLabel,
@ -418,6 +421,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
qrCodeImageView.setVisible(true);
balanceTextField.setVisible(true);
cancelButton2.setVisible(true);
splitOutputCheckbox.setVisible(true);
}
private void updateOfferElementsStyle() {
@ -1088,6 +1092,21 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten
Res.get("shared.tradeWalletBalance"));
balanceTextField.setVisible(false);
splitOutputCheckbox = FormBuilder.addLabelCheckBox(gridPane, ++gridRow,
Res.get("shared.reserveExactAmount"));
GridPane.setHalignment(splitOutputCheckbox, HPos.LEFT);
splitOutputCheckbox.setVisible(false);
splitOutputCheckbox.setSelected(preferences.getSplitOfferOutput());
splitOutputCheckbox.setOnAction(event -> {
boolean selected = splitOutputCheckbox.isSelected();
if (selected != preferences.getSplitOfferOutput()) {
preferences.setSplitOfferOutput(selected);
model.dataModel.setSplitOutput(selected);
}
});
fundingHBox = new HBox();
fundingHBox.setVisible(false);
fundingHBox.setManaged(false);

View file

@ -115,6 +115,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
// If we would change the price representation in the domain we would not be backward compatible
public final StringProperty price = new SimpleStringProperty();
public final StringProperty triggerPrice = new SimpleStringProperty("");
public final BooleanProperty splitOutput = new SimpleBooleanProperty(true);
final StringProperty tradeFee = new SimpleStringProperty();
final StringProperty tradeFeeInXmrWithFiat = new SimpleStringProperty();
final StringProperty tradeFeeCurrencyCode = new SimpleStringProperty();
@ -778,6 +779,10 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext
}
}
public void onSplitOutputCheckboxChanged() {
dataModel.setSplitOutput(splitOutput.get());
}
void onFixPriceToggleChange(boolean fixedPriceSelected) {
inputIsMarketBasedPrice = !fixedPriceSelected;
updateButtonDisableState();

View file

@ -82,6 +82,7 @@ class EditOfferViewModel extends MutableOfferViewModel<EditOfferDataModel> {
triggerPrice.set("");
}
onTriggerPriceTextFieldChanged();
onSplitOutputCheckboxChanged();
}
public void applyOpenOffer(OpenOffer openOffer) {