Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid NPE due to null fee while wrapping tx in TxInfo #5302

Merged
merged 10 commits into from Mar 19, 2021
39 changes: 10 additions & 29 deletions cli/src/main/java/bisq/cli/GrpcClient.java
Expand Up @@ -53,6 +53,7 @@
import bisq.proto.grpc.SetTxFeeRatePreferenceRequest;
import bisq.proto.grpc.SetWalletPasswordRequest;
import bisq.proto.grpc.StopRequest;
import bisq.proto.grpc.TakeOfferReply;
import bisq.proto.grpc.TakeOfferRequest;
import bisq.proto.grpc.TradeInfo;
import bisq.proto.grpc.TxFeeRateInfo;
Expand Down Expand Up @@ -309,41 +310,21 @@ private List<OfferInfo> sortOffersByDate(List<OfferInfo> offerInfoList) {
.collect(Collectors.toList());
}

public TradeInfo takeOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) {
public TakeOfferReply getTakeOfferReply(String offerId, String paymentAccountId, String takerFeeCurrencyCode) {
var request = TakeOfferRequest.newBuilder()
.setOfferId(offerId)
.setPaymentAccountId(paymentAccountId)
.setTakerFeeCurrencyCode(takerFeeCurrencyCode)
.build();
var reply = grpcStubs.tradesService.takeOffer(request);
if (reply.hasTrade()) {
return grpcStubs.tradesService.takeOffer(request);
}

public TradeInfo takeOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) {
var reply = getTakeOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode);
if (reply.hasTrade())
return reply.getTrade();
} else {
// If there is no trade, there should be a reason in the AvailabilityResult.
// Convert the enum to a user error message before throwing the exception.
switch (reply.getAvailabilityResult()) {
case MARKET_PRICE_NOT_AVAILABLE:
throw new IllegalStateException("could not take offer because market price for calculating trade price is unavailable");
case PRICE_OUT_OF_TOLERANCE:
throw new IllegalStateException("could not take offer because taker's price is outside tolerance");
case PRICE_CHECK_FAILED:
throw new IllegalStateException("could not take offer because trade price check failed");
case NO_ARBITRATORS:
throw new IllegalStateException("could not take offer because no arbitrators are available");
case NO_MEDIATORS:
throw new IllegalStateException("could not take offer because no mediators are available");
case NO_REFUND_AGENTS:
throw new IllegalStateException("could not take offer because no refund agents are available");
case USER_IGNORED:
throw new IllegalStateException("could not take offer from ignored user");
case MAKER_DENIED_API_USER:
throw new IllegalStateException("could not take offer because maker is api user");
case UNCONF_TX_LIMIT_HIT:
throw new IllegalStateException("could not take offer because you have too many unconfirmed transactions at this moment");
default:
throw new IllegalStateException("programmer error: could not take offer for unknown reason");
}
}
else
throw new IllegalStateException(reply.getAvailabilityResultDescription());
}

public TradeInfo getTrade(String tradeId) {
Expand Down
40 changes: 27 additions & 13 deletions core/src/main/java/bisq/core/offer/AvailabilityResult.java
Expand Up @@ -18,17 +18,31 @@
package bisq.core.offer;

public enum AvailabilityResult {
UNKNOWN_FAILURE,
AVAILABLE,
OFFER_TAKEN,
PRICE_OUT_OF_TOLERANCE,
MARKET_PRICE_NOT_AVAILABLE,
@SuppressWarnings("unused") NO_ARBITRATORS,
NO_MEDIATORS,
USER_IGNORED,
@SuppressWarnings("unused") MISSING_MANDATORY_CAPABILITY,
@SuppressWarnings("unused") NO_REFUND_AGENTS,
UNCONF_TX_LIMIT_HIT,
MAKER_DENIED_API_USER,
PRICE_CHECK_FAILED
UNKNOWN_FAILURE("cannot take offer for unknown reason"),
AVAILABLE("offer available"),
OFFER_TAKEN("offer taken"),
PRICE_OUT_OF_TOLERANCE("cannot take offer because taker's price is outside tolerance"),
MARKET_PRICE_NOT_AVAILABLE("cannot take offer because market price for calculating trade price is unavailable"),
@SuppressWarnings("unused") NO_ARBITRATORS("cannot take offer because no arbitrators are available"),
NO_MEDIATORS("cannot take offer because no mediators are available"),
USER_IGNORED("cannot take offer because user is ignored"),
@SuppressWarnings("unused") MISSING_MANDATORY_CAPABILITY("description not available"),
@SuppressWarnings("unused") NO_REFUND_AGENTS("cannot take offer because no refund agents are available"),
UNCONF_TX_LIMIT_HIT("cannot take offer because you have too many unconfirmed transactions at this moment"),
MAKER_DENIED_API_USER("cannot take offer because maker is api user"),
PRICE_CHECK_FAILED("cannot take offer because trade price check failed");

private final String description;

AvailabilityResult(String description) {
this.description = description;
}

public String description() {
return description;
}

public static AvailabilityResult fromProto(protobuf.AvailabilityResult proto) {
return AvailabilityResult.valueOf(proto.name());
}
}
Expand Up @@ -92,9 +92,10 @@ private void handleTakeOfferError(String errorMessage) {
// The client should look at the grpc reply object's AvailabilityResult
// field if reply.hasTrade = false, and use it give the user a human readable msg.
try {
AvailabilityResult availabilityResult = getAvailabilityResult(errorMessage);
AvailabilityResult availabilityResultProto = getAvailabilityResult(errorMessage);
var reply = TakeOfferReply.newBuilder()
.setAvailabilityResult(availabilityResult)
.setAvailabilityResult(availabilityResultProto)
.setAvailabilityResultDescription(getAvailabilityResultDescription(availabilityResultProto))
.build();
@SuppressWarnings("unchecked")
var takeOfferResponseObserver = (StreamObserver<TakeOfferReply>) responseObserver;
Expand All @@ -116,6 +117,10 @@ private AvailabilityResult getAvailabilityResult(String errorMessage) {
format("Could not find an AvailabilityResult in error message:%n%s", errorMessage)));
}

private String getAvailabilityResultDescription(AvailabilityResult proto) {
return bisq.core.offer.AvailabilityResult.fromProto(proto).description();
}

private boolean isTakeOfferError() {
return fullMethodName.equals(getTakeOfferMethod().getFullMethodName());
}
Expand Down
1 change: 1 addition & 0 deletions proto/src/main/proto/grpc.proto
Expand Up @@ -278,6 +278,7 @@ message TakeOfferRequest {
message TakeOfferReply {
TradeInfo trade = 1;
AvailabilityResult availabilityResult = 2;
string availabilityResultDescription = 3;
}

message ConfirmPaymentStartedRequest {
Expand Down