Add abstract AutoConfirmResult class to get better support if we want

to add auto confirm for other currencies in the future. The generic part
is only used where we would have issues with backward compatibility like
in the protobuf objects. Most of the current classes are kept XMR
specific and could be generalized once we add other assets, but that
would be an internal refactoring without breaking any network or
storage data. I think it would be premature to go further here as we
don't know the details of other use cases. I added the methods used from
clients to AutoConfirmResult, not sure if the API is well defined by
that, but as said that could become subject of a future refactoring once
another auto confirm feature gets added. Goal of that refactoring was
to avoid that we need more fields for trade and the the UI would have to
deal with lots of switch cases based on currency.

Sorry that is a larger commit, would have been hard to break up...
This commit is contained in:
chimp1984 2020-08-30 15:45:47 -05:00
parent 2f1566bb06
commit ed5078c0f1
No known key found for this signature in database
GPG key ID: 9801B4EC591F90E3
15 changed files with 263 additions and 181 deletions

View file

@ -17,66 +17,31 @@
package bisq.core.trade; package bisq.core.trade;
import bisq.core.locale.Res; import lombok.EqualsAndHashCode;
import lombok.Getter;
import bisq.common.proto.ProtoUtil;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@Slf4j /**
@Value * Base class for AutoConfirm implementations
public class AutoConfirmResult { */
public enum State { @EqualsAndHashCode
UNDEFINED, @Getter
FEATURE_DISABLED, public abstract class AutoConfirmResult {
TX_NOT_FOUND,
TX_NOT_CONFIRMED, public static AutoConfirmResult fromCurrencyCode(String currencyCode) {
PROOF_OK, switch (currencyCode) {
CONNECTION_FAIL, case "XMR":
API_FAILURE, return new XmrAutoConfirmResult();
API_INVALID, default:
TX_KEY_REUSED, return null;
TX_HASH_INVALID, }
TX_KEY_INVALID,
ADDRESS_INVALID,
NO_MATCH_FOUND,
AMOUNT_NOT_MATCHING,
TRADE_LIMIT_EXCEEDED,
TRADE_DATE_NOT_MATCHING
} }
// Only state gets persisted private final String stateName;
private final State state;
private final transient int confirmCount; protected AutoConfirmResult(String stateName) {
private final transient int confirmsRequired; this.stateName = stateName;
///////////////////////////////////////////////////////////////////////////////////////////
// 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());
}
} }
@ -84,48 +49,25 @@ public class AutoConfirmResult {
// PROTOBUF // PROTOBUF
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public protobuf.AutoConfirmResult toProtoMessage() { // We use fromProto as kind of factory method to get the specific AutoConfirmResult
return protobuf.AutoConfirmResult.newBuilder().setStateName(state.name()).build(); @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) { public abstract protobuf.AutoConfirmResult toProtoMessage();
AutoConfirmResult.State state = ProtoUtil.enumFromProto(AutoConfirmResult.State.class, proto.getStateName());
return state != null ? new AutoConfirmResult(state) : new AutoConfirmResult(State.UNDEFINED);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// API // API
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public String getTextStatus() { abstract public boolean isSuccessState();
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() { abstract public String getTextStatus();
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());
}
} }

View file

@ -435,7 +435,10 @@ public abstract class Trade implements Tradable, Model {
@Setter @Setter
private String counterCurrencyExtraData; private String counterCurrencyExtraData;
@Getter public AutoConfirmResult getAutoConfirmResult() {
return autoConfirmResult != null ? autoConfirmResult : AutoConfirmResult.fromCurrencyCode(checkNotNull(offer).getCurrencyCode());
}
@Nullable @Nullable
private AutoConfirmResult autoConfirmResult; private AutoConfirmResult autoConfirmResult;
@ -595,7 +598,7 @@ public abstract class Trade implements Tradable, Model {
trade.setLockTime(proto.getLockTime()); trade.setLockTime(proto.getLockTime());
trade.setLastRefreshRequestDate(proto.getLastRefreshRequestDate()); trade.setLastRefreshRequestDate(proto.getLastRefreshRequestDate());
trade.setCounterCurrencyExtraData(ProtoUtil.stringOrNullFromProto(proto.getCounterCurrencyExtraData())); 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() trade.chatMessages.addAll(proto.getChatMessageList().stream()
.map(ChatMessage::fromPayloadProto) .map(ChatMessage::fromPayloadProto)
@ -625,7 +628,7 @@ public abstract class Trade implements Tradable, Model {
User user, User user,
FilterManager filterManager, FilterManager filterManager,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
AutoConfirmationManager autoConfirmationManager, XmrAutoConfirmationManager xmrAutoConfirmationManager,
TradeStatisticsManager tradeStatisticsManager, TradeStatisticsManager tradeStatisticsManager,
ArbitratorManager arbitratorManager, ArbitratorManager arbitratorManager,
MediatorManager mediatorManager, MediatorManager mediatorManager,
@ -645,7 +648,7 @@ public abstract class Trade implements Tradable, Model {
user, user,
filterManager, filterManager,
accountAgeWitnessService, accountAgeWitnessService,
autoConfirmationManager, xmrAutoConfirmationManager,
tradeStatisticsManager, tradeStatisticsManager,
arbitratorManager, arbitratorManager,
mediatorManager, mediatorManager,

View file

@ -126,7 +126,7 @@ public class TradeManager implements PersistedDataHost {
private final TradeStatisticsManager tradeStatisticsManager; private final TradeStatisticsManager tradeStatisticsManager;
private final ReferralIdService referralIdService; private final ReferralIdService referralIdService;
private final AccountAgeWitnessService accountAgeWitnessService; private final AccountAgeWitnessService accountAgeWitnessService;
private final AutoConfirmationManager autoConfirmationManager; private final XmrAutoConfirmationManager xmrAutoConfirmationManager;
private final ArbitratorManager arbitratorManager; private final ArbitratorManager arbitratorManager;
private final MediatorManager mediatorManager; private final MediatorManager mediatorManager;
private final RefundAgentManager refundAgentManager; private final RefundAgentManager refundAgentManager;
@ -168,7 +168,7 @@ public class TradeManager implements PersistedDataHost {
TradeStatisticsManager tradeStatisticsManager, TradeStatisticsManager tradeStatisticsManager,
ReferralIdService referralIdService, ReferralIdService referralIdService,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
AutoConfirmationManager autoConfirmationManager, XmrAutoConfirmationManager xmrAutoConfirmationManager,
ArbitratorManager arbitratorManager, ArbitratorManager arbitratorManager,
MediatorManager mediatorManager, MediatorManager mediatorManager,
RefundAgentManager refundAgentManager, RefundAgentManager refundAgentManager,
@ -191,7 +191,7 @@ public class TradeManager implements PersistedDataHost {
this.tradeStatisticsManager = tradeStatisticsManager; this.tradeStatisticsManager = tradeStatisticsManager;
this.referralIdService = referralIdService; this.referralIdService = referralIdService;
this.accountAgeWitnessService = accountAgeWitnessService; this.accountAgeWitnessService = accountAgeWitnessService;
this.autoConfirmationManager = autoConfirmationManager; this.xmrAutoConfirmationManager = xmrAutoConfirmationManager;
this.arbitratorManager = arbitratorManager; this.arbitratorManager = arbitratorManager;
this.mediatorManager = mediatorManager; this.mediatorManager = mediatorManager;
this.refundAgentManager = refundAgentManager; this.refundAgentManager = refundAgentManager;
@ -436,7 +436,7 @@ public class TradeManager implements PersistedDataHost {
user, user,
filterManager, filterManager,
accountAgeWitnessService, accountAgeWitnessService,
autoConfirmationManager, xmrAutoConfirmationManager,
tradeStatisticsManager, tradeStatisticsManager,
arbitratorManager, arbitratorManager,
mediatorManager, mediatorManager,

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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());
}
}

View file

@ -20,6 +20,7 @@ package bisq.core.trade;
import bisq.core.account.witness.AccountAgeWitnessService; import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.btc.setup.WalletsSetup; import bisq.core.btc.setup.WalletsSetup;
import bisq.core.filter.FilterManager; import bisq.core.filter.FilterManager;
import bisq.core.monetary.Volume;
import bisq.core.offer.Offer; import bisq.core.offer.Offer;
import bisq.core.payment.payload.AssetsAccountPayload; import bisq.core.payment.payload.AssetsAccountPayload;
import bisq.core.payment.payload.PaymentAccountPayload; import bisq.core.payment.payload.PaymentAccountPayload;
@ -49,7 +50,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
@Slf4j @Slf4j
@Singleton @Singleton
public class AutoConfirmationManager { public class XmrAutoConfirmationManager {
private final FilterManager filterManager; private final FilterManager filterManager;
private final Preferences preferences; private final Preferences preferences;
@ -66,7 +67,7 @@ public class AutoConfirmationManager {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Inject @Inject
AutoConfirmationManager(FilterManager filterManager, XmrAutoConfirmationManager(FilterManager filterManager,
Preferences preferences, Preferences preferences,
XmrTransferProofService xmrTransferProofService, XmrTransferProofService xmrTransferProofService,
ClosedTradableManager closedTradableManager, ClosedTradableManager closedTradableManager,
@ -153,7 +154,7 @@ public class AutoConfirmationManager {
if (alreadyUsed) { if (alreadyUsed) {
String message = "Peer used the XMR tx key already at another trade with trade ID " + String message = "Peer used the XMR tx key already at another trade with trade ID " +
t.getId() + ". This might be a scam attempt."; 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; return alreadyUsed;
}); });
@ -163,23 +164,24 @@ public class AutoConfirmationManager {
} }
if (!preferences.getAutoConfirmSettings().enabled || this.isAutoConfDisabledByFilter()) { 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; return;
} }
Coin tradeAmount = trade.getTradeAmount(); Coin tradeAmount = trade.getTradeAmount();
Coin tradeLimit = Coin.valueOf(preferences.getAutoConfirmSettings().tradeLimit); 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", log.warn("Trade amount {} is higher than settings limit {}, will not attempt auto-confirm",
tradeAmount.toFriendlyString(), tradeLimit.toFriendlyString()); 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; return;
} }
String address = sellersAssetsAccountPayload.getAddress(); String address = sellersAssetsAccountPayload.getAddress();
// XMR satoshis have 12 decimal places vs. bitcoin's 8 // 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; int confirmsRequired = preferences.getAutoConfirmSettings().requiredConfirmations;
trade.setAutoConfirmResult(new AutoConfirmResult(AutoConfirmResult.State.TX_NOT_FOUND)); trade.setAutoConfirmResult(new XmrAutoConfirmResult(XmrAutoConfirmResult.State.TX_NOT_FOUND));
List<String> serviceAddresses = preferences.getAutoConfirmSettings().serviceAddresses; List<String> serviceAddresses = preferences.getAutoConfirmSettings().serviceAddresses;
txProofResultsPending.put(trade.getId(), serviceAddresses.size()); // need result from each service address txProofResultsPending.put(trade.getId(), serviceAddresses.size()); // need result from each service address
for (String serviceAddress : serviceAddresses) { 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 success = true;
boolean failure = false; boolean failure = false;
@ -250,8 +252,10 @@ public class AutoConfirmationManager {
} }
accountAgeWitnessService.maybeSignWitness(trade); accountAgeWitnessService.maybeSignWitness(trade);
// transition the trade to step 4: // transition the trade to step 4:
((SellerTrade) trade).onFiatPaymentReceived(() -> { }, ((SellerTrade) trade).onFiatPaymentReceived(() -> {
errorMessage -> { }); },
errorMessage -> {
});
return success; return success;
} }

View file

@ -17,7 +17,7 @@
package bisq.core.trade.asset.xmr; package bisq.core.trade.asset.xmr;
import bisq.core.trade.AutoConfirmResult; import bisq.core.trade.XmrAutoConfirmResult;
import bisq.asset.CryptoNoteAddressValidator; import bisq.asset.CryptoNoteAddressValidator;
@ -68,57 +68,57 @@ public class XmrProofInfo {
return txHash + "|" + serviceAddress; return txHash + "|" + serviceAddress;
} }
public AutoConfirmResult checkApiResponse(String jsonTxt) { public XmrAutoConfirmResult checkApiResponse(String jsonTxt) {
try { try {
JsonObject json = new Gson().fromJson(jsonTxt, JsonObject.class); JsonObject json = new Gson().fromJson(jsonTxt, JsonObject.class);
if (json == null) { 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 // there should always be "data" and "status" at the top level
if (json.get("data") == null || !json.get("data").isJsonObject() || json.get("status") == null) { 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(); JsonObject jsonData = json.get("data").getAsJsonObject();
String jsonStatus = json.get("status").getAsString(); String jsonStatus = json.get("status").getAsString();
if (jsonStatus.matches("fail")) { if (jsonStatus.matches("fail")) {
// the API returns "fail" until the transaction has successfully reached the mempool. // the API returns "fail" until the transaction has successfully reached the mempool.
// we return TX_NOT_FOUND which will cause a retry later // 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")) { } 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 // validate that the address matches
JsonElement jsonAddress = jsonData.get("address"); JsonElement jsonAddress = jsonData.get("address");
if (jsonAddress == null) { if (jsonAddress == null) {
return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing address field"); return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing address field");
} else { } else {
String expectedAddressHex = CryptoNoteAddressValidator.convertToRawHex(this.recipientAddress); String expectedAddressHex = CryptoNoteAddressValidator.convertToRawHex(this.recipientAddress);
if (!jsonAddress.getAsString().equalsIgnoreCase(expectedAddressHex)) { if (!jsonAddress.getAsString().equalsIgnoreCase(expectedAddressHex)) {
log.warn("address {}, expected: {}", jsonAddress.getAsString(), 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 // validate that the txhash matches
JsonElement jsonTxHash = jsonData.get("tx_hash"); JsonElement jsonTxHash = jsonData.get("tx_hash");
if (jsonTxHash == null) { 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 { } else {
if (!jsonTxHash.getAsString().equalsIgnoreCase(txHash)) { if (!jsonTxHash.getAsString().equalsIgnoreCase(txHash)) {
log.warn("txHash {}, expected: {}", jsonTxHash.getAsString(), 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 // validate that the txkey matches
JsonElement jsonViewkey = jsonData.get("viewkey"); JsonElement jsonViewkey = jsonData.get("viewkey");
if (jsonViewkey == null) { if (jsonViewkey == null) {
return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, "Missing viewkey field"); return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, "Missing viewkey field");
} else { } else {
if (!jsonViewkey.getAsString().equalsIgnoreCase(this.txKey)) { if (!jsonViewkey.getAsString().equalsIgnoreCase(this.txKey)) {
log.warn("viewkey {}, expected: {}", jsonViewkey.getAsString(), 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) // (except that in dev mode we let this check pass anyway)
JsonElement jsonTimestamp = jsonData.get("tx_timestamp"); JsonElement jsonTimestamp = jsonData.get("tx_timestamp");
if (jsonTimestamp == null) { 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 { } else {
long tradeDateSeconds = tradeDate.getTime() / 1000; long tradeDateSeconds = tradeDate.getTime() / 1000;
long difference = tradeDateSeconds - jsonTimestamp.getAsLong(); long difference = tradeDateSeconds - jsonTimestamp.getAsLong();
@ -134,7 +134,7 @@ public class XmrProofInfo {
if (difference > TimeUnit.HOURS.toSeconds(2) && !DevEnv.isDevMode()) { if (difference > TimeUnit.HOURS.toSeconds(2) && !DevEnv.isDevMode()) {
log.warn("tx_timestamp {}, tradeDate: {}, difference {}", log.warn("tx_timestamp {}, tradeDate: {}, difference {}",
jsonTimestamp.getAsLong(), tradeDateSeconds, 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; int confirmations;
JsonElement jsonConfs = jsonData.get("tx_confirmations"); JsonElement jsonConfs = jsonData.get("tx_confirmations");
if (jsonConfs == null) { 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 { } else {
confirmations = jsonConfs.getAsInt(); confirmations = jsonConfs.getAsInt();
log.info("Confirmations: {}, xmr txHash: {}", confirmations, txHash); 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 (jsonAmount == amount || DevEnv.isDevMode()) { // any amount ok in dev mode
if (confirmations < confirmsRequired) if (confirmations < confirmsRequired)
// we return TX_NOT_CONFIRMED which will cause a retry later // 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 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 // None of the outputs had a match entry
if (!anyMatchFound) { 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 // 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) { } catch (JsonParseException | NullPointerException e) {
return new AutoConfirmResult(AutoConfirmResult.State.API_INVALID, e.toString()); return new XmrAutoConfirmResult(XmrAutoConfirmResult.State.API_INVALID, e.toString());
} }
} }
} }

View file

@ -17,7 +17,7 @@
package bisq.core.trade.asset.xmr; package bisq.core.trade.asset.xmr;
import bisq.core.trade.AutoConfirmResult; import bisq.core.trade.XmrAutoConfirmResult;
import bisq.network.Socks5ProxyProvider; import bisq.network.Socks5ProxyProvider;
@ -50,7 +50,7 @@ public class XmrTransferProofRequester {
"XmrTransferProofRequester", 3, 5, 10 * 60); "XmrTransferProofRequester", 3, 5, 10 * 60);
private final XmrTxProofHttpClient httpClient; private final XmrTxProofHttpClient httpClient;
private final XmrProofInfo xmrProofInfo; private final XmrProofInfo xmrProofInfo;
private final Consumer<AutoConfirmResult> resultHandler; private final Consumer<XmrAutoConfirmResult> resultHandler;
private final FaultHandler faultHandler; private final FaultHandler faultHandler;
private boolean terminated; private boolean terminated;
@ -63,7 +63,7 @@ public class XmrTransferProofRequester {
XmrTransferProofRequester(@Nullable Socks5ProxyProvider socks5ProxyProvider, XmrTransferProofRequester(@Nullable Socks5ProxyProvider socks5ProxyProvider,
XmrProofInfo xmrProofInfo, XmrProofInfo xmrProofInfo,
Consumer<AutoConfirmResult> resultHandler, Consumer<XmrAutoConfirmResult> resultHandler,
FaultHandler faultHandler) { FaultHandler faultHandler) {
this.httpClient = new XmrTxProofHttpClient(socks5ProxyProvider); this.httpClient = new XmrTxProofHttpClient(socks5ProxyProvider);
this.httpClient.setBaseUrl("http://" + xmrProofInfo.getServiceAddress()); 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()); log.info("Request() aborted, this object has been terminated. Service: {}", httpClient.getBaseUrl());
return; return;
} }
ListenableFuture<AutoConfirmResult> future = executorService.submit(() -> { ListenableFuture<XmrAutoConfirmResult> future = executorService.submit(() -> {
Thread.currentThread().setName("XmrTransferProofRequest-" + xmrProofInfo.getKey()); Thread.currentThread().setName("XmrTransferProofRequest-" + xmrProofInfo.getKey());
String param = "/api/outputs?txhash=" + xmrProofInfo.getTxHash() + String param = "/api/outputs?txhash=" + xmrProofInfo.getTxHash() +
"&address=" + xmrProofInfo.getRecipientAddress() + "&address=" + xmrProofInfo.getRecipientAddress() +
@ -102,13 +102,13 @@ public class XmrTransferProofRequester {
"&txprove=1"; "&txprove=1";
log.info("Requesting from {} with param {}", httpClient.getBaseUrl(), param); log.info("Requesting from {} with param {}", httpClient.getBaseUrl(), param);
String json = httpClient.requestWithGET(param, "User-Agent", "bisq/" + Version.VERSION); 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); log.info("Response json {} resulted in autoConfirmResult {}", json, autoConfirmResult);
return autoConfirmResult; return autoConfirmResult;
}); });
Futures.addCallback(future, new FutureCallback<>() { Futures.addCallback(future, new FutureCallback<>() {
public void onSuccess(AutoConfirmResult result) { public void onSuccess(XmrAutoConfirmResult result) {
if (terminated) { if (terminated) {
log.info("API terminated from higher level: {}", httpClient.getBaseUrl()); log.info("API terminated from higher level: {}", httpClient.getBaseUrl());
return; return;
@ -127,7 +127,7 @@ public class XmrTransferProofRequester {
String errorMessage = "Request to " + httpClient.getBaseUrl() + " failed"; String errorMessage = "Request to " + httpClient.getBaseUrl() + " failed";
faultHandler.handleFault(errorMessage, throwable); faultHandler.handleFault(errorMessage, throwable);
UserThread.execute(() -> resultHandler.accept( UserThread.execute(() -> resultHandler.accept(
new AutoConfirmResult(AutoConfirmResult.State.CONNECTION_FAIL, errorMessage))); new XmrAutoConfirmResult(XmrAutoConfirmResult.State.CONNECTION_FAIL, errorMessage)));
} }
}); });
} }

View file

@ -17,7 +17,7 @@
package bisq.core.trade.asset.xmr; package bisq.core.trade.asset.xmr;
import bisq.core.trade.AutoConfirmResult; import bisq.core.trade.XmrAutoConfirmResult;
import bisq.network.Socks5ProxyProvider; import bisq.network.Socks5ProxyProvider;
@ -48,7 +48,7 @@ public class XmrTransferProofService {
} }
public void requestProof(XmrProofInfo xmrProofInfo, public void requestProof(XmrProofInfo xmrProofInfo,
Consumer<AutoConfirmResult> resultHandler, Consumer<XmrAutoConfirmResult> resultHandler,
FaultHandler faultHandler) { FaultHandler faultHandler) {
String key = xmrProofInfo.getKey(); String key = xmrProofInfo.getKey();
if (map.containsKey(key)) { if (map.containsKey(key)) {

View file

@ -33,10 +33,10 @@ import bisq.core.proto.CoreProtoResolver;
import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager; import bisq.core.support.dispute.arbitration.arbitrator.ArbitratorManager;
import bisq.core.support.dispute.mediation.mediator.MediatorManager; import bisq.core.support.dispute.mediation.mediator.MediatorManager;
import bisq.core.support.dispute.refund.refundagent.RefundAgentManager; import bisq.core.support.dispute.refund.refundagent.RefundAgentManager;
import bisq.core.trade.AutoConfirmationManager;
import bisq.core.trade.MakerTrade; import bisq.core.trade.MakerTrade;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.TradeManager; import bisq.core.trade.TradeManager;
import bisq.core.trade.XmrAutoConfirmationManager;
import bisq.core.trade.messages.TradeMessage; import bisq.core.trade.messages.TradeMessage;
import bisq.core.trade.statistics.ReferralIdService; import bisq.core.trade.statistics.ReferralIdService;
import bisq.core.trade.statistics.TradeStatisticsManager; import bisq.core.trade.statistics.TradeStatisticsManager;
@ -90,7 +90,7 @@ public class ProcessModel implements Model, PersistablePayload {
transient private User user; transient private User user;
transient private FilterManager filterManager; transient private FilterManager filterManager;
transient private AccountAgeWitnessService accountAgeWitnessService; transient private AccountAgeWitnessService accountAgeWitnessService;
transient private AutoConfirmationManager autoConfirmationManager; transient private XmrAutoConfirmationManager xmrAutoConfirmationManager;
transient private TradeStatisticsManager tradeStatisticsManager; transient private TradeStatisticsManager tradeStatisticsManager;
transient private ArbitratorManager arbitratorManager; transient private ArbitratorManager arbitratorManager;
transient private MediatorManager mediatorManager; transient private MediatorManager mediatorManager;
@ -247,7 +247,7 @@ public class ProcessModel implements Model, PersistablePayload {
User user, User user,
FilterManager filterManager, FilterManager filterManager,
AccountAgeWitnessService accountAgeWitnessService, AccountAgeWitnessService accountAgeWitnessService,
AutoConfirmationManager autoConfirmationManager, XmrAutoConfirmationManager xmrAutoConfirmationManager,
TradeStatisticsManager tradeStatisticsManager, TradeStatisticsManager tradeStatisticsManager,
ArbitratorManager arbitratorManager, ArbitratorManager arbitratorManager,
MediatorManager mediatorManager, MediatorManager mediatorManager,
@ -266,7 +266,7 @@ public class ProcessModel implements Model, PersistablePayload {
this.user = user; this.user = user;
this.filterManager = filterManager; this.filterManager = filterManager;
this.accountAgeWitnessService = accountAgeWitnessService; this.accountAgeWitnessService = accountAgeWitnessService;
this.autoConfirmationManager = autoConfirmationManager; this.xmrAutoConfirmationManager = xmrAutoConfirmationManager;
this.tradeStatisticsManager = tradeStatisticsManager; this.tradeStatisticsManager = tradeStatisticsManager;
this.arbitratorManager = arbitratorManager; this.arbitratorManager = arbitratorManager;
this.mediatorManager = mediatorManager; this.mediatorManager = mediatorManager;

View file

@ -58,7 +58,7 @@ public class SellerProcessCounterCurrencyTransferStartedMessage extends TradeTas
String counterCurrencyExtraData = message.getCounterCurrencyExtraData(); String counterCurrencyExtraData = message.getCounterCurrencyExtraData();
if (counterCurrencyExtraData != null && counterCurrencyExtraData.length() < 100) { if (counterCurrencyExtraData != null && counterCurrencyExtraData.length() < 100) {
trade.setCounterCurrencyExtraData(counterCurrencyExtraData); trade.setCounterCurrencyExtraData(counterCurrencyExtraData);
processModel.getAutoConfirmationManager().processCounterCurrencyExtraData( processModel.getXmrAutoConfirmationManager().processCounterCurrencyExtraData(
trade, processModel.getTradeManager().getTradableList().stream()); trade, processModel.getTradeManager().getTradableList().stream());
} }
processModel.removeMailboxMessageAfterProcessing(trade); processModel.removeMailboxMessageAfterProcessing(trade);

View file

@ -1,6 +1,6 @@
package bisq.core.trade.asset.xmr; package bisq.core.trade.asset.xmr;
import bisq.core.trade.AutoConfirmResult; import bisq.core.trade.XmrAutoConfirmResult;
import java.time.Instant; import java.time.Instant;
@ -48,13 +48,13 @@ public class XmrProofInfoTest {
public void testJsonRoot() { public void testJsonRoot() {
// checking what happens when bad input is provided // checking what happens when bad input is provided
assertTrue(xmrProofInfo.checkApiResponse( assertTrue(xmrProofInfo.checkApiResponse(
"invalid json data").getState() == AutoConfirmResult.State.API_INVALID); "invalid json data").getState() == XmrAutoConfirmResult.State.API_INVALID);
assertTrue(xmrProofInfo.checkApiResponse( assertTrue(xmrProofInfo.checkApiResponse(
"").getState() == AutoConfirmResult.State.API_INVALID); "").getState() == XmrAutoConfirmResult.State.API_INVALID);
assertTrue(xmrProofInfo.checkApiResponse( assertTrue(xmrProofInfo.checkApiResponse(
"[]").getState() == AutoConfirmResult.State.API_INVALID); "[]").getState() == XmrAutoConfirmResult.State.API_INVALID);
assertTrue(xmrProofInfo.checkApiResponse( assertTrue(xmrProofInfo.checkApiResponse(
"{}").getState() == AutoConfirmResult.State.API_INVALID); "{}").getState() == XmrAutoConfirmResult.State.API_INVALID);
} }
@Test @Test
@ -62,34 +62,34 @@ public class XmrProofInfoTest {
// testing the top level fields: data and status // testing the top level fields: data and status
assertTrue(xmrProofInfo.checkApiResponse( assertTrue(xmrProofInfo.checkApiResponse(
"{'data':{'title':''},'status':'fail'}" ) "{'data':{'title':''},'status':'fail'}" )
.getState() == AutoConfirmResult.State.TX_NOT_FOUND); .getState() == XmrAutoConfirmResult.State.TX_NOT_FOUND);
assertTrue(xmrProofInfo.checkApiResponse( assertTrue(xmrProofInfo.checkApiResponse(
"{'data':{'title':''},'missingstatus':'success'}" ) "{'data':{'title':''},'missingstatus':'success'}" )
.getState() == AutoConfirmResult.State.API_INVALID); .getState() == XmrAutoConfirmResult.State.API_INVALID);
assertTrue(xmrProofInfo.checkApiResponse( assertTrue(xmrProofInfo.checkApiResponse(
"{'missingdata':{'title':''},'status':'success'}" ) "{'missingdata':{'title':''},'status':'success'}" )
.getState() == AutoConfirmResult.State.API_INVALID); .getState() == XmrAutoConfirmResult.State.API_INVALID);
} }
@Test @Test
public void testJsonAddress() { public void testJsonAddress() {
assertTrue(xmrProofInfo.checkApiResponse( assertTrue(xmrProofInfo.checkApiResponse(
"{'data':{'missingaddress':'irrelevant'},'status':'success'}" ) "{'data':{'missingaddress':'irrelevant'},'status':'success'}" )
.getState() == AutoConfirmResult.State.API_INVALID); .getState() == XmrAutoConfirmResult.State.API_INVALID);
assertTrue(xmrProofInfo.checkApiResponse( assertTrue(xmrProofInfo.checkApiResponse(
"{'data':{'address':'e957dac7'},'status':'success'}" ) "{'data':{'address':'e957dac7'},'status':'success'}" )
.getState() == AutoConfirmResult.State.ADDRESS_INVALID); .getState() == XmrAutoConfirmResult.State.ADDRESS_INVALID);
} }
@Test @Test
public void testJsonTxHash() { public void testJsonTxHash() {
String missing_tx_hash = "{'data':{'address':'" + recipientAddressHex + "'}, 'status':'success'}"; String missing_tx_hash = "{'data':{'address':'" + recipientAddressHex + "'}, 'status':'success'}";
assertTrue(xmrProofInfo.checkApiResponse(missing_tx_hash).getState() 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'}"; String invalid_tx_hash = "{'data':{'address':'" + recipientAddressHex + "', 'tx_hash':'488e48'}, 'status':'success'}";
assertTrue(xmrProofInfo.checkApiResponse(invalid_tx_hash).getState() assertTrue(xmrProofInfo.checkApiResponse(invalid_tx_hash).getState()
== AutoConfirmResult.State.TX_HASH_INVALID); == XmrAutoConfirmResult.State.TX_HASH_INVALID);
} }
@Test @Test
@ -97,13 +97,13 @@ public class XmrProofInfoTest {
String missing_tx_key = "{'data':{'address':'" + recipientAddressHex + "', " + String missing_tx_key = "{'data':{'address':'" + recipientAddressHex + "', " +
"'tx_hash':'" + txHash + "'}, 'status':'success'}"; "'tx_hash':'" + txHash + "'}, 'status':'success'}";
assertTrue(xmrProofInfo.checkApiResponse(missing_tx_key).getState() assertTrue(xmrProofInfo.checkApiResponse(missing_tx_key).getState()
== AutoConfirmResult.State.API_INVALID); == XmrAutoConfirmResult.State.API_INVALID);
String invalid_tx_key = "{'data':{'address':'" + recipientAddressHex + "', " + String invalid_tx_key = "{'data':{'address':'" + recipientAddressHex + "', " +
"'tx_hash':'" + txHash + "', " + "'tx_hash':'" + txHash + "', " +
"'viewkey':'cdce04'}, 'status':'success'}"; "'viewkey':'cdce04'}, 'status':'success'}";
assertTrue(xmrProofInfo.checkApiResponse(invalid_tx_key).getState() assertTrue(xmrProofInfo.checkApiResponse(invalid_tx_key).getState()
== AutoConfirmResult.State.TX_KEY_INVALID); == XmrAutoConfirmResult.State.TX_KEY_INVALID);
} }
@Test @Test
@ -112,14 +112,14 @@ public class XmrProofInfoTest {
"'tx_hash':'" + txHash + "'," + "'tx_hash':'" + txHash + "'," +
"'viewkey':'" + txKey + "'}, 'status':'success'}"; "'viewkey':'" + txKey + "'}, 'status':'success'}";
assertTrue(xmrProofInfo.checkApiResponse(missing_tx_timestamp).getState() assertTrue(xmrProofInfo.checkApiResponse(missing_tx_timestamp).getState()
== AutoConfirmResult.State.API_INVALID); == XmrAutoConfirmResult.State.API_INVALID);
String invalid_tx_timestamp = "{'data':{'address':'" + recipientAddressHex + "', " + String invalid_tx_timestamp = "{'data':{'address':'" + recipientAddressHex + "', " +
"'tx_hash':'" + txHash + "', " + "'tx_hash':'" + txHash + "', " +
"'viewkey':'" + txKey + "'," + "'viewkey':'" + txKey + "'," +
"'tx_timestamp':'12345'}, 'status':'success'}"; "'tx_timestamp':'12345'}, 'status':'success'}";
assertTrue(xmrProofInfo.checkApiResponse(invalid_tx_timestamp).getState() assertTrue(xmrProofInfo.checkApiResponse(invalid_tx_timestamp).getState()
== AutoConfirmResult.State.TRADE_DATE_NOT_MATCHING); == XmrAutoConfirmResult.State.TRADE_DATE_NOT_MATCHING);
} }
@Test @Test
@ -137,25 +137,25 @@ public class XmrProofInfoTest {
"'tx_timestamp':'" + Long.toString(epochDate) + "'}" + "'tx_timestamp':'" + Long.toString(epochDate) + "'}" +
"}"; "}";
assertTrue(xmrProofInfo.checkApiResponse(json).getState() assertTrue(xmrProofInfo.checkApiResponse(json).getState()
== AutoConfirmResult.State.PROOF_OK); == XmrAutoConfirmResult.State.PROOF_OK);
json = json.replaceFirst("777", "0"); json = json.replaceFirst("777", "0");
assertTrue(xmrProofInfo.checkApiResponse(json).getState() assertTrue(xmrProofInfo.checkApiResponse(json).getState()
== AutoConfirmResult.State.TX_NOT_CONFIRMED); == XmrAutoConfirmResult.State.TX_NOT_CONFIRMED);
json = json.replaceFirst("100000000000", "100000000001"); json = json.replaceFirst("100000000000", "100000000001");
assertTrue(xmrProofInfo.checkApiResponse(json).getState() assertTrue(xmrProofInfo.checkApiResponse(json).getState()
== AutoConfirmResult.State.AMOUNT_NOT_MATCHING); == XmrAutoConfirmResult.State.AMOUNT_NOT_MATCHING);
// Revert change of amount // Revert change of amount
json = json.replaceFirst("100000000001", "100000000000"); json = json.replaceFirst("100000000001", "100000000000");
json = json.replaceFirst("'match':true", "'match':false"); json = json.replaceFirst("'match':true", "'match':false");
assertTrue(xmrProofInfo.checkApiResponse(json).getState() assertTrue(xmrProofInfo.checkApiResponse(json).getState()
== AutoConfirmResult.State.NO_MATCH_FOUND); == XmrAutoConfirmResult.State.NO_MATCH_FOUND);
} }
@Test @Test
public void testJsonFail() { public void testJsonFail() {
String failedJson = "{\"data\":null,\"message\":\"Cant parse tx hash: a\",\"status\":\"error\"}"; String failedJson = "{\"data\":null,\"message\":\"Cant parse tx hash: a\",\"status\":\"error\"}";
assertTrue(xmrProofInfo.checkApiResponse(failedJson).getState() assertTrue(xmrProofInfo.checkApiResponse(failedJson).getState()
== AutoConfirmResult.State.API_INVALID); == XmrAutoConfirmResult.State.API_INVALID);
} }
} }

View file

@ -39,7 +39,6 @@ import bisq.core.util.coin.CoinFormatter;
import bisq.network.p2p.NodeAddress; import bisq.network.p2p.NodeAddress;
import bisq.common.UserThread; import bisq.common.UserThread;
import bisq.common.util.Utilities;
import org.bitcoinj.core.Utils; import org.bitcoinj.core.Utils;
@ -160,8 +159,9 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> {
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradePrice"), addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradePrice"),
FormattingUtils.formatPrice(trade.getTradePrice())); FormattingUtils.formatPrice(trade.getTradePrice()));
String methodText = Res.get(offer.getPaymentMethod().getId()); String methodText = Res.get(offer.getPaymentMethod().getId());
if (trade.getAutoConfirmResult() != null && trade.getAutoConfirmResult().isSuccessState()) if (trade.getAutoConfirmResult().isSuccessState()) {
methodText += " (" + trade.getAutoConfirmResult().getTextStatus() + ")"; methodText += " (" + trade.getAutoConfirmResult().getTextStatus() + ")";
}
addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.paymentMethod"), methodText); addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.paymentMethod"), methodText);
// second group // second group

View file

@ -117,7 +117,7 @@ public class BuyerStep4View extends TradeStepView {
GridPane.setMargin(hBox2, new Insets(18, -10, -12, -10)); GridPane.setMargin(hBox2, new Insets(18, -10, -12, -10));
gridPane.getChildren().add(hBox2); gridPane.getChildren().add(hBox2);
GridPane.setRowSpan(hBox2, 5); GridPane.setRowSpan(hBox2, 5);
if (trade.getAutoConfirmResult() == null || !trade.getAutoConfirmResult().isSuccessState()) { if (!trade.getAutoConfirmResult().isSuccessState()) {
autoConfBadge.setVisible(false); autoConfBadge.setVisible(false);
} }

View file

@ -40,9 +40,9 @@ import bisq.core.payment.payload.SepaAccountPayload;
import bisq.core.payment.payload.SepaInstantAccountPayload; import bisq.core.payment.payload.SepaInstantAccountPayload;
import bisq.core.payment.payload.USPostalMoneyOrderAccountPayload; import bisq.core.payment.payload.USPostalMoneyOrderAccountPayload;
import bisq.core.payment.payload.WesternUnionAccountPayload; import bisq.core.payment.payload.WesternUnionAccountPayload;
import bisq.core.trade.AutoConfirmResult;
import bisq.core.trade.Contract; import bisq.core.trade.Contract;
import bisq.core.trade.Trade; import bisq.core.trade.Trade;
import bisq.core.trade.AutoConfirmResult;
import bisq.core.user.DontShowAgainLookup; import bisq.core.user.DontShowAgainLookup;
import bisq.common.Timer; import bisq.common.Timer;
@ -154,10 +154,7 @@ public class SellerStep3View extends TradeStepView {
if (autoConfirmStatusField != null) { if (autoConfirmStatusField != null) {
trade.getAutoConfirmResultProperty().addListener(autoConfirmResultListener); trade.getAutoConfirmResultProperty().addListener(autoConfirmResultListener);
// display the initial value, or FEATURE_DISABLED if there is none // display the initial value, or FEATURE_DISABLED if there is none
AutoConfirmResult autoConfirmResult = trade.getAutoConfirmResult(); autoConfirmStatusField.setText(trade.getAutoConfirmResult().getTextStatus());
if (autoConfirmResult == null)
autoConfirmResult = new AutoConfirmResult(AutoConfirmResult.State.FEATURE_DISABLED);
autoConfirmStatusField.setText(autoConfirmResult.getTextStatus());
} }
} }

View file

@ -1397,7 +1397,7 @@ message Trade {
} }
message AutoConfirmResult { message AutoConfirmResult {
string stateName = 1; // name of AutoConfirmResult.State enum string stateName = 1;
} }
message BuyerAsMakerTrade { message BuyerAsMakerTrade {