mirror of
https://github.com/bisq-network/bisq.git
synced 2025-03-03 18:56:59 +01:00
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:
parent
2f1566bb06
commit
ed5078c0f1
15 changed files with 263 additions and 181 deletions
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
136
core/src/main/java/bisq/core/trade/XmrAutoConfirmResult.java
Normal file
136
core/src/main/java/bisq/core/trade/XmrAutoConfirmResult.java
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Reference in a new issue