From 023e2bcd2fc61d227294cf311c39982bd4ff42b2 Mon Sep 17 00:00:00 2001 From: bvcxza <175357591+bvcxza@users.noreply.github.com> Date: Thu, 14 Nov 2024 12:16:13 -0300 Subject: [PATCH 1/6] Fix deviation percent for fixed-price crypto offers (#1411) --- .../desktop/main/offer/offerbook/OfferBookViewModel.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java index f5fdd74509..b0a0f7c1df 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java @@ -402,9 +402,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel { } public Optional getMarketBasedPrice(Offer offer) { - OfferDirection displayDirection = offer.isTraditionalOffer() ? direction : - direction.equals(OfferDirection.BUY) ? OfferDirection.SELL : OfferDirection.BUY; - return priceUtil.getMarketBasedPrice(offer, displayDirection); + return priceUtil.getMarketBasedPrice(offer, direction); } String formatMarketPriceMarginPct(Offer offer) { From 5221782ba044b1ffc23131b8c828e903b9d62d99 Mon Sep 17 00:00:00 2001 From: woodser Date: Wed, 13 Nov 2024 20:12:48 -0500 Subject: [PATCH 2/6] return empty list if no backup files exist --- common/src/main/java/haveno/common/file/FileUtil.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/haveno/common/file/FileUtil.java b/common/src/main/java/haveno/common/file/FileUtil.java index 8bb6ae75a8..ca533cc0d2 100644 --- a/common/src/main/java/haveno/common/file/FileUtil.java +++ b/common/src/main/java/haveno/common/file/FileUtil.java @@ -32,6 +32,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Date; @@ -76,11 +77,11 @@ public class FileUtil { public static List getBackupFiles(File dir, String fileName) { File backupDir = new File(Paths.get(dir.getAbsolutePath(), BACKUP_DIR).toString()); - if (!backupDir.exists()) return null; + if (!backupDir.exists()) return new ArrayList(); String dirName = "backups_" + fileName; if (dirName.contains(".")) dirName = dirName.replace(".", "_"); File backupFileDir = new File(Paths.get(backupDir.getAbsolutePath(), dirName).toString()); - if (!backupFileDir.exists()) return null; + if (!backupFileDir.exists()) return new ArrayList(); File[] files = backupFileDir.listFiles(); return Arrays.asList(files); } From 59d8a8ee44325d525f18a5027fdbe3c37ff47405 Mon Sep 17 00:00:00 2001 From: woodser Date: Wed, 13 Nov 2024 12:00:24 -0500 Subject: [PATCH 3/6] trader can re-open dispute unless payout confirmed --- .../core/support/dispute/DisputeManager.java | 214 +++++++++--------- 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeManager.java b/core/src/main/java/haveno/core/support/dispute/DisputeManager.java index 6fca89f8ea..d6b2469744 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeManager.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeManager.java @@ -359,6 +359,13 @@ public abstract class DisputeManager> extends Sup return; } + // skip if payout is confirmed + if (trade.isPayoutConfirmed()) { + String errorMsg = "Cannot open dispute because payout is already confirmed for " + trade.getClass().getSimpleName() + " " + trade.getId(); + faultHandler.handleFault(errorMsg, new IllegalStateException(errorMsg)); + return; + } + synchronized (disputeList.getObservableList()) { if (disputeList.contains(dispute)) { String msg = "We got a dispute msg that we have already stored. TradeId = " + dispute.getTradeId() + ", DisputeId = " + dispute.getId(); @@ -368,116 +375,109 @@ public abstract class DisputeManager> extends Sup } Optional storedDisputeOptional = findDispute(dispute); - boolean reOpen = storedDisputeOptional.isPresent() && storedDisputeOptional.get().isClosed(); - if (!storedDisputeOptional.isPresent() || reOpen) { + boolean reOpen = storedDisputeOptional.isPresent(); - // add or re-open dispute - if (reOpen) { - dispute = storedDisputeOptional.get(); - } else { - disputeList.add(dispute); - } - - String disputeInfo = getDisputeInfo(dispute); - String sysMsg = dispute.isSupportTicket() ? - Res.get("support.youOpenedTicket", disputeInfo, Version.VERSION) : - Res.get("support.youOpenedDispute", disputeInfo, Version.VERSION); - - ChatMessage chatMessage = new ChatMessage( - getSupportType(), - dispute.getTradeId(), - keyRing.getPubKeyRing().hashCode(), - false, - Res.get("support.systemMsg", sysMsg), - p2PService.getAddress()); - chatMessage.setSystemMessage(true); - dispute.addAndPersistChatMessage(chatMessage); - - // export latest multisig hex - try { - trade.exportMultisigHex(); - } catch (Exception e) { - log.error("Failed to export multisig hex", e); - } - - // create dispute opened message - NodeAddress agentNodeAddress = getAgentNodeAddress(dispute); - DisputeOpenedMessage disputeOpenedMessage = new DisputeOpenedMessage(dispute, - p2PService.getAddress(), - UUID.randomUUID().toString(), - getSupportType(), - trade.getSelf().getUpdatedMultisigHex(), - trade.getArbitrator().getPaymentSentMessage()); - log.info("Send {} to peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + - "chatMessage.uid={}", - disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, - disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), - chatMessage.getUid()); - recordPendingMessage(disputeOpenedMessage.getClass().getSimpleName()); - - // send dispute opened message - trade.setDisputeState(Trade.DisputeState.DISPUTE_REQUESTED); - mailboxMessageService.sendEncryptedMailboxMessage(agentNodeAddress, - dispute.getAgentPubKeyRing(), - disputeOpenedMessage, - new SendMailboxMessageListener() { - @Override - public void onArrived() { - log.info("{} arrived at peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + - "chatMessage.uid={}", - disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, - disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), - chatMessage.getUid()); - clearPendingMessage(); - - // We use the chatMessage wrapped inside the openNewDisputeMessage for - // the state, as that is displayed to the user and we only persist that msg - chatMessage.setArrived(true); - trade.advanceDisputeState(Trade.DisputeState.DISPUTE_REQUESTED); - requestPersistence(); - resultHandler.handleResult(); - } - - @Override - public void onStoredInMailbox() { - log.info("{} stored in mailbox for peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + - "chatMessage.uid={}", - disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, - disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), - chatMessage.getUid()); - clearPendingMessage(); - - // We use the chatMessage wrapped inside the openNewDisputeMessage for - // the state, as that is displayed to the user and we only persist that msg - chatMessage.setStoredInMailbox(true); - requestPersistence(); - resultHandler.handleResult(); - } - - @Override - public void onFault(String errorMessage) { - log.error("{} failed: Peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + - "chatMessage.uid={}, errorMessage={}", - disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, - disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), - chatMessage.getUid(), errorMessage); - - clearPendingMessage(); - // We use the chatMessage wrapped inside the openNewDisputeMessage for - // the state, as that is displayed to the user and we only persist that msg - chatMessage.setSendMessageError(errorMessage); - trade.setDisputeState(Trade.DisputeState.NO_DISPUTE); - requestPersistence(); - faultHandler.handleFault("Sending dispute message failed: " + - errorMessage, new DisputeMessageDeliveryFailedException()); - } - }); + // add or re-open dispute + if (reOpen) { + dispute = storedDisputeOptional.get(); } else { - String msg = "We got a dispute already open for that trade and trading peer.\n" + - "TradeId = " + dispute.getTradeId(); - log.warn(msg); - faultHandler.handleFault(msg, new DisputeAlreadyOpenException()); + disputeList.add(dispute); } + + String disputeInfo = getDisputeInfo(dispute); + String sysMsg = dispute.isSupportTicket() ? + Res.get("support.youOpenedTicket", disputeInfo, Version.VERSION) : + Res.get("support.youOpenedDispute", disputeInfo, Version.VERSION); + + ChatMessage chatMessage = new ChatMessage( + getSupportType(), + dispute.getTradeId(), + keyRing.getPubKeyRing().hashCode(), + false, + Res.get("support.systemMsg", sysMsg), + p2PService.getAddress()); + chatMessage.setSystemMessage(true); + dispute.addAndPersistChatMessage(chatMessage); + + // export latest multisig hex + try { + trade.exportMultisigHex(); + } catch (Exception e) { + log.error("Failed to export multisig hex", e); + } + + // create dispute opened message + NodeAddress agentNodeAddress = getAgentNodeAddress(dispute); + DisputeOpenedMessage disputeOpenedMessage = new DisputeOpenedMessage(dispute, + p2PService.getAddress(), + UUID.randomUUID().toString(), + getSupportType(), + trade.getSelf().getUpdatedMultisigHex(), + trade.getArbitrator().getPaymentSentMessage()); + log.info("Send {} to peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + + "chatMessage.uid={}", + disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, + disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), + chatMessage.getUid()); + recordPendingMessage(disputeOpenedMessage.getClass().getSimpleName()); + + // send dispute opened message + trade.setDisputeState(Trade.DisputeState.DISPUTE_REQUESTED); + mailboxMessageService.sendEncryptedMailboxMessage(agentNodeAddress, + dispute.getAgentPubKeyRing(), + disputeOpenedMessage, + new SendMailboxMessageListener() { + @Override + public void onArrived() { + log.info("{} arrived at peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + + "chatMessage.uid={}", + disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, + disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), + chatMessage.getUid()); + clearPendingMessage(); + + // We use the chatMessage wrapped inside the openNewDisputeMessage for + // the state, as that is displayed to the user and we only persist that msg + chatMessage.setArrived(true); + trade.advanceDisputeState(Trade.DisputeState.DISPUTE_REQUESTED); + requestPersistence(); + resultHandler.handleResult(); + } + + @Override + public void onStoredInMailbox() { + log.info("{} stored in mailbox for peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + + "chatMessage.uid={}", + disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, + disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), + chatMessage.getUid()); + clearPendingMessage(); + + // We use the chatMessage wrapped inside the openNewDisputeMessage for + // the state, as that is displayed to the user and we only persist that msg + chatMessage.setStoredInMailbox(true); + requestPersistence(); + resultHandler.handleResult(); + } + + @Override + public void onFault(String errorMessage) { + log.error("{} failed: Peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + + "chatMessage.uid={}, errorMessage={}", + disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, + disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), + chatMessage.getUid(), errorMessage); + + clearPendingMessage(); + // We use the chatMessage wrapped inside the openNewDisputeMessage for + // the state, as that is displayed to the user and we only persist that msg + chatMessage.setSendMessageError(errorMessage); + trade.setDisputeState(Trade.DisputeState.NO_DISPUTE); + requestPersistence(); + faultHandler.handleFault("Sending dispute message failed: " + + errorMessage, new DisputeMessageDeliveryFailedException()); + } + }); } requestPersistence(); From 86e67d384cc5038ed6a10f151f7ca7966b62df10 Mon Sep 17 00:00:00 2001 From: woodser Date: Wed, 13 Nov 2024 18:41:57 -0500 Subject: [PATCH 4/6] new dispute state is considered open --- core/src/main/java/haveno/core/support/dispute/Dispute.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/haveno/core/support/dispute/Dispute.java b/core/src/main/java/haveno/core/support/dispute/Dispute.java index 268cb3e272..15595b8893 100644 --- a/core/src/main/java/haveno/core/support/dispute/Dispute.java +++ b/core/src/main/java/haveno/core/support/dispute/Dispute.java @@ -467,7 +467,7 @@ public final class Dispute implements NetworkPayload, PersistablePayload { } public boolean isOpen() { - return this.disputeState == State.OPEN || this.disputeState == State.REOPENED; + return isNew() || this.disputeState == State.OPEN || this.disputeState == State.REOPENED; } public boolean isClosed() { From c9e992442c3a746e3cd8c7f7dd5a98fd1bbe60ef Mon Sep 17 00:00:00 2001 From: woodser Date: Fri, 15 Nov 2024 09:27:06 -0500 Subject: [PATCH 5/6] bump version to 1.0.14 --- build.gradle | 2 +- common/src/main/java/haveno/common/app/Version.java | 2 +- desktop/package/macosx/Info.plist | 4 ++-- seednode/src/main/java/haveno/seednode/SeedNodeMain.java | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 81a315ad50..d35c6bd05c 100644 --- a/build.gradle +++ b/build.gradle @@ -610,7 +610,7 @@ configure(project(':desktop')) { apply plugin: 'com.github.johnrengelman.shadow' apply from: 'package/package.gradle' - version = '1.0.13-SNAPSHOT' + version = '1.0.14-SNAPSHOT' jar.manifest.attributes( "Implementation-Title": project.name, diff --git a/common/src/main/java/haveno/common/app/Version.java b/common/src/main/java/haveno/common/app/Version.java index 14e5a6c7c8..2b4b01b036 100644 --- a/common/src/main/java/haveno/common/app/Version.java +++ b/common/src/main/java/haveno/common/app/Version.java @@ -28,7 +28,7 @@ import static com.google.common.base.Preconditions.checkArgument; public class Version { // The application versions // We use semantic versioning with major, minor and patch - public static final String VERSION = "1.0.13"; + public static final String VERSION = "1.0.14"; /** * Holds a list of the tagged resource files for optimizing the getData requests. diff --git a/desktop/package/macosx/Info.plist b/desktop/package/macosx/Info.plist index 2d4618f7a0..31325683fd 100644 --- a/desktop/package/macosx/Info.plist +++ b/desktop/package/macosx/Info.plist @@ -5,10 +5,10 @@ CFBundleVersion - 1.0.13 + 1.0.14 CFBundleShortVersionString - 1.0.13 + 1.0.14 CFBundleExecutable Haveno diff --git a/seednode/src/main/java/haveno/seednode/SeedNodeMain.java b/seednode/src/main/java/haveno/seednode/SeedNodeMain.java index b1da3d3e19..e0f5ad7c3e 100644 --- a/seednode/src/main/java/haveno/seednode/SeedNodeMain.java +++ b/seednode/src/main/java/haveno/seednode/SeedNodeMain.java @@ -41,7 +41,7 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class SeedNodeMain extends ExecutableForAppWithP2p { private static final long CHECK_CONNECTION_LOSS_SEC = 30; - private static final String VERSION = "1.0.13"; + private static final String VERSION = "1.0.14"; private SeedNode seedNode; private Timer checkConnectionLossTime; From 264cb5f0acd2ebc4523de2e092eb7697dcc52956 Mon Sep 17 00:00:00 2001 From: woodser Date: Fri, 15 Nov 2024 10:41:42 -0500 Subject: [PATCH 6/6] fix inverted buy/sell label on make or take crypto offer --- .../haveno/desktop/main/offer/MutableOfferView.java | 8 ++++---- .../desktop/main/offer/takeoffer/TakeOfferView.java | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferView.java b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferView.java index db008e93ff..3c6ed09788 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferView.java @@ -308,7 +308,7 @@ public abstract class MutableOfferView> exten if (CurrencyUtil.isTraditionalCurrency(tradeCurrency.getCode())) { placeOfferButtonLabel = Res.get("createOffer.placeOfferButton", Res.get("shared.buy")); } else { - placeOfferButtonLabel = Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.buy"), tradeCurrency.getCode()); + placeOfferButtonLabel = Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.sell"), tradeCurrency.getCode()); } nextButton.setId("buy-button"); fundFromSavingsWalletButton.setId("buy-button"); @@ -317,7 +317,7 @@ public abstract class MutableOfferView> exten if (CurrencyUtil.isTraditionalCurrency(tradeCurrency.getCode())) { placeOfferButtonLabel = Res.get("createOffer.placeOfferButton", Res.get("shared.sell")); } else { - placeOfferButtonLabel = Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.sell"), tradeCurrency.getCode()); + placeOfferButtonLabel = Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.buy"), tradeCurrency.getCode()); } nextButton.setId("sell-button"); fundFromSavingsWalletButton.setId("sell-button"); @@ -707,10 +707,10 @@ public abstract class MutableOfferView> exten triggerPriceInputTextField.clear(); if (!CurrencyUtil.isTraditionalCurrency(newValue)) { if (model.isShownAsBuyOffer()) { - placeOfferButton.updateText(Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.buy"), + placeOfferButton.updateText(Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.sell"), model.getTradeCurrency().getCode())); } else { - placeOfferButton.updateText(Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.sell"), + placeOfferButton.updateText(Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.buy"), model.getTradeCurrency().getCode())); } } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferView.java b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferView.java index 1b0867ef7d..6f4e9635c1 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferView.java @@ -306,12 +306,12 @@ public class TakeOfferView extends ActivatableViewAndModel