diff --git a/core/src/main/java/bisq/core/trade/AutoConfirmResult.java b/core/src/main/java/bisq/core/trade/AutoConfirmResult.java index 29f6bce8ac..bed7463d0f 100644 --- a/core/src/main/java/bisq/core/trade/AutoConfirmResult.java +++ b/core/src/main/java/bisq/core/trade/AutoConfirmResult.java @@ -17,115 +17,57 @@ package bisq.core.trade; -import bisq.core.locale.Res; - -import bisq.common.proto.ProtoUtil; - -import lombok.Value; -import lombok.extern.slf4j.Slf4j; +import lombok.EqualsAndHashCode; +import lombok.Getter; import javax.annotation.Nullable; -@Slf4j -@Value -public class AutoConfirmResult { - public enum State { - UNDEFINED, - FEATURE_DISABLED, - TX_NOT_FOUND, - TX_NOT_CONFIRMED, - PROOF_OK, - CONNECTION_FAIL, - API_FAILURE, - API_INVALID, - TX_KEY_REUSED, - TX_HASH_INVALID, - TX_KEY_INVALID, - ADDRESS_INVALID, - NO_MATCH_FOUND, - AMOUNT_NOT_MATCHING, - TRADE_LIMIT_EXCEEDED, - TRADE_DATE_NOT_MATCHING - } +/** + * Base class for AutoConfirm implementations + */ +@EqualsAndHashCode +@Getter +public abstract class AutoConfirmResult { - // Only state gets persisted - private final State state; - - private final transient int confirmCount; - private final transient int confirmsRequired; - - - /////////////////////////////////////////////////////////////////////////////////////////// - // Constructor - /////////////////////////////////////////////////////////////////////////////////////////// - - public AutoConfirmResult(State state) { - this(state, 0, 0); - } - - // alternate constructor for showing confirmation progress information - public AutoConfirmResult(State state, int confirmCount, int confirmsRequired) { - this.state = state; - this.confirmCount = confirmCount; - this.confirmsRequired = confirmsRequired; - } - - // alternate constructor for error scenarios - public AutoConfirmResult(State state, @Nullable String errorMsg) { - this(state, 0, 0); - - if (isErrorState()) { - log.error(errorMsg != null ? errorMsg : state.toString()); + public static AutoConfirmResult fromCurrencyCode(String currencyCode) { + switch (currencyCode) { + case "XMR": + return new XmrAutoConfirmResult(); + default: + return null; } } + private final String stateName; + + protected AutoConfirmResult(String stateName) { + this.stateName = stateName; + } + /////////////////////////////////////////////////////////////////////////////////////////// // PROTOBUF /////////////////////////////////////////////////////////////////////////////////////////// - public protobuf.AutoConfirmResult toProtoMessage() { - return protobuf.AutoConfirmResult.newBuilder().setStateName(state.name()).build(); + // We use fromProto as kind of factory method to get the specific AutoConfirmResult + @Nullable + static AutoConfirmResult fromProto(protobuf.AutoConfirmResult proto, String currencyCode) { + switch (currencyCode) { + case "XMR": + return XmrAutoConfirmResult.fromProto(proto); + default: + return null; + } } - public static AutoConfirmResult fromProto(protobuf.AutoConfirmResult proto) { - AutoConfirmResult.State state = ProtoUtil.enumFromProto(AutoConfirmResult.State.class, proto.getStateName()); - return state != null ? new AutoConfirmResult(state) : new AutoConfirmResult(State.UNDEFINED); - - } + public abstract protobuf.AutoConfirmResult toProtoMessage(); /////////////////////////////////////////////////////////////////////////////////////////// // API /////////////////////////////////////////////////////////////////////////////////////////// - public String getTextStatus() { - switch (state) { - case TX_NOT_CONFIRMED: - return Res.get("portfolio.pending.autoConfirmPending") - + " " + confirmCount - + "/" + confirmsRequired; - case TX_NOT_FOUND: - return Res.get("portfolio.pending.autoConfirmTxNotFound"); - case FEATURE_DISABLED: - return Res.get("portfolio.pending.autoConfirmDisabled"); - case PROOF_OK: - return Res.get("portfolio.pending.autoConfirmSuccess"); - default: - // any other statuses we display the enum name - return this.state.toString(); - } - } + abstract public boolean isSuccessState(); - public boolean isPendingState() { - return (state == State.TX_NOT_FOUND || state == State.TX_NOT_CONFIRMED); - } - - public boolean isSuccessState() { - return (state == State.PROOF_OK); - } - - public boolean isErrorState() { - return (!isPendingState() && !isSuccessState()); - } + abstract public String getTextStatus(); } diff --git a/core/src/main/java/bisq/core/trade/Trade.java b/core/src/main/java/bisq/core/trade/Trade.java index 5ca75ca76d..dc765d5200 100644 --- a/core/src/main/java/bisq/core/trade/Trade.java +++ b/core/src/main/java/bisq/core/trade/Trade.java @@ -435,7 +435,10 @@ public abstract class Trade implements Tradable, Model { @Setter private String counterCurrencyExtraData; - @Getter + public AutoConfirmResult getAutoConfirmResult() { + return autoConfirmResult != null ? autoConfirmResult : AutoConfirmResult.fromCurrencyCode(checkNotNull(offer).getCurrencyCode()); + } + @Nullable private AutoConfirmResult autoConfirmResult; @@ -595,7 +598,7 @@ public abstract class Trade implements Tradable, Model { trade.setLockTime(proto.getLockTime()); trade.setLastRefreshRequestDate(proto.getLastRefreshRequestDate()); trade.setCounterCurrencyExtraData(ProtoUtil.stringOrNullFromProto(proto.getCounterCurrencyExtraData())); - trade.setAutoConfirmResult(AutoConfirmResult.fromProto(proto.getAutoConfirmResult())); + trade.setAutoConfirmResult(AutoConfirmResult.fromProto(proto.getAutoConfirmResult(), checkNotNull(trade.getOffer()).getCurrencyCode())); trade.chatMessages.addAll(proto.getChatMessageList().stream() .map(ChatMessage::fromPayloadProto) @@ -625,7 +628,7 @@ public abstract class Trade implements Tradable, Model { User user, FilterManager filterManager, AccountAgeWitnessService accountAgeWitnessService, - AutoConfirmationManager autoConfirmationManager, + XmrAutoConfirmationManager xmrAutoConfirmationManager, TradeStatisticsManager tradeStatisticsManager, ArbitratorManager arbitratorManager, MediatorManager mediatorManager, @@ -645,7 +648,7 @@ public abstract class Trade implements Tradable, Model { user, filterManager, accountAgeWitnessService, - autoConfirmationManager, + xmrAutoConfirmationManager, tradeStatisticsManager, arbitratorManager, mediatorManager, diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index 3a7cd125b3..70ecd216c8 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -126,7 +126,7 @@ public class TradeManager implements PersistedDataHost { private final TradeStatisticsManager tradeStatisticsManager; private final ReferralIdService referralIdService; private final AccountAgeWitnessService accountAgeWitnessService; - private final AutoConfirmationManager autoConfirmationManager; + private final XmrAutoConfirmationManager xmrAutoConfirmationManager; private final ArbitratorManager arbitratorManager; private final MediatorManager mediatorManager; private final RefundAgentManager refundAgentManager; @@ -168,7 +168,7 @@ public class TradeManager implements PersistedDataHost { TradeStatisticsManager tradeStatisticsManager, ReferralIdService referralIdService, AccountAgeWitnessService accountAgeWitnessService, - AutoConfirmationManager autoConfirmationManager, + XmrAutoConfirmationManager xmrAutoConfirmationManager, ArbitratorManager arbitratorManager, MediatorManager mediatorManager, RefundAgentManager refundAgentManager, @@ -191,7 +191,7 @@ public class TradeManager implements PersistedDataHost { this.tradeStatisticsManager = tradeStatisticsManager; this.referralIdService = referralIdService; this.accountAgeWitnessService = accountAgeWitnessService; - this.autoConfirmationManager = autoConfirmationManager; + this.xmrAutoConfirmationManager = xmrAutoConfirmationManager; this.arbitratorManager = arbitratorManager; this.mediatorManager = mediatorManager; this.refundAgentManager = refundAgentManager; @@ -436,7 +436,7 @@ public class TradeManager implements PersistedDataHost { user, filterManager, accountAgeWitnessService, - autoConfirmationManager, + xmrAutoConfirmationManager, tradeStatisticsManager, arbitratorManager, mediatorManager, diff --git a/core/src/main/java/bisq/core/trade/XmrAutoConfirmResult.java b/core/src/main/java/bisq/core/trade/XmrAutoConfirmResult.java new file mode 100644 index 0000000000..4bce7bedf1 --- /dev/null +++ b/core/src/main/java/bisq/core/trade/XmrAutoConfirmResult.java @@ -0,0 +1,136 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.trade; + +import bisq.core.locale.Res; + +import bisq.common.proto.ProtoUtil; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import javax.annotation.Nullable; + +@Slf4j +@Getter +@EqualsAndHashCode(callSuper = true) +public class XmrAutoConfirmResult extends AutoConfirmResult { + public enum State { + UNDEFINED, + FEATURE_DISABLED, + TX_NOT_FOUND, + TX_NOT_CONFIRMED, + PROOF_OK, + CONNECTION_FAIL, + API_FAILURE, + API_INVALID, + TX_KEY_REUSED, + TX_HASH_INVALID, + TX_KEY_INVALID, + ADDRESS_INVALID, + NO_MATCH_FOUND, + AMOUNT_NOT_MATCHING, + TRADE_LIMIT_EXCEEDED, + TRADE_DATE_NOT_MATCHING + } + + private final State state; + private final transient int confirmCount; + private final transient int confirmsRequired; + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + public XmrAutoConfirmResult() { + this(State.UNDEFINED, 0, 0); + } + + public XmrAutoConfirmResult(State state) { + this(state, 0, 0); + } + + // alternate constructor for showing confirmation progress information + public XmrAutoConfirmResult(State state, int confirmCount, int confirmsRequired) { + super(state.name()); + this.state = state; + this.confirmCount = confirmCount; + this.confirmsRequired = confirmsRequired; + } + + // alternate constructor for error scenarios + public XmrAutoConfirmResult(State state, @Nullable String errorMsg) { + this(state, 0, 0); + + if (isErrorState()) { + log.error(errorMsg != null ? errorMsg : state.toString()); + } + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // PROTOBUF + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public protobuf.AutoConfirmResult toProtoMessage() { + return protobuf.AutoConfirmResult.newBuilder().setStateName(state.name()).build(); + } + + public static XmrAutoConfirmResult fromProto(protobuf.AutoConfirmResult proto) { + XmrAutoConfirmResult.State state = ProtoUtil.enumFromProto(XmrAutoConfirmResult.State.class, proto.getStateName()); + return state != null ? new XmrAutoConfirmResult(state) : new XmrAutoConfirmResult(State.UNDEFINED); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // API + /////////////////////////////////////////////////////////////////////////////////////////// + + public String getTextStatus() { + switch (state) { + case TX_NOT_CONFIRMED: + return Res.get("portfolio.pending.autoConfirmPending") + + " " + confirmCount + + "/" + confirmsRequired; + case TX_NOT_FOUND: + return Res.get("portfolio.pending.autoConfirmTxNotFound"); + case FEATURE_DISABLED: + return Res.get("portfolio.pending.autoConfirmDisabled"); + case PROOF_OK: + return Res.get("portfolio.pending.autoConfirmSuccess"); + default: + // any other statuses we display the enum name + return this.state.toString(); + } + } + + public boolean isPendingState() { + return (state == State.TX_NOT_FOUND || state == State.TX_NOT_CONFIRMED); + } + + public boolean isSuccessState() { + return (state == State.PROOF_OK); + } + + public boolean isErrorState() { + return (!isPendingState() && !isSuccessState()); + } +} diff --git a/core/src/main/java/bisq/core/trade/AutoConfirmationManager.java b/core/src/main/java/bisq/core/trade/XmrAutoConfirmationManager.java similarity index 88% rename from core/src/main/java/bisq/core/trade/AutoConfirmationManager.java rename to core/src/main/java/bisq/core/trade/XmrAutoConfirmationManager.java index 6f9f2bce8b..67a6bbeeab 100644 --- a/core/src/main/java/bisq/core/trade/AutoConfirmationManager.java +++ b/core/src/main/java/bisq/core/trade/XmrAutoConfirmationManager.java @@ -20,6 +20,7 @@ package bisq.core.trade; import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.btc.setup.WalletsSetup; import bisq.core.filter.FilterManager; +import bisq.core.monetary.Volume; import bisq.core.offer.Offer; import bisq.core.payment.payload.AssetsAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload; @@ -49,7 +50,7 @@ import static com.google.common.base.Preconditions.checkNotNull; @Slf4j @Singleton -public class AutoConfirmationManager { +public class XmrAutoConfirmationManager { private final FilterManager filterManager; private final Preferences preferences; @@ -66,15 +67,15 @@ public class AutoConfirmationManager { /////////////////////////////////////////////////////////////////////////////////////////// @Inject - AutoConfirmationManager(FilterManager filterManager, - Preferences preferences, - XmrTransferProofService xmrTransferProofService, - ClosedTradableManager closedTradableManager, - FailedTradesManager failedTradesManager, - P2PService p2PService, - WalletsSetup walletsSetup, - AccountAgeWitnessService accountAgeWitnessService - ) { + XmrAutoConfirmationManager(FilterManager filterManager, + Preferences preferences, + XmrTransferProofService xmrTransferProofService, + ClosedTradableManager closedTradableManager, + FailedTradesManager failedTradesManager, + P2PService p2PService, + WalletsSetup walletsSetup, + AccountAgeWitnessService accountAgeWitnessService + ) { this.filterManager = filterManager; this.preferences = preferences; this.xmrTransferProofService = xmrTransferProofService; @@ -153,7 +154,7 @@ public class AutoConfirmationManager { if (alreadyUsed) { String message = "Peer used the XMR tx key already at another trade with trade ID " + t.getId() + ". This might be a scam attempt."; - trade.setAutoConfirmResult(new AutoConfirmResult(AutoConfirmResult.State.TX_KEY_REUSED, message)); + trade.setAutoConfirmResult(new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TX_KEY_REUSED, message)); } return alreadyUsed; }); @@ -163,23 +164,24 @@ public class AutoConfirmationManager { } if (!preferences.getAutoConfirmSettings().enabled || this.isAutoConfDisabledByFilter()) { - trade.setAutoConfirmResult(new AutoConfirmResult(AutoConfirmResult.State.FEATURE_DISABLED, null)); + trade.setAutoConfirmResult(new XmrAutoConfirmResult(XmrAutoConfirmResult.State.FEATURE_DISABLED, null)); return; } Coin tradeAmount = trade.getTradeAmount(); Coin tradeLimit = Coin.valueOf(preferences.getAutoConfirmSettings().tradeLimit); - if (tradeAmount.isGreaterThan(tradeLimit)) { + if (tradeAmount != null && tradeAmount.isGreaterThan(tradeLimit)) { log.warn("Trade amount {} is higher than settings limit {}, will not attempt auto-confirm", tradeAmount.toFriendlyString(), tradeLimit.toFriendlyString()); - trade.setAutoConfirmResult(new AutoConfirmResult(AutoConfirmResult.State.TRADE_LIMIT_EXCEEDED, null)); + trade.setAutoConfirmResult(new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TRADE_LIMIT_EXCEEDED, null)); return; } String address = sellersAssetsAccountPayload.getAddress(); // XMR satoshis have 12 decimal places vs. bitcoin's 8 - long amountXmr = offer.getVolumeByAmount(tradeAmount).getValue() * 10000L; + Volume volume = offer.getVolumeByAmount(tradeAmount); + long amountXmr = volume != null ? volume.getValue() * 10000L : 0L; int confirmsRequired = preferences.getAutoConfirmSettings().requiredConfirmations; - trade.setAutoConfirmResult(new AutoConfirmResult(AutoConfirmResult.State.TX_NOT_FOUND)); + trade.setAutoConfirmResult(new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TX_NOT_FOUND)); List serviceAddresses = preferences.getAutoConfirmSettings().serviceAddresses; txProofResultsPending.put(trade.getId(), serviceAddresses.size()); // need result from each service address for (String serviceAddress : serviceAddresses) { @@ -204,7 +206,7 @@ public class AutoConfirmationManager { } } - private boolean handleProofResult(AutoConfirmResult result, Trade trade) { + private boolean handleProofResult(XmrAutoConfirmResult result, Trade trade) { boolean success = true; boolean failure = false; @@ -250,8 +252,10 @@ public class AutoConfirmationManager { } accountAgeWitnessService.maybeSignWitness(trade); // transition the trade to step 4: - ((SellerTrade) trade).onFiatPaymentReceived(() -> { }, - errorMessage -> { }); + ((SellerTrade) trade).onFiatPaymentReceived(() -> { + }, + errorMessage -> { + }); return success; } diff --git a/core/src/main/java/bisq/core/trade/asset/xmr/XmrProofInfo.java b/core/src/main/java/bisq/core/trade/asset/xmr/XmrProofInfo.java index 64a852a8c2..ebbbee968b 100644 --- a/core/src/main/java/bisq/core/trade/asset/xmr/XmrProofInfo.java +++ b/core/src/main/java/bisq/core/trade/asset/xmr/XmrProofInfo.java @@ -17,7 +17,7 @@ package bisq.core.trade.asset.xmr; -import bisq.core.trade.AutoConfirmResult; +import bisq.core.trade.XmrAutoConfirmResult; import bisq.asset.CryptoNoteAddressValidator; @@ -68,57 +68,57 @@ public class XmrProofInfo { return txHash + "|" + serviceAddress; } - public AutoConfirmResult checkApiResponse(String jsonTxt) { + public XmrAutoConfirmResult checkApiResponse(String jsonTxt) { try { JsonObject json = new Gson().fromJson(jsonTxt, JsonObject.class); if (json == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Empty json"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Empty json"); } // there should always be "data" and "status" at the top level if (json.get("data") == null || !json.get("data").isJsonObject() || json.get("status") == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing data / status fields"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing data / status fields"); } JsonObject jsonData = json.get("data").getAsJsonObject(); String jsonStatus = json.get("status").getAsString(); if (jsonStatus.matches("fail")) { // the API returns "fail" until the transaction has successfully reached the mempool. // we return TX_NOT_FOUND which will cause a retry later - return new AutoConfirmResult(AutoConfirmResult.State.TX_NOT_FOUND, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TX_NOT_FOUND, null); } else if (!jsonStatus.matches("success")) { - return new AutoConfirmResult(AutoConfirmResult.State.API_FAILURE, "Unhandled status value"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_FAILURE, "Unhandled status value"); } // validate that the address matches JsonElement jsonAddress = jsonData.get("address"); if (jsonAddress == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing address field"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing address field"); } else { String expectedAddressHex = CryptoNoteAddressValidator.convertToRawHex(this.recipientAddress); if (!jsonAddress.getAsString().equalsIgnoreCase(expectedAddressHex)) { log.warn("address {}, expected: {}", jsonAddress.getAsString(), expectedAddressHex); - return new AutoConfirmResult(AutoConfirmResult.State.ADDRESS_INVALID, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.ADDRESS_INVALID, null); } } // validate that the txhash matches JsonElement jsonTxHash = jsonData.get("tx_hash"); if (jsonTxHash == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing tx_hash field"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing tx_hash field"); } else { if (!jsonTxHash.getAsString().equalsIgnoreCase(txHash)) { log.warn("txHash {}, expected: {}", jsonTxHash.getAsString(), txHash); - return new AutoConfirmResult(AutoConfirmResult.State.TX_HASH_INVALID, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TX_HASH_INVALID, null); } } // validate that the txkey matches JsonElement jsonViewkey = jsonData.get("viewkey"); if (jsonViewkey == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing viewkey field"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing viewkey field"); } else { if (!jsonViewkey.getAsString().equalsIgnoreCase(this.txKey)) { log.warn("viewkey {}, expected: {}", jsonViewkey.getAsString(), txKey); - return new AutoConfirmResult(AutoConfirmResult.State.TX_KEY_INVALID, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TX_KEY_INVALID, null); } } @@ -126,7 +126,7 @@ public class XmrProofInfo { // (except that in dev mode we let this check pass anyway) JsonElement jsonTimestamp = jsonData.get("tx_timestamp"); if (jsonTimestamp == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing tx_timestamp field"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing tx_timestamp field"); } else { long tradeDateSeconds = tradeDate.getTime() / 1000; long difference = tradeDateSeconds - jsonTimestamp.getAsLong(); @@ -134,7 +134,7 @@ public class XmrProofInfo { if (difference > TimeUnit.HOURS.toSeconds(2) && !DevEnv.isDevMode()) { log.warn("tx_timestamp {}, tradeDate: {}, difference {}", jsonTimestamp.getAsLong(), tradeDateSeconds, difference); - return new AutoConfirmResult(AutoConfirmResult.State.TRADE_DATE_NOT_MATCHING, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TRADE_DATE_NOT_MATCHING, null); } } @@ -142,7 +142,7 @@ public class XmrProofInfo { int confirmations; JsonElement jsonConfs = jsonData.get("tx_confirmations"); if (jsonConfs == null) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing tx_confirmations field"); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing tx_confirmations field"); } else { confirmations = jsonConfs.getAsInt(); log.info("Confirmations: {}, xmr txHash: {}", confirmations, txHash); @@ -161,23 +161,23 @@ public class XmrProofInfo { if (jsonAmount == amount || DevEnv.isDevMode()) { // any amount ok in dev mode if (confirmations < confirmsRequired) // we return TX_NOT_CONFIRMED which will cause a retry later - return new AutoConfirmResult(AutoConfirmResult.State.TX_NOT_CONFIRMED, confirmations, confirmsRequired); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TX_NOT_CONFIRMED, confirmations, confirmsRequired); else - return new AutoConfirmResult(AutoConfirmResult.State.PROOF_OK, confirmations, confirmsRequired); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.PROOF_OK, confirmations, confirmsRequired); } } } // None of the outputs had a match entry if (!anyMatchFound) { - return new AutoConfirmResult(AutoConfirmResult.State.NO_MATCH_FOUND, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.NO_MATCH_FOUND, null); } // reaching this point means there was no matching amount - return new AutoConfirmResult(AutoConfirmResult.State.AMOUNT_NOT_MATCHING, null); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.AMOUNT_NOT_MATCHING, null); } catch (JsonParseException | NullPointerException e) { - return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, e.toString()); + return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, e.toString()); } } } diff --git a/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofRequester.java b/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofRequester.java index 53b8293b1f..1003e05429 100644 --- a/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofRequester.java +++ b/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofRequester.java @@ -17,7 +17,7 @@ package bisq.core.trade.asset.xmr; -import bisq.core.trade.AutoConfirmResult; +import bisq.core.trade.XmrAutoConfirmResult; import bisq.network.Socks5ProxyProvider; @@ -50,7 +50,7 @@ public class XmrTransferProofRequester { "XmrTransferProofRequester", 3, 5, 10 * 60); private final XmrTxProofHttpClient httpClient; private final XmrProofInfo xmrProofInfo; - private final Consumer resultHandler; + private final Consumer resultHandler; private final FaultHandler faultHandler; private boolean terminated; @@ -63,7 +63,7 @@ public class XmrTransferProofRequester { XmrTransferProofRequester(@Nullable Socks5ProxyProvider socks5ProxyProvider, XmrProofInfo xmrProofInfo, - Consumer resultHandler, + Consumer resultHandler, FaultHandler faultHandler) { this.httpClient = new XmrTxProofHttpClient(socks5ProxyProvider); this.httpClient.setBaseUrl("http://" + xmrProofInfo.getServiceAddress()); @@ -94,7 +94,7 @@ public class XmrTransferProofRequester { log.info("Request() aborted, this object has been terminated. Service: {}", httpClient.getBaseUrl()); return; } - ListenableFuture future = executorService.submit(() -> { + ListenableFuture future = executorService.submit(() -> { Thread.currentThread().setName("XmrTransferProofRequest-" + xmrProofInfo.getKey()); String param = "/api/outputs?txhash=" + xmrProofInfo.getTxHash() + "&address=" + xmrProofInfo.getRecipientAddress() + @@ -102,13 +102,13 @@ public class XmrTransferProofRequester { "&txprove=1"; log.info("Requesting from {} with param {}", httpClient.getBaseUrl(), param); String json = httpClient.requestWithGET(param, "User-Agent", "bisq/" + Version.VERSION); - AutoConfirmResult autoConfirmResult = xmrProofInfo.checkApiResponse(json); + XmrAutoConfirmResult autoConfirmResult = xmrProofInfo.checkApiResponse(json); log.info("Response json {} resulted in autoConfirmResult {}", json, autoConfirmResult); return autoConfirmResult; }); Futures.addCallback(future, new FutureCallback<>() { - public void onSuccess(AutoConfirmResult result) { + public void onSuccess(XmrAutoConfirmResult result) { if (terminated) { log.info("API terminated from higher level: {}", httpClient.getBaseUrl()); return; @@ -127,7 +127,7 @@ public class XmrTransferProofRequester { String errorMessage = "Request to " + httpClient.getBaseUrl() + " failed"; faultHandler.handleFault(errorMessage, throwable); UserThread.execute(() -> resultHandler.accept( - new AutoConfirmResult(AutoConfirmResult.State.CONNECTION_FAIL, errorMessage))); + new XmrAutoConfirmResult(XmrAutoConfirmResult.State.CONNECTION_FAIL, errorMessage))); } }); } diff --git a/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofService.java b/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofService.java index 976fc70303..151463d81e 100644 --- a/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofService.java +++ b/core/src/main/java/bisq/core/trade/asset/xmr/XmrTransferProofService.java @@ -17,7 +17,7 @@ package bisq.core.trade.asset.xmr; -import bisq.core.trade.AutoConfirmResult; +import bisq.core.trade.XmrAutoConfirmResult; import bisq.network.Socks5ProxyProvider; @@ -48,7 +48,7 @@ public class XmrTransferProofService { } public void requestProof(XmrProofInfo xmrProofInfo, - Consumer resultHandler, + Consumer resultHandler, FaultHandler faultHandler) { String key = xmrProofInfo.getKey(); if (map.containsKey(key)) { diff --git a/core/src/main/java/bisq/core/trade/protocol/ProcessModel.java b/core/src/main/java/bisq/core/trade/protocol/ProcessModel.java index ed590b307c..51e0e08429 100644 --- a/core/src/main/java/bisq/core/trade/protocol/ProcessModel.java +++ b/core/src/main/java/bisq/core/trade/protocol/ProcessModel.java @@ -33,10 +33,10 @@ import bisq.core.proto.CoreProtoResolver; import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager; import bisq.core.support.dispute.mediation.mediator.MediatorManager; import bisq.core.support.dispute.refund.refundagent.RefundAgentManager; -import bisq.core.trade.AutoConfirmationManager; import bisq.core.trade.MakerTrade; import bisq.core.trade.Trade; import bisq.core.trade.TradeManager; +import bisq.core.trade.XmrAutoConfirmationManager; import bisq.core.trade.messages.TradeMessage; import bisq.core.trade.statistics.ReferralIdService; import bisq.core.trade.statistics.TradeStatisticsManager; @@ -90,7 +90,7 @@ public class ProcessModel implements Model, PersistablePayload { transient private User user; transient private FilterManager filterManager; transient private AccountAgeWitnessService accountAgeWitnessService; - transient private AutoConfirmationManager autoConfirmationManager; + transient private XmrAutoConfirmationManager xmrAutoConfirmationManager; transient private TradeStatisticsManager tradeStatisticsManager; transient private ArbitratorManager arbitratorManager; transient private MediatorManager mediatorManager; @@ -247,7 +247,7 @@ public class ProcessModel implements Model, PersistablePayload { User user, FilterManager filterManager, AccountAgeWitnessService accountAgeWitnessService, - AutoConfirmationManager autoConfirmationManager, + XmrAutoConfirmationManager xmrAutoConfirmationManager, TradeStatisticsManager tradeStatisticsManager, ArbitratorManager arbitratorManager, MediatorManager mediatorManager, @@ -266,7 +266,7 @@ public class ProcessModel implements Model, PersistablePayload { this.user = user; this.filterManager = filterManager; this.accountAgeWitnessService = accountAgeWitnessService; - this.autoConfirmationManager = autoConfirmationManager; + this.xmrAutoConfirmationManager = xmrAutoConfirmationManager; this.tradeStatisticsManager = tradeStatisticsManager; this.arbitratorManager = arbitratorManager; this.mediatorManager = mediatorManager; diff --git a/core/src/main/java/bisq/core/trade/protocol/tasks/seller/SellerProcessCounterCurrencyTransferStartedMessage.java b/core/src/main/java/bisq/core/trade/protocol/tasks/seller/SellerProcessCounterCurrencyTransferStartedMessage.java index ba8ba8b8f7..2faa9fc335 100644 --- a/core/src/main/java/bisq/core/trade/protocol/tasks/seller/SellerProcessCounterCurrencyTransferStartedMessage.java +++ b/core/src/main/java/bisq/core/trade/protocol/tasks/seller/SellerProcessCounterCurrencyTransferStartedMessage.java @@ -58,7 +58,7 @@ public class SellerProcessCounterCurrencyTransferStartedMessage extends TradeTas String counterCurrencyExtraData = message.getCounterCurrencyExtraData(); if (counterCurrencyExtraData != null && counterCurrencyExtraData.length() < 100) { trade.setCounterCurrencyExtraData(counterCurrencyExtraData); - processModel.getAutoConfirmationManager().processCounterCurrencyExtraData( + processModel.getXmrAutoConfirmationManager().processCounterCurrencyExtraData( trade, processModel.getTradeManager().getTradableList().stream()); } processModel.removeMailboxMessageAfterProcessing(trade); diff --git a/core/src/test/java/bisq/core/trade/asset/xmr/XmrProofInfoTest.java b/core/src/test/java/bisq/core/trade/asset/xmr/XmrProofInfoTest.java index ab8d2a1b84..427a5cb9ba 100644 --- a/core/src/test/java/bisq/core/trade/asset/xmr/XmrProofInfoTest.java +++ b/core/src/test/java/bisq/core/trade/asset/xmr/XmrProofInfoTest.java @@ -1,6 +1,6 @@ package bisq.core.trade.asset.xmr; -import bisq.core.trade.AutoConfirmResult; +import bisq.core.trade.XmrAutoConfirmResult; import java.time.Instant; @@ -48,13 +48,13 @@ public class XmrProofInfoTest { public void testJsonRoot() { // checking what happens when bad input is provided assertTrue(xmrProofInfo.checkApiResponse( - "invalid json data").getState() == AutoConfirmResult.State.API_INVALID); + "invalid json data").getState() == XmrAutoConfirmResult.State.API_INVALID); assertTrue(xmrProofInfo.checkApiResponse( - "").getState() == AutoConfirmResult.State.API_INVALID); + "").getState() == XmrAutoConfirmResult.State.API_INVALID); assertTrue(xmrProofInfo.checkApiResponse( - "[]").getState() == AutoConfirmResult.State.API_INVALID); + "[]").getState() == XmrAutoConfirmResult.State.API_INVALID); assertTrue(xmrProofInfo.checkApiResponse( - "{}").getState() == AutoConfirmResult.State.API_INVALID); + "{}").getState() == XmrAutoConfirmResult.State.API_INVALID); } @Test @@ -62,34 +62,34 @@ public class XmrProofInfoTest { // testing the top level fields: data and status assertTrue(xmrProofInfo.checkApiResponse( "{'data':{'title':''},'status':'fail'}" ) - .getState() == AutoConfirmResult.State.TX_NOT_FOUND); + .getState() == XmrAutoConfirmResult.State.TX_NOT_FOUND); assertTrue(xmrProofInfo.checkApiResponse( "{'data':{'title':''},'missingstatus':'success'}" ) - .getState() == AutoConfirmResult.State.API_INVALID); + .getState() == XmrAutoConfirmResult.State.API_INVALID); assertTrue(xmrProofInfo.checkApiResponse( "{'missingdata':{'title':''},'status':'success'}" ) - .getState() == AutoConfirmResult.State.API_INVALID); + .getState() == XmrAutoConfirmResult.State.API_INVALID); } @Test public void testJsonAddress() { assertTrue(xmrProofInfo.checkApiResponse( "{'data':{'missingaddress':'irrelevant'},'status':'success'}" ) - .getState() == AutoConfirmResult.State.API_INVALID); + .getState() == XmrAutoConfirmResult.State.API_INVALID); assertTrue(xmrProofInfo.checkApiResponse( "{'data':{'address':'e957dac7'},'status':'success'}" ) - .getState() == AutoConfirmResult.State.ADDRESS_INVALID); + .getState() == XmrAutoConfirmResult.State.ADDRESS_INVALID); } @Test public void testJsonTxHash() { String missing_tx_hash = "{'data':{'address':'" + recipientAddressHex + "'}, 'status':'success'}"; assertTrue(xmrProofInfo.checkApiResponse(missing_tx_hash).getState() - == AutoConfirmResult.State.API_INVALID); + == XmrAutoConfirmResult.State.API_INVALID); String invalid_tx_hash = "{'data':{'address':'" + recipientAddressHex + "', 'tx_hash':'488e48'}, 'status':'success'}"; assertTrue(xmrProofInfo.checkApiResponse(invalid_tx_hash).getState() - == AutoConfirmResult.State.TX_HASH_INVALID); + == XmrAutoConfirmResult.State.TX_HASH_INVALID); } @Test @@ -97,13 +97,13 @@ public class XmrProofInfoTest { String missing_tx_key = "{'data':{'address':'" + recipientAddressHex + "', " + "'tx_hash':'" + txHash + "'}, 'status':'success'}"; assertTrue(xmrProofInfo.checkApiResponse(missing_tx_key).getState() - == AutoConfirmResult.State.API_INVALID); + == XmrAutoConfirmResult.State.API_INVALID); String invalid_tx_key = "{'data':{'address':'" + recipientAddressHex + "', " + "'tx_hash':'" + txHash + "', " + "'viewkey':'cdce04'}, 'status':'success'}"; assertTrue(xmrProofInfo.checkApiResponse(invalid_tx_key).getState() - == AutoConfirmResult.State.TX_KEY_INVALID); + == XmrAutoConfirmResult.State.TX_KEY_INVALID); } @Test @@ -112,14 +112,14 @@ public class XmrProofInfoTest { "'tx_hash':'" + txHash + "'," + "'viewkey':'" + txKey + "'}, 'status':'success'}"; assertTrue(xmrProofInfo.checkApiResponse(missing_tx_timestamp).getState() - == AutoConfirmResult.State.API_INVALID); + == XmrAutoConfirmResult.State.API_INVALID); String invalid_tx_timestamp = "{'data':{'address':'" + recipientAddressHex + "', " + "'tx_hash':'" + txHash + "', " + "'viewkey':'" + txKey + "'," + "'tx_timestamp':'12345'}, 'status':'success'}"; assertTrue(xmrProofInfo.checkApiResponse(invalid_tx_timestamp).getState() - == AutoConfirmResult.State.TRADE_DATE_NOT_MATCHING); + == XmrAutoConfirmResult.State.TRADE_DATE_NOT_MATCHING); } @Test @@ -137,25 +137,25 @@ public class XmrProofInfoTest { "'tx_timestamp':'" + Long.toString(epochDate) + "'}" + "}"; assertTrue(xmrProofInfo.checkApiResponse(json).getState() - == AutoConfirmResult.State.PROOF_OK); + == XmrAutoConfirmResult.State.PROOF_OK); json = json.replaceFirst("777", "0"); assertTrue(xmrProofInfo.checkApiResponse(json).getState() - == AutoConfirmResult.State.TX_NOT_CONFIRMED); + == XmrAutoConfirmResult.State.TX_NOT_CONFIRMED); json = json.replaceFirst("100000000000", "100000000001"); assertTrue(xmrProofInfo.checkApiResponse(json).getState() - == AutoConfirmResult.State.AMOUNT_NOT_MATCHING); + == XmrAutoConfirmResult.State.AMOUNT_NOT_MATCHING); // Revert change of amount json = json.replaceFirst("100000000001", "100000000000"); json = json.replaceFirst("'match':true", "'match':false"); assertTrue(xmrProofInfo.checkApiResponse(json).getState() - == AutoConfirmResult.State.NO_MATCH_FOUND); + == XmrAutoConfirmResult.State.NO_MATCH_FOUND); } @Test public void testJsonFail() { String failedJson = "{\"data\":null,\"message\":\"Cant parse tx hash: a\",\"status\":\"error\"}"; assertTrue(xmrProofInfo.checkApiResponse(failedJson).getState() - == AutoConfirmResult.State.API_INVALID); + == XmrAutoConfirmResult.State.API_INVALID); } } diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java index d2babf8923..9e7d6a2cea 100644 --- a/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java +++ b/desktop/src/main/java/bisq/desktop/main/overlays/windows/TradeDetailsWindow.java @@ -39,7 +39,6 @@ import bisq.core.util.coin.CoinFormatter; import bisq.network.p2p.NodeAddress; import bisq.common.UserThread; -import bisq.common.util.Utilities; import org.bitcoinj.core.Utils; @@ -160,8 +159,9 @@ public class TradeDetailsWindow extends Overlay { addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradePrice"), FormattingUtils.formatPrice(trade.getTradePrice())); String methodText = Res.get(offer.getPaymentMethod().getId()); - if (trade.getAutoConfirmResult() != null && trade.getAutoConfirmResult().isSuccessState()) + if (trade.getAutoConfirmResult().isSuccessState()) { methodText += " (" + trade.getAutoConfirmResult().getTextStatus() + ")"; + } addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.paymentMethod"), methodText); // second group diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java index 0a945a7b73..83a5decfdd 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java @@ -117,7 +117,7 @@ public class BuyerStep4View extends TradeStepView { GridPane.setMargin(hBox2, new Insets(18, -10, -12, -10)); gridPane.getChildren().add(hBox2); GridPane.setRowSpan(hBox2, 5); - if (trade.getAutoConfirmResult() == null || !trade.getAutoConfirmResult().isSuccessState()) { + if (!trade.getAutoConfirmResult().isSuccessState()) { autoConfBadge.setVisible(false); } diff --git a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java index c459c7ff3a..eb805a76a3 100644 --- a/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java +++ b/desktop/src/main/java/bisq/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java @@ -40,9 +40,9 @@ import bisq.core.payment.payload.SepaAccountPayload; import bisq.core.payment.payload.SepaInstantAccountPayload; import bisq.core.payment.payload.USPostalMoneyOrderAccountPayload; import bisq.core.payment.payload.WesternUnionAccountPayload; +import bisq.core.trade.AutoConfirmResult; import bisq.core.trade.Contract; import bisq.core.trade.Trade; -import bisq.core.trade.AutoConfirmResult; import bisq.core.user.DontShowAgainLookup; import bisq.common.Timer; @@ -154,10 +154,7 @@ public class SellerStep3View extends TradeStepView { if (autoConfirmStatusField != null) { trade.getAutoConfirmResultProperty().addListener(autoConfirmResultListener); // display the initial value, or FEATURE_DISABLED if there is none - AutoConfirmResult autoConfirmResult = trade.getAutoConfirmResult(); - if (autoConfirmResult == null) - autoConfirmResult = new AutoConfirmResult(AutoConfirmResult.State.FEATURE_DISABLED); - autoConfirmStatusField.setText(autoConfirmResult.getTextStatus()); + autoConfirmStatusField.setText(trade.getAutoConfirmResult().getTextStatus()); } } diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index 7b96a55f85..10a27fd375 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -1397,7 +1397,7 @@ message Trade { } message AutoConfirmResult { - string stateName = 1; // name of AutoConfirmResult.State enum + string stateName = 1; } message BuyerAsMakerTrade {