mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Code review changes.
This commit is contained in:
parent
1cc42aef77
commit
27dcec00e9
@ -209,21 +209,25 @@ public final class AddressEntryList implements PersistableEnvelope, PersistedDat
|
||||
}
|
||||
|
||||
log.info("swapToAvailable addressEntry to swap={}", addressEntry);
|
||||
boolean setChangedByRemove = entrySet.remove(addressEntry);
|
||||
|
||||
// check if the ADDRESS still has any existing entries, only if not do the add to available.
|
||||
boolean entryWithSameContextAlreadyExist = entrySet.stream().anyMatch(e -> {
|
||||
if (entrySet.remove(addressEntry)) {
|
||||
requestPersistence();
|
||||
}
|
||||
// check if the address still has any existing entries, which would be OCO offers sharing the UTXO
|
||||
boolean entryWithSameContextStillExists = entrySet.stream().anyMatch(e -> {
|
||||
if (addressEntry.getAddressString() != null) {
|
||||
return addressEntry.getAddressString().equals(e.getAddressString()) &&
|
||||
addressEntry.getContext() == addressEntry.getContext();
|
||||
addressEntry.getContext() == e.getContext();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
boolean setChangedByAdd = !entryWithSameContextAlreadyExist && entrySet.add(
|
||||
if (entryWithSameContextStillExists) {
|
||||
return;
|
||||
}
|
||||
// no other uses of the address context remain, so make it available
|
||||
if (entrySet.add(
|
||||
new AddressEntry(addressEntry.getKeyPair(),
|
||||
AddressEntry.Context.AVAILABLE,
|
||||
addressEntry.isSegwit()));
|
||||
if (setChangedByRemove || setChangedByAdd) {
|
||||
addressEntry.isSegwit()))) {
|
||||
requestPersistence();
|
||||
}
|
||||
}
|
||||
|
@ -630,10 +630,19 @@ public class BtcWalletService extends WalletService {
|
||||
.findAny();
|
||||
}
|
||||
|
||||
public AddressEntry createAddressEntryForOcoOffer(AddressEntry orgAddressEntry, String offerId) {
|
||||
AddressEntry newEntry = new AddressEntry(orgAddressEntry.getKeyPair(), orgAddressEntry.getContext(), offerId, true);
|
||||
addressEntryList.addAddressEntry(newEntry);
|
||||
return newEntry;
|
||||
// when a new offer needs to share the reserved amount info from parent offer's address entry
|
||||
public AddressEntry getOrCreateAddressEntry(AddressEntry orgAddressEntry, String offerId) {
|
||||
Optional<AddressEntry> addressEntry = getAddressEntryListAsImmutableList().stream()
|
||||
.filter(e -> offerId.equals(e.getOfferId()))
|
||||
.filter(e -> orgAddressEntry.getContext() == e.getContext())
|
||||
.findAny();
|
||||
if (addressEntry.isPresent()) {
|
||||
return addressEntry.get();
|
||||
} else {
|
||||
AddressEntry newEntry = new AddressEntry(orgAddressEntry.getKeyPair(), orgAddressEntry.getContext(), offerId, true);
|
||||
addressEntryList.addAddressEntry(newEntry);
|
||||
return newEntry;
|
||||
}
|
||||
}
|
||||
|
||||
public AddressEntry getOrCreateAddressEntry(String offerId, AddressEntry.Context context) {
|
||||
|
@ -381,7 +381,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
public void placeOffer(Offer offer,
|
||||
double buyerSecurityDeposit,
|
||||
boolean useSavingsWallet,
|
||||
boolean useOco,
|
||||
boolean useBatchOfferOco,
|
||||
long triggerPrice,
|
||||
TransactionResultHandler resultHandler,
|
||||
ErrorMessageHandler errorMessageHandler) {
|
||||
@ -399,12 +399,14 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
buyerSecurityDeposit,
|
||||
createOfferService.getSellerSecurityDepositAsDouble(buyerSecurityDeposit));
|
||||
|
||||
offer.setPriceFeedService(priceFeedService);
|
||||
if (useBatchOfferOco) {
|
||||
offer.setPriceFeedService(priceFeedService);
|
||||
}
|
||||
|
||||
PlaceOfferModel model = new PlaceOfferModel(offer,
|
||||
reservedFundsForOffer,
|
||||
useSavingsWallet,
|
||||
useOco,
|
||||
useBatchOfferOco,
|
||||
btcWalletService,
|
||||
tradeWalletService,
|
||||
bsqWalletService,
|
||||
@ -419,7 +421,9 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
model,
|
||||
transaction -> {
|
||||
OpenOffer openOffer = new OpenOffer(offer, triggerPrice);
|
||||
openOffer.setState(useOco ? OpenOffer.State.DEACTIVATED : OpenOffer.State.AVAILABLE);
|
||||
if (useBatchOfferOco) {
|
||||
openOffer.setState(OpenOffer.State.DEACTIVATED);
|
||||
}
|
||||
addOpenOfferToList(openOffer);
|
||||
if (!stopped) {
|
||||
startPeriodicRepublishOffersTimer();
|
||||
@ -476,7 +480,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSpam(openOffer)) {
|
||||
if (!canBeEnabled(openOffer.getOffer())) {
|
||||
log.info("{} cannot be enabled, as it has duplicate characteristics with another open offer", openOffer.getShortId());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -624,7 +629,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
getOpenOffersByMakerFeeTxId(offer.getOfferFeePaymentTxId()).forEach(openOffer -> {
|
||||
removeOpenOfferFromList(openOffer);
|
||||
openOffer.setState(OpenOffer.State.CLOSED);
|
||||
if (!offer.getId().equalsIgnoreCase(openOffer.getId())) {
|
||||
if (!offer.getId().equals(openOffer.getId())) {
|
||||
btcWalletService.resetAddressEntriesForOpenOffer(openOffer.getId()); // cleanup OCO clone
|
||||
}
|
||||
offerBookService.removeOffer(openOffer.getOffer().getOfferPayloadBase(),
|
||||
@ -657,8 +662,10 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
}
|
||||
|
||||
public List<OpenOffer> getOpenOffersByMakerFeeTxId(String makerFeeTxId) {
|
||||
String safeSearch = makerFeeTxId == null ? "" : makerFeeTxId;
|
||||
return openOffers.stream().filter(e -> !e.getOffer().isBsqSwapOffer() && e.getOffer().getOfferFeePaymentTxId().equals(safeSearch)).collect(Collectors.toList());
|
||||
return openOffers.stream()
|
||||
.filter(e -> !e.getOffer().isBsqSwapOffer() && e.getOffer().getOfferFeePaymentTxId()
|
||||
.equals(makerFeeTxId == null ? "" : makerFeeTxId))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@ -1178,26 +1185,16 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
openOffer.isBsqSwapOfferHasMissingFunds();
|
||||
}
|
||||
|
||||
public boolean isSpam(OpenOffer newOffer) {
|
||||
// an offer is spam if the user has another open offer on the same ccy, payment method, and reserved UTXO
|
||||
long matchingOffers = openOffers.stream()
|
||||
.filter((openOffer -> !openOffer.getOffer().isBsqSwapOffer()))
|
||||
.filter(openOffer -> !openOffer.isDeactivated())
|
||||
.filter(openOffer -> !openOffer.getShortId().equalsIgnoreCase(newOffer.getShortId()))
|
||||
.filter(openOffer1 -> {
|
||||
Offer newOffer1 = newOffer.getOffer();
|
||||
Offer offer1 = openOffer1.getOffer();
|
||||
return
|
||||
offer1.getOfferFeePaymentTxId().equalsIgnoreCase(newOffer1.getOfferFeePaymentTxId()) &&
|
||||
offer1.getPaymentMethodId().equalsIgnoreCase(newOffer1.getPaymentMethodId()) &&
|
||||
offer1.getCounterCurrencyCode().equalsIgnoreCase(newOffer1.getCounterCurrencyCode()) &&
|
||||
offer1.getBaseCurrencyCode().equalsIgnoreCase(newOffer1.getBaseCurrencyCode());
|
||||
})
|
||||
.count();
|
||||
if (matchingOffers > 0) {
|
||||
log.info("{} is considered spam", newOffer.getShortId());
|
||||
}
|
||||
return matchingOffers > 0;
|
||||
public boolean canBeEnabled(Offer newOffer) {
|
||||
// does the user have another open offer on the same currency, payment method, and reserved UTXO?
|
||||
return openOffers.stream().noneMatch(e ->
|
||||
!e.getOffer().isBsqSwapOffer() &&
|
||||
!e.isDeactivated() &&
|
||||
!e.getId().equals(newOffer.getId()) &&
|
||||
e.getOffer().getOfferFeePaymentTxId().equals(newOffer.getOfferFeePaymentTxId()) &&
|
||||
e.getOffer().getPaymentMethodId().equalsIgnoreCase(newOffer.getPaymentMethodId()) &&
|
||||
e.getOffer().getCounterCurrencyCode().equalsIgnoreCase(newOffer.getCounterCurrencyCode()) &&
|
||||
e.getOffer().getBaseCurrencyCode().equalsIgnoreCase(newOffer.getBaseCurrencyCode()));
|
||||
}
|
||||
|
||||
public boolean safeRemovalOfOcoClone(OpenOffer openOffer) {
|
||||
@ -1205,6 +1202,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
||||
}
|
||||
|
||||
private boolean preventedFromPublishing(OpenOffer openOffer) {
|
||||
return openOffer.isDeactivated() || openOffer.isBsqSwapOfferHasMissingFunds() || isSpam(openOffer);
|
||||
return openOffer.isDeactivated() || openOffer.isBsqSwapOfferHasMissingFunds() || !canBeEnabled(openOffer.getOffer());
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public class PlaceOfferModel implements Model {
|
||||
private final Offer offer;
|
||||
private final Coin reservedFundsForOffer;
|
||||
private final boolean useSavingsWallet;
|
||||
private final boolean useOco;
|
||||
private final boolean useBatchOfferOco;
|
||||
private final BtcWalletService walletService;
|
||||
private final TradeWalletService tradeWalletService;
|
||||
private final BsqWalletService bsqWalletService;
|
||||
@ -67,7 +67,7 @@ public class PlaceOfferModel implements Model {
|
||||
public PlaceOfferModel(Offer offer,
|
||||
Coin reservedFundsForOffer,
|
||||
boolean useSavingsWallet,
|
||||
boolean useOco,
|
||||
boolean useBatchOfferOco,
|
||||
BtcWalletService walletService,
|
||||
TradeWalletService tradeWalletService,
|
||||
BsqWalletService bsqWalletService,
|
||||
@ -81,7 +81,7 @@ public class PlaceOfferModel implements Model {
|
||||
this.offer = offer;
|
||||
this.reservedFundsForOffer = reservedFundsForOffer;
|
||||
this.useSavingsWallet = useSavingsWallet;
|
||||
this.useOco = useOco;
|
||||
this.useBatchOfferOco = useBatchOfferOco;
|
||||
this.walletService = walletService;
|
||||
this.tradeWalletService = tradeWalletService;
|
||||
this.bsqWalletService = bsqWalletService;
|
||||
|
@ -78,7 +78,7 @@ public class PlaceOfferProtocol {
|
||||
}
|
||||
);
|
||||
|
||||
if (model.isUseOco()) {
|
||||
if (model.isUseBatchOfferOco()) {
|
||||
taskRunner.addTasks(
|
||||
ValidateOffer.class,
|
||||
CloneMakerFeeOco.class
|
||||
|
@ -49,7 +49,7 @@ public class CloneMakerFeeOco extends Task<PlaceOfferModel> {
|
||||
for (AddressEntry potentialOcoSource : walletService.getAddressEntries(AddressEntry.Context.RESERVED_FOR_TRADE)) {
|
||||
getTxIdFromAddress(walletService, potentialOcoSource.getAddress()).ifPresent(txId -> {
|
||||
if (txId.equalsIgnoreCase(newOcoOffer.getOfferFeePaymentTxId())) {
|
||||
walletService.createAddressEntryForOcoOffer(potentialOcoSource, newOcoOffer.getId());
|
||||
walletService.getOrCreateAddressEntry(potentialOcoSource, newOcoOffer.getId());
|
||||
newOcoOffer.setState(Offer.State.OFFER_FEE_PAID);
|
||||
complete();
|
||||
}
|
||||
|
@ -77,6 +77,7 @@ shared.deviation=Deviation
|
||||
shared.paymentMethod=Payment method
|
||||
shared.tradeCurrency=Trade currency
|
||||
shared.offerType=Offer type
|
||||
shared.group=Group
|
||||
shared.details=Details
|
||||
shared.address=Address
|
||||
shared.balanceWithCur=Balance in {0}
|
||||
@ -100,6 +101,7 @@ shared.removeOffer=Remove offer
|
||||
shared.dontRemoveOffer=Don't remove offer
|
||||
shared.editOffer=Edit offer
|
||||
shared.duplicateOffer=Duplicate offer
|
||||
shared.duplicateOcoOffer=Duplicate as OCO
|
||||
shared.openLargeQRWindow=Open large QR code window
|
||||
shared.chooseTradingAccount=Choose trading account
|
||||
shared.faq=Visit FAQ page
|
||||
@ -364,6 +366,7 @@ offerbook.timeSinceSigning.tooltip.checkmark.buyBtc=buy BTC from a signed accoun
|
||||
offerbook.timeSinceSigning.tooltip.checkmark.wait=wait a minimum of {0} days
|
||||
offerbook.timeSinceSigning.tooltip.learnMore=Learn more
|
||||
offerbook.xmrAutoConf=Is auto-confirm enabled
|
||||
offerbook.toEnableOffer=Change ccy or payment method to enable offer.
|
||||
|
||||
offerbook.timeSinceSigning.help=When you successfully complete a trade with a peer who has a signed payment account, your payment account is signed.\n\
|
||||
{0} days later, the initial limit of {1} is lifted and your account can sign other peers'' payment accounts.
|
||||
|
@ -134,12 +134,16 @@ class OpenOfferListItem implements FilterableListItem {
|
||||
}
|
||||
}
|
||||
|
||||
public String getOcoGroupAsString() {
|
||||
public String getOcoGroupForSorting() {
|
||||
Offer offer = getOffer();
|
||||
if (offer.isBsqSwapOffer()) {
|
||||
return "";
|
||||
return " ";
|
||||
}
|
||||
return offer.getOfferFeePaymentTxId().substring(0, 4);
|
||||
return offer.getOfferFeePaymentTxId();
|
||||
}
|
||||
|
||||
public String getOcoGroupForDisplay() {
|
||||
return getOcoGroupForSorting().substring(0, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -107,7 +107,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
VOLUME(Res.get("shared.amountMinMax")),
|
||||
PAYMENT_METHOD(Res.get("shared.paymentMethod")),
|
||||
DIRECTION(Res.get("shared.offerType")),
|
||||
GROUP("Group"),
|
||||
GROUP(Res.get("shared.group")),
|
||||
STATUS(Res.get("shared.state"));
|
||||
|
||||
private final String text;
|
||||
@ -209,7 +209,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
deviationColumn.setComparator(Comparator.comparing(OpenOfferListItem::getPriceDeviationAsDouble, Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
triggerPriceColumn.setComparator(Comparator.comparing(o -> o.getOpenOffer().getTriggerPrice(),
|
||||
Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
groupColumn.setComparator(Comparator.comparing(OpenOfferListItem::getOcoGroupAsString));
|
||||
groupColumn.setComparator(Comparator.comparing(OpenOfferListItem::getOcoGroupForSorting));
|
||||
volumeColumn.setComparator(Comparator.comparing(o -> o.getOffer().getVolume(), Comparator.nullsFirst(Comparator.naturalOrder())));
|
||||
dateColumn.setComparator(Comparator.comparing(o -> o.getOffer().getDate()));
|
||||
paymentMethodColumn.setComparator(Comparator.comparing(o -> Res.get(o.getOffer().getPaymentMethod().getId())));
|
||||
@ -223,9 +223,9 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
final ContextMenu rowMenu = new ContextMenu();
|
||||
MenuItem duplicateItem = new MenuItem(Res.get("portfolio.context.offerLikeThis"));
|
||||
duplicateItem.setOnAction((event) -> onDuplicateOffer(row.getItem()));
|
||||
MenuItem duplicateItemOco1 = new MenuItem("Duplicate as OCO");
|
||||
MenuItem duplicateItemOco1 = new MenuItem(Res.get("shared.duplicateOcoOffer"));
|
||||
duplicateItemOco1.setOnAction((event) -> onDuplicateOfferOco(row.getItem(), 1));
|
||||
MenuItem duplicateItemOco5 = new MenuItem("Duplicate as OCO x5");
|
||||
MenuItem duplicateItemOco5 = new MenuItem(Res.get("shared.duplicateOcoOffer") + " x5");
|
||||
duplicateItemOco5.setOnAction((event) -> onDuplicateOfferOco(row.getItem(), 5));
|
||||
rowMenu.getItems().add(duplicateItem);
|
||||
rowMenu.getItems().add(duplicateItemOco1);
|
||||
@ -252,6 +252,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
c.next();
|
||||
if (c.wasAdded() || c.wasRemoved()) {
|
||||
updateNumberOfOffers();
|
||||
updateGroupColumn();
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -266,7 +267,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
|
||||
filterBox.initializeWithCallback(filteredList, tableView, this::updateNumberOfOffers);
|
||||
filterBox.activate();
|
||||
|
||||
updateGroupColumn();
|
||||
updateSelectToggleButtonState();
|
||||
|
||||
selectToggleButton.setOnAction(event -> {
|
||||
@ -300,7 +301,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
columns[ColumnNames.VOLUME.ordinal()] = item.getVolumeAsString();
|
||||
columns[ColumnNames.PAYMENT_METHOD.ordinal()] = item.getPaymentMethodAsString();
|
||||
columns[ColumnNames.DIRECTION.ordinal()] = item.getDirectionLabel();
|
||||
columns[ColumnNames.GROUP.ordinal()] = item.getOcoGroupAsString();
|
||||
columns[ColumnNames.GROUP.ordinal()] = item.getOcoGroupForDisplay();
|
||||
columns[ColumnNames.STATUS.ordinal()] = String.valueOf(!item.getOpenOffer().isDeactivated());
|
||||
return columns;
|
||||
};
|
||||
@ -319,14 +320,12 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
|
||||
private void updateNumberOfOffers() {
|
||||
numItems.setText(Res.get("shared.numItemsLabel", sortedList.size()));
|
||||
groupColumn.setVisible(ocoIsInUse());
|
||||
}
|
||||
|
||||
private boolean ocoIsInUse()
|
||||
{
|
||||
return sortedList.stream()
|
||||
.collect(Collectors.groupingBy(OpenOfferListItem::getOcoGroupAsString, Collectors.counting()))
|
||||
.values().stream().anyMatch(i -> i > 1);
|
||||
private void updateGroupColumn() {
|
||||
groupColumn.setVisible(sortedList.stream()
|
||||
.collect(Collectors.groupingBy(OpenOfferListItem::getOcoGroupForSorting, Collectors.counting()))
|
||||
.values().stream().anyMatch(i -> i > 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -687,11 +686,11 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView
|
||||
getStyleClass().removeAll("offer-disabled");
|
||||
if (item != null) {
|
||||
if (item.isNotPublished()) getStyleClass().add("offer-disabled");
|
||||
Label label = new AutoTooltipLabel(item.getOcoGroupAsString());
|
||||
if (openOfferManager.isSpam(item.getOpenOffer())) {
|
||||
Label label = new AutoTooltipLabel(item.getOcoGroupForDisplay());
|
||||
if (!openOfferManager.canBeEnabled(item.getOpenOffer().getOffer())) {
|
||||
Text icon = getRegularIconForLabel(MaterialDesignIcon.EYE_OFF, label, "opaque-icon");
|
||||
label.setContentDisplay(ContentDisplay.RIGHT);
|
||||
Tooltip.install(icon, new Tooltip("Change ccy or payment method to enable offer."));
|
||||
Tooltip.install(icon, new Tooltip(Res.get("offerbook.toEnableOffer")));
|
||||
}
|
||||
setGraphic(label);
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user