From 5924312e6487e36d771f75e5f16349df63444908 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Thu, 11 Nov 2021 12:51:00 -0300 Subject: [PATCH 01/17] Adjust bsq-swap-offer related gRPC services & msgs - Adjust GetBsqSwapOffer(s) rpc services to remove currency param. - Adjust OfferInfo and remove BsqSwapOfferInfo. - Add GetOfferCategory service so CLI can determine what kind of takeoffer service is to be used. - Add comment about adding sub-message BsqSwapTradeInfo field to TradeInfo. --- proto/src/main/proto/grpc.proto | 101 +++++++++++++++++--------------- 1 file changed, 53 insertions(+), 48 deletions(-) diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index ec8235b4042..e050f951051 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -62,6 +62,8 @@ message GetMethodHelpReply { /////////////////////////////////////////////////////////////////////////////////////////// service Offers { + rpc GetOfferCategory (GetOfferCategoryRequest) returns (GetOfferCategoryReply) { + } rpc GetBsqSwapOffer (GetOfferRequest) returns (GetBsqSwapOfferReply) { } rpc GetOffer (GetOfferRequest) returns (GetOfferReply) { @@ -70,11 +72,11 @@ service Offers { } rpc GetMyOffer (GetMyOfferRequest) returns (GetMyOfferReply) { } - rpc GetBsqSwapOffers (GetOffersRequest) returns (GetBsqSwapOffersReply) { + rpc GetBsqSwapOffers (GetBsqSwapOffersRequest) returns (GetBsqSwapOffersReply) { } rpc GetOffers (GetOffersRequest) returns (GetOffersReply) { } - rpc GetMyBsqSwapOffers (GetMyOffersRequest) returns (GetMyBsqSwapOffersReply) { + rpc GetMyBsqSwapOffers (GetBsqSwapOffersRequest) returns (GetMyBsqSwapOffersReply) { } rpc GetMyOffers (GetMyOffersRequest) returns (GetMyOffersReply) { } @@ -88,8 +90,22 @@ service Offers { } } +message GetOfferCategoryRequest { + string id = 1; +} + +message GetOfferCategoryReply { + enum OfferCategory { + UNKNOWN = 0; + FIAT = 1; + ALTCOIN = 2; + BSQ_SWAP = 3; + } + OfferCategory offerCategory = 1; +} + message GetBsqSwapOfferReply { - BsqSwapOfferInfo bsqSwapOffer = 1; + OfferInfo bsqSwapOffer = 1; } message GetOfferRequest { @@ -101,7 +117,7 @@ message GetOfferReply { } message GetMyBsqSwapOfferReply { - BsqSwapOfferInfo bsqSwapOffer = 1; + OfferInfo bsqSwapOffer = 1; } message GetMyOfferRequest { @@ -121,8 +137,12 @@ message GetOffersReply { repeated OfferInfo offers = 1; } +message GetBsqSwapOffersRequest { + string direction = 1; +} + message GetBsqSwapOffersReply { - repeated BsqSwapOfferInfo bsqSwapOffers = 1; + repeated OfferInfo bsqSwapOffers = 1; } message GetMyOffersRequest { @@ -135,7 +155,7 @@ message GetMyOffersReply { } message GetMyBsqSwapOffersReply { - repeated BsqSwapOfferInfo bsqSwapOffers = 1; + repeated OfferInfo bsqSwapOffers = 1; } message CreateBsqSwapOfferRequest { @@ -147,7 +167,7 @@ message CreateBsqSwapOfferRequest { } message CreateBsqSwapOfferReply { - BsqSwapOfferInfo bsqSwapOffer = 1; + OfferInfo bsqSwapOffer = 1; } message CreateOfferRequest { @@ -204,25 +224,6 @@ message CancelOfferRequest { message CancelOfferReply { } -message BsqSwapOfferInfo { - string id = 1; - string direction = 2; - uint64 amount = 3; - uint64 minAmount = 4; - uint64 price = 5; - string makerPaymentAccountId = 6; - string paymentMethodId = 7; - string paymentMethodShortName = 8; - string baseCurrencyCode = 9; - string counterCurrencyCode = 10; - uint64 getMakerFee = 11; - uint64 date = 12; - string ownerNodeAddress = 13; - string pubKeyRing = 14; - string versionNr = 15; - int32 protocolVersion = 16; -} - message OfferInfo { string id = 1; string direction = 2; @@ -250,6 +251,11 @@ message OfferInfo { bool isActivated = 24; bool isMyOffer = 25; bool isMyPendingOffer = 26; + bool isBsqSwapOffer = 27; + string ownerNodeAddress = 28; + string pubKeyRing = 29; + string versionNr = 30; + int32 protocolVersion = 31; } message AvailabilityResultWithDescription { @@ -460,33 +466,30 @@ message WithdrawFundsReply { } message BsqSwapTradeInfo { - BsqSwapOfferInfo bsqSwapOfferInfo = 1; + OfferInfo offer = 1; string tradeId = 2; string tempTradingPeerNodeAddress = 3; string peerNodeAddress = 4; string txId = 5; uint64 bsqTradeAmount = 6; - uint64 bsqMaxTradeAmount = 7; - uint64 bsqMinTradeAmount = 8; - uint64 btcTradeAmount = 9; - uint64 btcMaxTradeAmount = 10; - uint64 btcMinTradeAmount = 11; - uint64 tradePrice = 12; - bool isCurrencyForMakerFeeBtc = 13; - bool isCurrencyForTakerFeeBtc = 14; - uint64 bsqMakerTradeFee = 15; - uint64 btcMakerTradeFee = 16; - uint64 bsqTakerTradeFee = 17; - uint64 btcTakerTradeFee = 18; - uint64 txFeePerVbyte = 19; - uint64 txFee = 20; - string makerBsqAddress = 21; - string makerBtcAddress = 22; - string takerBsqAddress = 23; - string takerBtcAddress = 24; - uint64 takeOfferDate = 25; - string state = 26; - string errorMessage = 27; + uint64 btcTradeAmount = 7; + uint64 tradePrice = 8; + bool isCurrencyForMakerFeeBtc = 9; + bool isCurrencyForTakerFeeBtc = 10; + uint64 bsqMakerTradeFee = 11; + uint64 btcMakerTradeFee = 12; + uint64 bsqTakerTradeFee = 13; + uint64 btcTakerTradeFee = 14; + uint64 txFeePerVbyte = 15; + uint64 txFee = 16; + string makerBsqAddress = 17; + string makerBtcAddress = 18; + string takerBsqAddress = 19; + string takerBtcAddress = 20; + uint64 takeOfferDate = 21; + string role = 22; + string state = 23; + string errorMessage = 24; } message TradeInfo { @@ -516,6 +519,8 @@ message TradeInfo { string contractAsJson = 24; ContractInfo contract = 25; uint64 tradeVolume = 26; + // TODO See if a sub-message BsqSwapTradeInfo field could be added here. + // Use the existing BsqSwapTradeInfo message, without the redundant fields. } message ContractInfo { From c6aceb0458a403a43106bd212f404ded3504c98b Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Thu, 11 Nov 2021 12:56:34 -0300 Subject: [PATCH 02/17] Adjust bsq-swap-offer related gRPC daemon services - Add GetOfferCategory service so CLI can determine what kind of takeoffer service is to be used. - Adjust to removal of BsqSwapOfferInfo proto. - Call new coreApi.getRole(BsqSwapTrade) before building BsqSwapTradeInfo proto. --- .../bisq/daemon/grpc/GrpcOffersService.java | 71 +++++++++++++------ .../bisq/daemon/grpc/GrpcTradesService.java | 18 +++-- 2 files changed, 63 insertions(+), 26 deletions(-) diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java index bafd4c17d03..4f2fef1556b 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java @@ -18,7 +18,6 @@ package bisq.daemon.grpc; import bisq.core.api.CoreApi; -import bisq.core.api.model.BsqSwapOfferInfo; import bisq.core.api.model.OfferInfo; import bisq.core.offer.Offer; import bisq.core.offer.OpenOffer; @@ -33,12 +32,15 @@ import bisq.proto.grpc.EditOfferRequest; import bisq.proto.grpc.GetBsqSwapOfferReply; import bisq.proto.grpc.GetBsqSwapOffersReply; +import bisq.proto.grpc.GetBsqSwapOffersRequest; import bisq.proto.grpc.GetMyBsqSwapOfferReply; import bisq.proto.grpc.GetMyBsqSwapOffersReply; import bisq.proto.grpc.GetMyOfferReply; import bisq.proto.grpc.GetMyOfferRequest; import bisq.proto.grpc.GetMyOffersReply; import bisq.proto.grpc.GetMyOffersRequest; +import bisq.proto.grpc.GetOfferCategoryReply; +import bisq.proto.grpc.GetOfferCategoryRequest; import bisq.proto.grpc.GetOfferReply; import bisq.proto.grpc.GetOfferRequest; import bisq.proto.grpc.GetOffersReply; @@ -56,10 +58,15 @@ import lombok.extern.slf4j.Slf4j; -import static bisq.core.api.model.BsqSwapOfferInfo.toBsqSwapOfferInfo; +import static bisq.core.api.model.OfferInfo.toMyPendingOfferInfo; import static bisq.core.api.model.OfferInfo.toOfferInfo; -import static bisq.core.api.model.OfferInfo.toPendingOfferInfo; import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; +import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory; +import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory.ALTCOIN; +import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory.BSQ_SWAP; +import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory.FIAT; +import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory.UNKNOWN; +import static bisq.proto.grpc.GetOfferCategoryReply.newBuilder; import static bisq.proto.grpc.OffersGrpc.*; import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.SECONDS; @@ -81,13 +88,28 @@ public GrpcOffersService(CoreApi coreApi, GrpcExceptionHandler exceptionHandler) this.exceptionHandler = exceptionHandler; } + @Override + public void getOfferCategory(GetOfferCategoryRequest req, + StreamObserver responseObserver) { + try { + OfferCategory category = getAvailableOfferCategory(req.getId()); + var reply = newBuilder() + .setOfferCategory(category) + .build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } catch (Throwable cause) { + exceptionHandler.handleException(log, cause, responseObserver); + } + } + @Override public void getBsqSwapOffer(GetOfferRequest req, StreamObserver responseObserver) { try { Offer offer = coreApi.getOffer(req.getId()); var reply = GetBsqSwapOfferReply.newBuilder() - .setBsqSwapOffer(toBsqSwapOfferInfo(offer).toProtoMessage()) + .setBsqSwapOffer(toOfferInfo(offer).toProtoMessage()) .build(); responseObserver.onNext(reply); responseObserver.onCompleted(); @@ -117,7 +139,7 @@ public void getMyBsqSwapOffer(GetMyOfferRequest req, try { Offer offer = coreApi.getMyBsqSwapOffer(req.getId()); var reply = GetMyBsqSwapOfferReply.newBuilder() - .setBsqSwapOffer(toBsqSwapOfferInfo(offer /* TODO support triggerPrice */).toProtoMessage()) + .setBsqSwapOffer(toOfferInfo(offer /* TODO support triggerPrice */).toProtoMessage()) .build(); responseObserver.onNext(reply); responseObserver.onCompleted(); @@ -132,7 +154,7 @@ public void getMyOffer(GetMyOfferRequest req, try { OpenOffer openOffer = coreApi.getMyOffer(req.getId()); var reply = GetMyOfferReply.newBuilder() - .setOffer(toOfferInfo(openOffer).toProtoMessage()) + .setOffer(OfferInfo.toMyOfferInfo(openOffer).toProtoMessage()) .build(); responseObserver.onNext(reply); responseObserver.onCompleted(); @@ -142,15 +164,15 @@ public void getMyOffer(GetMyOfferRequest req, } @Override - public void getBsqSwapOffers(GetOffersRequest req, + public void getBsqSwapOffers(GetBsqSwapOffersRequest req, StreamObserver responseObserver) { try { - List result = coreApi.getBsqSwapOffers(req.getDirection()) - .stream().map(BsqSwapOfferInfo::toBsqSwapOfferInfo) + List result = coreApi.getBsqSwapOffers(req.getDirection()) + .stream().map(OfferInfo::toOfferInfo) .collect(Collectors.toList()); var reply = GetBsqSwapOffersReply.newBuilder() .addAllBsqSwapOffers(result.stream() - .map(BsqSwapOfferInfo::toProtoMessage) + .map(OfferInfo::toProtoMessage) .collect(Collectors.toList())) .build(); responseObserver.onNext(reply); @@ -180,15 +202,15 @@ public void getOffers(GetOffersRequest req, } @Override - public void getMyBsqSwapOffers(GetMyOffersRequest req, + public void getMyBsqSwapOffers(GetBsqSwapOffersRequest req, StreamObserver responseObserver) { try { - List result = coreApi.getMyBsqSwapOffers(req.getDirection()) - .stream().map(BsqSwapOfferInfo::toBsqSwapOfferInfo) + List result = coreApi.getMyBsqSwapOffers(req.getDirection()) + .stream().map(OfferInfo::toOfferInfo) .collect(Collectors.toList()); var reply = GetMyBsqSwapOffersReply.newBuilder() .addAllBsqSwapOffers(result.stream() - .map(BsqSwapOfferInfo::toProtoMessage) + .map(OfferInfo::toProtoMessage) .collect(Collectors.toList())) .build(); responseObserver.onNext(reply); @@ -204,7 +226,7 @@ public void getMyOffers(GetMyOffersRequest req, try { List result = coreApi.getMyOffers(req.getDirection(), req.getCurrencyCode()) .stream() - .map(OfferInfo::toOfferInfo) + .map(OfferInfo::toMyOfferInfo) .collect(Collectors.toList()); var reply = GetMyOffersReply.newBuilder() .addAllOffers(result.stream() @@ -222,17 +244,15 @@ public void getMyOffers(GetMyOffersRequest req, public void createBsqSwapOffer(CreateBsqSwapOfferRequest req, StreamObserver responseObserver) { try { - //todo PaymentAccount for bsq swap not needed as its just a dummy account coreApi.createAndPlaceBsqSwapOffer( req.getDirection(), req.getAmount(), req.getMinAmount(), req.getPrice(), - /* req.getPaymentAccountId(),*/ offer -> { - BsqSwapOfferInfo bsqSwapOfferInfo = toBsqSwapOfferInfo(offer); + OfferInfo offerInfo = toMyPendingOfferInfo(offer); CreateBsqSwapOfferReply reply = CreateBsqSwapOfferReply.newBuilder() - .setBsqSwapOffer(bsqSwapOfferInfo.toProtoMessage()) + .setBsqSwapOffer(offerInfo.toProtoMessage()) .build(); responseObserver.onNext(reply); responseObserver.onCompleted(); @@ -261,7 +281,7 @@ public void createOffer(CreateOfferRequest req, offer -> { // This result handling consumer's accept operation will return // the new offer to the gRPC client after async placement is done. - OfferInfo offerInfo = toPendingOfferInfo(offer); + OfferInfo offerInfo = toMyPendingOfferInfo(offer); CreateOfferReply reply = CreateOfferReply.newBuilder() .setOffer(offerInfo.toProtoMessage()) .build(); @@ -325,4 +345,15 @@ final Optional rateMeteringInterceptor() { }} ))); } + + private OfferCategory getAvailableOfferCategory(String offerId) { + if (coreApi.isAvailableAltcoinOffer(offerId)) + return ALTCOIN; + else if (coreApi.isAvailableFiatOffer(offerId)) + return FIAT; + else if (coreApi.isAvailableBsqSwapOffer(offerId)) + return BSQ_SWAP; + else + return UNKNOWN; + } } diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java index 5e712e253e1..00ec52305a9 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java @@ -78,9 +78,10 @@ public void getBsqSwapTrade(GetTradeRequest req, StreamObserver responseObserver) { try { var bsqSwapTrade = coreApi.getBsqSwapTrade(req.getTradeId()); - // String role = coreApi.getBsqSwapTradeRole(req.getTradeId()); + boolean wasMyOffer = coreApi.isMyOffer(bsqSwapTrade.getOffer().getId()); + String role = coreApi.getBsqSwapTradeRole(req.getTradeId()); var reply = GetBsqSwapTradeReply.newBuilder() - .setBsqSwapTrade(toBsqSwapTradeInfo(bsqSwapTrade).toProtoMessage()) + .setBsqSwapTrade(toBsqSwapTradeInfo(bsqSwapTrade, role, wasMyOffer).toProtoMessage()) .build(); responseObserver.onNext(reply); responseObserver.onCompleted(); @@ -97,7 +98,7 @@ public void getBsqSwapTrade(GetTradeRequest req, public void takeBsqSwapOffer(TakeBsqSwapOfferRequest req, StreamObserver responseObserver) { GrpcErrorMessageHandler errorMessageHandler = - new GrpcErrorMessageHandler(getTakeOfferMethod().getFullMethodName(), + new GrpcErrorMessageHandler(getTakeBsqSwapOfferMethod().getFullMethodName(), responseObserver, exceptionHandler, log); @@ -105,7 +106,10 @@ public void takeBsqSwapOffer(TakeBsqSwapOfferRequest req, req.getPaymentAccountId(), req.getTakerFeeCurrencyCode(), bsqSwapTrade -> { - BsqSwapTradeInfo bsqSwapTradeInfo = toBsqSwapTradeInfo(bsqSwapTrade); + String role = coreApi.getBsqSwapTradeRole(bsqSwapTrade); + BsqSwapTradeInfo bsqSwapTradeInfo = toBsqSwapTradeInfo(bsqSwapTrade, + role, + false); var reply = TakeBsqSwapOfferReply.newBuilder() .setBsqSwapTrade(bsqSwapTradeInfo.toProtoMessage()) .build(); @@ -123,10 +127,10 @@ public void getTrade(GetTradeRequest req, StreamObserver responseObserver) { try { Trade trade = coreApi.getTrade(req.getTradeId()); - boolean isMyOffer = coreApi.isMyOffer(trade.getOffer().getId()); + boolean wasMyOffer = coreApi.isMyOffer(trade.getOffer().getId()); String role = coreApi.getTradeRole(req.getTradeId()); var reply = GetTradeReply.newBuilder() - .setTrade(toTradeInfo(trade, role, isMyOffer).toProtoMessage()) + .setTrade(toTradeInfo(trade, role, wasMyOffer).toProtoMessage()) .build(); responseObserver.onNext(reply); responseObserver.onCompleted(); @@ -227,7 +231,9 @@ final Optional rateMeteringInterceptor() { .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( new HashMap<>() {{ put(getGetTradeMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS)); + put(getGetBsqSwapTradeMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS)); put(getTakeOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES)); + put(getTakeBsqSwapOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES)); put(getConfirmPaymentStartedMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES)); put(getConfirmPaymentReceivedMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES)); put(getKeepFundsMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES)); From 5d63fd7e3952d00f71e264a5b9e26b5b1ba72204 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Thu, 11 Nov 2021 13:01:48 -0300 Subject: [PATCH 03/17] Partially adjust api proto wrappers for bsq-swap support - Complete BsqSwapTradeInfo impl. - Merge BsqSwapOfferInfo fields into OfferInfo and remove BsqSwapOfferInfo. - Change all model builders to private static class Builder. --- .../bisq/core/api/model/BsqSwapOfferInfo.java | 227 ------------------ .../bisq/core/api/model/BsqSwapTradeInfo.java | 154 +++++------- .../java/bisq/core/api/model/OfferInfo.java | 155 ++++++++---- .../java/bisq/core/api/model/TradeInfo.java | 66 ++--- .../main/java/bisq/core/api/model/TxInfo.java | 24 +- 5 files changed, 216 insertions(+), 410 deletions(-) delete mode 100644 core/src/main/java/bisq/core/api/model/BsqSwapOfferInfo.java diff --git a/core/src/main/java/bisq/core/api/model/BsqSwapOfferInfo.java b/core/src/main/java/bisq/core/api/model/BsqSwapOfferInfo.java deleted file mode 100644 index 487e4fbf23f..00000000000 --- a/core/src/main/java/bisq/core/api/model/BsqSwapOfferInfo.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.core.api.model; - -import bisq.core.offer.Offer; - -import bisq.common.Payload; - -import java.util.Objects; - -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.ToString; - -@EqualsAndHashCode -@ToString -@Getter -public class BsqSwapOfferInfo implements Payload { - private final String id; - private final String direction; - private final long amount; - private final long minAmount; - private final long price; - private final String makerPaymentAccountId; - private final String paymentMethodId; - private final String paymentMethodShortName; - private final String baseCurrencyCode; - private final String counterCurrencyCode; - private final long date; - private final String ownerNodeAddress; - private final String pubKeyRing; // TODO ? - private final String versionNumber; - private final int protocolVersion; - - public BsqSwapOfferInfo(BsqSwapOfferInfoBuilder builder) { - this.id = builder.id; - this.direction = builder.direction; - this.amount = builder.amount; - this.minAmount = builder.minAmount; - this.price = builder.price; - this.makerPaymentAccountId = builder.makerPaymentAccountId; - this.paymentMethodId = builder.paymentMethodId; - this.paymentMethodShortName = builder.paymentMethodShortName; - this.baseCurrencyCode = builder.baseCurrencyCode; - this.counterCurrencyCode = builder.counterCurrencyCode; - this.date = builder.date; - this.ownerNodeAddress = builder.ownerNodeAddress; - this.pubKeyRing = builder.pubKeyRing; - this.versionNumber = builder.versionNumber; - this.protocolVersion = builder.protocolVersion; - } - - public static BsqSwapOfferInfo toBsqSwapOfferInfo(Offer offer) { - // TODO support triggerPrice - return getAtomicOfferInfoBuilder(offer).build(); - } - - private static BsqSwapOfferInfoBuilder getAtomicOfferInfoBuilder(Offer offer) { - return new BsqSwapOfferInfoBuilder() - .withId(offer.getId()) - .withDirection(offer.getDirection().name()) - .withAmount(offer.getAmount().value) - .withMinAmount(offer.getMinAmount().value) - .withPrice(Objects.requireNonNull(offer.getPrice()).getValue()) - //.withMakerPaymentAccountId(offer.getOfferPayloadI().getMakerPaymentAccountId()) - //.withPaymentMethodId(offer.getOfferPayloadI().getPaymentMethodId()) - //.withPaymentMethodShortName(getPaymentMethodById(offer.getOfferPayloadI().getPaymentMethodId()).getShortName()) - .withBaseCurrencyCode(offer.getOfferPayloadBase().getBaseCurrencyCode()) - .withCounterCurrencyCode(offer.getOfferPayloadBase().getCounterCurrencyCode()) - .withDate(offer.getDate().getTime()) - .withOwnerNodeAddress(offer.getOfferPayloadBase().getOwnerNodeAddress().getFullAddress()) - .withPubKeyRing(offer.getOfferPayloadBase().getPubKeyRing().toString()) - .withVersionNumber(offer.getOfferPayloadBase().getVersionNr()) - .withProtocolVersion(offer.getOfferPayloadBase().getProtocolVersion()); - } - - /////////////////////////////////////////////////////////////////////////////////////////// - // PROTO BUFFER - /////////////////////////////////////////////////////////////////////////////////////////// - - @Override - public bisq.proto.grpc.BsqSwapOfferInfo toProtoMessage() { - return bisq.proto.grpc.BsqSwapOfferInfo.newBuilder() - .setId(id) - .setDirection(direction) - .setAmount(amount) - .setMinAmount(minAmount) - .setPrice(price) - .setBaseCurrencyCode(baseCurrencyCode) - .setCounterCurrencyCode(counterCurrencyCode) - .setDate(date) - .setOwnerNodeAddress(ownerNodeAddress) - .setPubKeyRing(pubKeyRing) - .setVersionNr(versionNumber) - .setProtocolVersion(protocolVersion) - .build(); - } - - public static BsqSwapOfferInfo fromProto(bisq.proto.grpc.BsqSwapOfferInfo proto) { - return new BsqSwapOfferInfoBuilder() - .withId(proto.getId()) - .withDirection(proto.getDirection()) - .withAmount(proto.getAmount()) - .withMinAmount(proto.getMinAmount()) - .withPrice(proto.getPrice()) - .withBaseCurrencyCode(proto.getBaseCurrencyCode()) - .withCounterCurrencyCode(proto.getCounterCurrencyCode()) - .withDate(proto.getDate()) - .withOwnerNodeAddress(proto.getOwnerNodeAddress()) - .withPubKeyRing(proto.getPubKeyRing()) - .withVersionNumber(proto.getVersionNr()) - .withProtocolVersion(proto.getProtocolVersion()) - .build(); - } - - public static class BsqSwapOfferInfoBuilder { - private String id; - private String direction; - private long amount; - private long minAmount; - private long price; - private String makerPaymentAccountId; - private String paymentMethodId; - private String paymentMethodShortName; - private String baseCurrencyCode; - private String counterCurrencyCode; - private long date; - private String ownerNodeAddress; - private String pubKeyRing; - private String versionNumber; - private int protocolVersion; - - public BsqSwapOfferInfoBuilder withId(String id) { - this.id = id; - return this; - } - - public BsqSwapOfferInfoBuilder withDirection(String direction) { - this.direction = direction; - return this; - } - - public BsqSwapOfferInfoBuilder withAmount(long amount) { - this.amount = amount; - return this; - } - - public BsqSwapOfferInfoBuilder withMinAmount(long minAmount) { - this.minAmount = minAmount; - return this; - } - - public BsqSwapOfferInfoBuilder withPrice(long price) { - this.price = price; - return this; - } - - public BsqSwapOfferInfoBuilder withMakerPaymentAccountId(String makerPaymentAccountId) { - this.makerPaymentAccountId = makerPaymentAccountId; - return this; - } - - public BsqSwapOfferInfoBuilder withPaymentMethodId(String paymentMethodId) { - this.paymentMethodId = paymentMethodId; - return this; - } - - public BsqSwapOfferInfoBuilder withPaymentMethodShortName(String paymentMethodShortName) { - this.paymentMethodShortName = paymentMethodShortName; - return this; - } - - public BsqSwapOfferInfoBuilder withBaseCurrencyCode(String baseCurrencyCode) { - this.baseCurrencyCode = baseCurrencyCode; - return this; - } - - public BsqSwapOfferInfoBuilder withCounterCurrencyCode(String counterCurrencyCode) { - this.counterCurrencyCode = counterCurrencyCode; - return this; - } - - public BsqSwapOfferInfoBuilder withDate(long date) { - this.date = date; - return this; - } - - public BsqSwapOfferInfoBuilder withOwnerNodeAddress(String ownerNodeAddress) { - this.ownerNodeAddress = ownerNodeAddress; - return this; - } - - public BsqSwapOfferInfoBuilder withPubKeyRing(String pubKeyRing) { - this.pubKeyRing = pubKeyRing; - return this; - } - - public BsqSwapOfferInfoBuilder withVersionNumber(String versionNumber) { - this.versionNumber = versionNumber; - return this; - } - - public BsqSwapOfferInfoBuilder withProtocolVersion(int protocolVersion) { - this.protocolVersion = protocolVersion; - return this; - } - - public BsqSwapOfferInfo build() { - return new BsqSwapOfferInfo(this); - } - } -} diff --git a/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java b/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java index c24dcca0163..ce1fa745ebb 100644 --- a/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java +++ b/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java @@ -25,24 +25,21 @@ import lombok.Getter; import lombok.ToString; -import static bisq.core.api.model.BsqSwapOfferInfo.toBsqSwapOfferInfo; +import static bisq.core.api.model.OfferInfo.toMyOfferInfo; +import static bisq.core.api.model.OfferInfo.toOfferInfo; @EqualsAndHashCode @ToString @Getter public class BsqSwapTradeInfo implements Payload { - private final BsqSwapOfferInfo bsqSwapOffer; + private final OfferInfo bsqSwapOffer; private final String tradeId; private final String tempTradingPeerNodeAddress; private final String peerNodeAddress; private final String txId; private final long bsqTradeAmount; - private final long bsqMaxTradeAmount; - private final long bsqMinTradeAmount; private final long btcTradeAmount; - private final long btcMaxTradeAmount; - private final long btcMinTradeAmount; private final long tradePrice; private final long bsqMakerTradeFee; private final long bsqTakerTradeFee; @@ -53,21 +50,18 @@ public class BsqSwapTradeInfo implements Payload { private final String takerBsqAddress; private final String takerBtcAddress; private final long takeOfferDate; + private final String role; private final String state; private final String errorMessage; - public BsqSwapTradeInfo(BsqSwapTradeInfoBuilder builder) { - this.bsqSwapOffer = builder.bsqSwapOfferInfo; + public BsqSwapTradeInfo(Builder builder) { + this.bsqSwapOffer = builder.bsqSwapOffer; this.tradeId = builder.tradeId; this.tempTradingPeerNodeAddress = builder.tempTradingPeerNodeAddress; this.peerNodeAddress = builder.peerNodeAddress; this.txId = builder.txId; this.bsqTradeAmount = builder.bsqTradeAmount; - this.bsqMaxTradeAmount = builder.bsqMaxTradeAmount; - this.bsqMinTradeAmount = builder.bsqMinTradeAmount; this.btcTradeAmount = builder.btcTradeAmount; - this.btcMaxTradeAmount = builder.btcMaxTradeAmount; - this.btcMinTradeAmount = builder.btcMinTradeAmount; this.tradePrice = builder.tradePrice; this.bsqMakerTradeFee = builder.bsqMakerTradeFee; this.bsqTakerTradeFee = builder.bsqTakerTradeFee; @@ -78,38 +72,38 @@ public BsqSwapTradeInfo(BsqSwapTradeInfoBuilder builder) { this.takerBsqAddress = builder.takerBsqAddress; this.takerBtcAddress = builder.takerBtcAddress; this.takeOfferDate = builder.takeOfferDate; + this.role = builder.role; this.state = builder.state; this.errorMessage = builder.errorMessage; } - public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade) { - return toBsqSwapTradeInfo(trade, null); - } - - //TODO - public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade, String role) { - return new BsqSwapTradeInfoBuilder() - .withBsqSwapOffer(toBsqSwapOfferInfo(trade.getOffer())) + public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade, String role, boolean wasMyOffer) { + var protocolModel = trade.getBsqSwapProtocolModel(); + var swapPeer = protocolModel.getTradePeer(); + var makerBsqAddress = wasMyOffer ? protocolModel.getBsqAddress() : swapPeer.getBsqAddress(); + var makerBtcAddress = wasMyOffer ? protocolModel.getBtcAddress() : swapPeer.getBtcAddress(); + var takerBsqAddress = wasMyOffer ? swapPeer.getBsqAddress() : protocolModel.getBsqAddress(); + var takerBtcAddress = wasMyOffer ? swapPeer.getBtcAddress() : protocolModel.getBtcAddress(); + var offerInfo = wasMyOffer ? toMyOfferInfo(trade.getOffer()) : toOfferInfo(trade.getOffer()); + return new Builder() + .withBsqSwapOffer(offerInfo) .withTradeId(trade.getId()) .withTempTradingPeerNodeAddress(trade.getBsqSwapProtocolModel().getTempTradingPeerNodeAddress().getFullAddress()) .withPeerNodeAddress(trade.getTradingPeerNodeAddress().getFullAddress()) .withTxId(trade.getTxId()) - /* .withBsqTradeAmount(trade.getBsqSwapProtocolModel().getBsqTradeAmount()) - .withBsqMaxTradeAmount(trade.getBsqSwapProtocolModel().getBsqMaxTradeAmount()) - .withBsqMinTradeAmount(trade.getBsqSwapProtocolModel().getBsqMinTradeAmount()) - .withBtcTradeAmount(trade.getBsqSwapProtocolModel().getBtcTradeAmount()) - .withBtcMaxTradeAmount(trade.getBsqSwapProtocolModel().getBtcMaxTradeAmount()) - .withBtcMinTradeAmount(trade.getBsqSwapProtocolModel().getBtcMinTradeAmount()) - .withTradePrice(trade.getBsqSwapProtocolModel().getTradePrice()) - .withBsqMakerTradeFee(trade.getBsqSwapProtocolModel().getBsqMakerTradeFee()) - .withBsqTakerTradeFee(trade.getBsqSwapProtocolModel().getBsqTakerTradeFee()) - .withTxFeePerVbyte(trade.getBsqSwapProtocolModel().getTxFeePerVbyte()) - .withTxFee(trade.getBsqSwapProtocolModel().getTxFee()) - .withMakerBsqAddress(trade.getBsqSwapProtocolModel().getMakerBsqAddress()) - .withMakerBtcAddress(trade.getBsqSwapProtocolModel().getMakerBtcAddress()) - .withTakerBsqAddress(trade.getBsqSwapProtocolModel().getTakerBsqAddress()) - .withTakerBtcAddress(trade.getBsqSwapProtocolModel().getTakerBtcAddress())*/ + .withBsqTradeAmount(trade.getBsqTradeAmount()) + .withBtcTradeAmount(trade.getAmountAsLong()) + .withTradePrice(trade.getPrice().getValue()) + .withBsqMakerTradeFee(trade.getMakerFeeAsLong()) + .withBsqTakerTradeFee(trade.getTakerFeeAsLong()) + .withTxFeePerVbyte(trade.getTxFeePerVbyte()) + .withTxFee(trade.getTxFee().value) + .withMakerBsqAddress(makerBsqAddress) + .withMakerBtcAddress(makerBtcAddress) + .withTakerBsqAddress(takerBsqAddress) + .withTakerBtcAddress(takerBtcAddress) .withTakeOfferDate(trade.getTakeOfferDate()) + .withRole(role == null ? "" : role) .withState(trade.getTradeState().name()) .withErrorMessage(trade.getErrorMessage()) .build(); @@ -122,17 +116,13 @@ public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade, String rol @Override public bisq.proto.grpc.BsqSwapTradeInfo toProtoMessage() { return bisq.proto.grpc.BsqSwapTradeInfo.newBuilder() - .setBsqSwapOfferInfo(bsqSwapOffer.toProtoMessage()) + .setOffer(bsqSwapOffer.toProtoMessage()) .setTradeId(tradeId) .setTempTradingPeerNodeAddress(tempTradingPeerNodeAddress != null ? tempTradingPeerNodeAddress : "") .setPeerNodeAddress(peerNodeAddress != null ? peerNodeAddress : "") .setTxId(txId != null ? txId : "") .setBsqTradeAmount(bsqTradeAmount) - .setBsqMaxTradeAmount(bsqMaxTradeAmount) - .setBsqMinTradeAmount(bsqMinTradeAmount) .setBtcTradeAmount(btcTradeAmount) - .setBtcMaxTradeAmount(btcMaxTradeAmount) - .setBtcMinTradeAmount(btcMinTradeAmount) .setTradePrice(tradePrice) .setBsqMakerTradeFee(bsqMakerTradeFee) .setBsqTakerTradeFee(bsqTakerTradeFee) @@ -143,24 +133,21 @@ public bisq.proto.grpc.BsqSwapTradeInfo toProtoMessage() { .setMakerBtcAddress(makerBtcAddress != null ? makerBtcAddress : "") .setTakerBtcAddress(takerBtcAddress != null ? takerBtcAddress : "") .setTakeOfferDate(takeOfferDate) + .setRole(role) .setState(state) .setErrorMessage(errorMessage != null ? errorMessage : "") .build(); } public static BsqSwapTradeInfo fromProto(bisq.proto.grpc.BsqSwapTradeInfo proto) { - return new BsqSwapTradeInfoBuilder() - .withBsqSwapOffer(BsqSwapOfferInfo.fromProto(proto.getBsqSwapOfferInfo())) + return new Builder() + .withBsqSwapOffer(OfferInfo.fromProto(proto.getOffer())) .withTradeId(proto.getTradeId()) .withTempTradingPeerNodeAddress(proto.getTempTradingPeerNodeAddress()) .withPeerNodeAddress(proto.getPeerNodeAddress()) .withTxId(proto.getTxId()) .withBsqTradeAmount(proto.getBsqTradeAmount()) - .withBsqMaxTradeAmount(proto.getBsqMaxTradeAmount()) - .withBsqMinTradeAmount(proto.getBsqMinTradeAmount()) .withBtcTradeAmount(proto.getBtcTradeAmount()) - .withBtcMaxTradeAmount(proto.getBtcMaxTradeAmount()) - .withBtcMinTradeAmount(proto.getBtcMinTradeAmount()) .withTradePrice(proto.getTradePrice()) .withBsqMakerTradeFee(proto.getBsqMakerTradeFee()) .withBsqTakerTradeFee(proto.getBsqTakerTradeFee()) @@ -171,23 +158,20 @@ public static BsqSwapTradeInfo fromProto(bisq.proto.grpc.BsqSwapTradeInfo proto) .withTakerBsqAddress(proto.getTakerBsqAddress()) .withTakerBtcAddress(proto.getTakerBtcAddress()) .withTakeOfferDate(proto.getTakeOfferDate()) + .withRole(proto.getRole()) .withState(proto.getState()) .withErrorMessage(proto.getErrorMessage()) .build(); } - public static class BsqSwapTradeInfoBuilder { - private BsqSwapOfferInfo bsqSwapOfferInfo; + private static class Builder { + private OfferInfo bsqSwapOffer; private String tradeId; private String tempTradingPeerNodeAddress; private String peerNodeAddress; private String txId; private long bsqTradeAmount; - private long bsqMaxTradeAmount; - private long bsqMinTradeAmount; private long btcTradeAmount; - private long btcMaxTradeAmount; - private long btcMinTradeAmount; private long tradePrice; private long bsqMakerTradeFee; private long bsqTakerTradeFee; @@ -198,120 +182,106 @@ public static class BsqSwapTradeInfoBuilder { private String takerBsqAddress; private String takerBtcAddress; private long takeOfferDate; + private String role; private String state; private String errorMessage; - public BsqSwapTradeInfoBuilder withBsqSwapOffer(BsqSwapOfferInfo bsqSwapOfferInfo) { - this.bsqSwapOfferInfo = bsqSwapOfferInfo; + public Builder withBsqSwapOffer(OfferInfo bsqSwapOffer) { + this.bsqSwapOffer = bsqSwapOffer; return this; } - public BsqSwapTradeInfoBuilder withTradeId(String tradeId) { + public Builder withTradeId(String tradeId) { this.tradeId = tradeId; return this; } - public BsqSwapTradeInfoBuilder withTempTradingPeerNodeAddress(String tempTradingPeerNodeAddress) { + public Builder withTempTradingPeerNodeAddress(String tempTradingPeerNodeAddress) { this.tempTradingPeerNodeAddress = tempTradingPeerNodeAddress; return this; } - public BsqSwapTradeInfoBuilder withPeerNodeAddress(String peerNodeAddress) { + public Builder withPeerNodeAddress(String peerNodeAddress) { this.peerNodeAddress = peerNodeAddress; return this; } - public BsqSwapTradeInfoBuilder withTxId(String txId) { + public Builder withTxId(String txId) { this.txId = txId; return this; } - public BsqSwapTradeInfoBuilder withBsqTradeAmount(long bsqTradeAmount) { + public Builder withBsqTradeAmount(long bsqTradeAmount) { this.bsqTradeAmount = bsqTradeAmount; return this; } - public BsqSwapTradeInfoBuilder withBsqMaxTradeAmount(long bsqMaxTradeAmount) { - this.bsqMaxTradeAmount = bsqMaxTradeAmount; - return this; - } - - public BsqSwapTradeInfoBuilder withBsqMinTradeAmount(long bsqMinTradeAmount) { - this.bsqMinTradeAmount = bsqMinTradeAmount; - return this; - } - - public BsqSwapTradeInfoBuilder withBtcTradeAmount(long btcTradeAmount) { + public Builder withBtcTradeAmount(long btcTradeAmount) { this.btcTradeAmount = btcTradeAmount; return this; } - public BsqSwapTradeInfoBuilder withBtcMaxTradeAmount(long btcMaxTradeAmount) { - this.btcMaxTradeAmount = btcMaxTradeAmount; - return this; - } - - public BsqSwapTradeInfoBuilder withBtcMinTradeAmount(long btcMinTradeAmount) { - this.btcMinTradeAmount = btcMinTradeAmount; - return this; - } - - public BsqSwapTradeInfoBuilder withTradePrice(long tradePrice) { + public Builder withTradePrice(long tradePrice) { this.tradePrice = tradePrice; return this; } - public BsqSwapTradeInfoBuilder withBsqMakerTradeFee(long bsqMakerTradeFee) { + public Builder withBsqMakerTradeFee(long bsqMakerTradeFee) { this.bsqMakerTradeFee = bsqMakerTradeFee; return this; } - public BsqSwapTradeInfoBuilder withBsqTakerTradeFee(long bsqTakerTradeFee) { + public Builder withBsqTakerTradeFee(long bsqTakerTradeFee) { this.bsqTakerTradeFee = bsqTakerTradeFee; return this; } - public BsqSwapTradeInfoBuilder withTxFeePerVbyte(long txFeePerVbyte) { + public Builder withTxFeePerVbyte(long txFeePerVbyte) { this.txFeePerVbyte = txFeePerVbyte; return this; } - public BsqSwapTradeInfoBuilder withTxFee(long txFee) { + public Builder withTxFee(long txFee) { this.txFee = txFee; return this; } - public BsqSwapTradeInfoBuilder withMakerBsqAddress(String makerBsqAddress) { + public Builder withMakerBsqAddress(String makerBsqAddress) { this.makerBsqAddress = makerBsqAddress; return this; } - public BsqSwapTradeInfoBuilder withMakerBtcAddress(String makerBtcAddress) { + public Builder withMakerBtcAddress(String makerBtcAddress) { this.makerBtcAddress = makerBtcAddress; return this; } - public BsqSwapTradeInfoBuilder withTakerBsqAddress(String takerBsqAddress) { + public Builder withTakerBsqAddress(String takerBsqAddress) { this.takerBsqAddress = takerBsqAddress; return this; } - public BsqSwapTradeInfoBuilder withTakerBtcAddress(String takerBtcAddress) { + public Builder withTakerBtcAddress(String takerBtcAddress) { this.takerBtcAddress = takerBtcAddress; return this; } - public BsqSwapTradeInfoBuilder withTakeOfferDate(long takeOfferDate) { + public Builder withTakeOfferDate(long takeOfferDate) { this.takeOfferDate = takeOfferDate; return this; } - public BsqSwapTradeInfoBuilder withState(String state) { + public Builder withRole(String role) { + this.role = role; + return this; + } + + public Builder withState(String state) { this.state = state; return this; } - public BsqSwapTradeInfoBuilder withErrorMessage(String errorMessage) { + public Builder withErrorMessage(String errorMessage) { this.errorMessage = errorMessage; return this; } diff --git a/core/src/main/java/bisq/core/api/model/OfferInfo.java b/core/src/main/java/bisq/core/api/model/OfferInfo.java index 67cee988a3b..f84e69ad001 100644 --- a/core/src/main/java/bisq/core/api/model/OfferInfo.java +++ b/core/src/main/java/bisq/core/api/model/OfferInfo.java @@ -19,6 +19,7 @@ import bisq.core.offer.Offer; import bisq.core.offer.OpenOffer; +import bisq.core.util.coin.CoinUtil; import bisq.common.Payload; @@ -28,6 +29,8 @@ import lombok.Getter; import lombok.ToString; +import static java.util.Objects.requireNonNull; + @EqualsAndHashCode @ToString @Getter @@ -56,17 +59,22 @@ public class OfferInfo implements Payload { private final String paymentAccountId; private final String paymentMethodId; private final String paymentMethodShortName; - // For fiat offer the baseCurrencyCode is BTC and the counterCurrencyCode is the fiat currency - // For altcoin offers it is the opposite. baseCurrencyCode is the altcoin and the counterCurrencyCode is BTC. + // Fiat offer: baseCurrencyCode = BTC, counterCurrencyCode = fiat ccy code. + // Altcoin offer: baseCurrencyCode = altcoin ccy code, counterCurrencyCode = BTC. private final String baseCurrencyCode; private final String counterCurrencyCode; private final long date; private final String state; private final boolean isActivated; - private boolean isMyOffer; // Not final -- may be re-set after instantiation. + private final boolean isMyOffer; private final boolean isMyPendingOffer; + private final boolean isBsqSwapOffer; + private final String ownerNodeAddress; + private final String pubKeyRing; + private final String versionNumber; + private final int protocolVersion; - public OfferInfo(OfferInfoBuilder builder) { + public OfferInfo(Builder builder) { this.id = builder.id; this.direction = builder.direction; this.price = builder.price; @@ -93,39 +101,43 @@ public OfferInfo(OfferInfoBuilder builder) { this.isActivated = builder.isActivated; this.isMyOffer = builder.isMyOffer; this.isMyPendingOffer = builder.isMyPendingOffer; + this.isBsqSwapOffer = builder.isBsqSwapOffer; + this.ownerNodeAddress = builder.ownerNodeAddress; + this.pubKeyRing = builder.pubKeyRing; + this.versionNumber = builder.versionNumber; + this.protocolVersion = builder.protocolVersion; } - // Allow isMyOffer to be set on a new offer's OfferInfo instance. - public void setIsMyOffer(boolean isMyOffer) { - this.isMyOffer = isMyOffer; + public static OfferInfo toMyOfferInfo(Offer offer) { + return getBuilder(offer, true).build(); } public static OfferInfo toOfferInfo(Offer offer) { // Assume the offer is not mine, but isMyOffer can be reset to true, i.e., when // calling TradeInfo toTradeInfo(Trade trade, String role, boolean isMyOffer); - return getOfferInfoBuilder(offer, false).build(); + return getBuilder(offer, false).build(); } - public static OfferInfo toPendingOfferInfo(Offer myNewOffer) { + public static OfferInfo toMyPendingOfferInfo(Offer myNewOffer) { // Use this to build an OfferInfo instance when a new OpenOffer is being // prepared, and no valid OpenOffer state (AVAILABLE, DEACTIVATED) exists. // It is needed for the CLI's 'createoffer' output, which has a boolean 'ENABLED' // column that will show a PENDING value when this.isMyPendingOffer = true. - return getOfferInfoBuilder(myNewOffer, true) + return getBuilder(myNewOffer, true) .withIsMyPendingOffer(true) .build(); } - public static OfferInfo toOfferInfo(OpenOffer openOffer) { + public static OfferInfo toMyOfferInfo(OpenOffer openOffer) { // An OpenOffer is always my offer. - return getOfferInfoBuilder(openOffer.getOffer(), true) + return getBuilder(openOffer.getOffer(), true) .withTriggerPrice(openOffer.getTriggerPrice()) .withIsActivated(!openOffer.isDeactivated()) .build(); } - private static OfferInfoBuilder getOfferInfoBuilder(Offer offer, boolean isMyOffer) { - return new OfferInfoBuilder() + private static Builder getBuilder(Offer offer, boolean isMyOffer) { + return new Builder() .withId(offer.getId()) .withDirection(offer.getDirection().name()) .withPrice(Objects.requireNonNull(offer.getPrice()).getValue()) @@ -135,7 +147,7 @@ private static OfferInfoBuilder getOfferInfoBuilder(Offer offer, boolean isMyOff .withMinAmount(offer.getMinAmount().value) .withVolume(Objects.requireNonNull(offer.getVolume()).getValue()) .withMinVolume(Objects.requireNonNull(offer.getMinVolume()).getValue()) - .withMakerFee(offer.getMakerFee().value) + .withMakerFee(getMakerFee(offer, isMyOffer)) .withTxFee(offer.getTxFee().value) .withOfferFeePaymentTxId(offer.getOfferFeePaymentTxId()) .withBuyerSecurityDeposit(offer.getBuyerSecurityDeposit().value) @@ -148,7 +160,18 @@ private static OfferInfoBuilder getOfferInfoBuilder(Offer offer, boolean isMyOff .withCounterCurrencyCode(offer.getCounterCurrencyCode()) .withDate(offer.getDate().getTime()) .withState(offer.getState().name()) - .withIsMyOffer(isMyOffer); + .withIsMyOffer(isMyOffer) + .withIsBsqSwapOffer(offer.isBsqSwapOffer()) + .withOwnerNodeAddress(offer.getOfferPayloadBase().getOwnerNodeAddress().getFullAddress()) + .withPubKeyRing(offer.getOfferPayloadBase().getPubKeyRing().toString()) + .withVersionNumber(offer.getOfferPayloadBase().getVersionNr()) + .withProtocolVersion(offer.getOfferPayloadBase().getProtocolVersion()); + } + + private static long getMakerFee(Offer offer, boolean isMyOffer) { + return isMyOffer + ? requireNonNull(CoinUtil.getMakerFee(false, offer.getAmount())).value + : 0; } /////////////////////////////////////////////////////////////////////////////////////////// @@ -169,7 +192,7 @@ public bisq.proto.grpc.OfferInfo toProtoMessage() { .setMinVolume(minVolume) .setMakerFee(makerFee) .setTxFee(txFee) - .setOfferFeePaymentTxId(offerFeePaymentTxId) + .setOfferFeePaymentTxId(isBsqSwapOffer ? "" : offerFeePaymentTxId) .setBuyerSecurityDeposit(buyerSecurityDeposit) .setSellerSecurityDeposit(sellerSecurityDeposit) .setTriggerPrice(triggerPrice) @@ -184,12 +207,17 @@ public bisq.proto.grpc.OfferInfo toProtoMessage() { .setIsActivated(isActivated) .setIsMyOffer(isMyOffer) .setIsMyPendingOffer(isMyPendingOffer) + .setIsBsqSwapOffer(isBsqSwapOffer) + .setOwnerNodeAddress(ownerNodeAddress) + .setPubKeyRing(pubKeyRing) + .setVersionNr(versionNumber) + .setProtocolVersion(protocolVersion) .build(); } @SuppressWarnings("unused") public static OfferInfo fromProto(bisq.proto.grpc.OfferInfo proto) { - return new OfferInfoBuilder() + return new Builder() .withId(proto.getId()) .withDirection(proto.getDirection()) .withPrice(proto.getPrice()) @@ -216,16 +244,21 @@ public static OfferInfo fromProto(bisq.proto.grpc.OfferInfo proto) { .withIsActivated(proto.getIsActivated()) .withIsMyOffer(proto.getIsMyOffer()) .withIsMyPendingOffer(proto.getIsMyPendingOffer()) + .withIsBsqSwapOffer(proto.getIsBsqSwapOffer()) + .withOwnerNodeAddress(proto.getOwnerNodeAddress()) + .withPubKeyRing(proto.getPubKeyRing()) + .withVersionNumber(proto.getVersionNr()) + .withProtocolVersion(proto.getProtocolVersion()) .build(); } /* - * OfferInfoBuilder helps avoid bungling use of a large OfferInfo constructor + * Builder helps avoid bungling use of a large OfferInfo constructor * argument list. If consecutive argument values of the same type are not * ordered correctly, the compiler won't complain but the resulting bugs could * be hard to find and fix. */ - public static class OfferInfoBuilder { + private static class Builder { private String id; private String direction; private long price; @@ -252,137 +285,167 @@ public static class OfferInfoBuilder { private boolean isActivated; private boolean isMyOffer; private boolean isMyPendingOffer; + private boolean isBsqSwapOffer; + private String ownerNodeAddress; + private String pubKeyRing; + private String versionNumber; + private int protocolVersion; - public OfferInfoBuilder withId(String id) { + public Builder withId(String id) { this.id = id; return this; } - public OfferInfoBuilder withDirection(String direction) { + public Builder withDirection(String direction) { this.direction = direction; return this; } - public OfferInfoBuilder withPrice(long price) { + public Builder withPrice(long price) { this.price = price; return this; } - public OfferInfoBuilder withUseMarketBasedPrice(boolean useMarketBasedPrice) { + public Builder withUseMarketBasedPrice(boolean useMarketBasedPrice) { this.useMarketBasedPrice = useMarketBasedPrice; return this; } - public OfferInfoBuilder withMarketPriceMargin(double useMarketBasedPrice) { + public Builder withMarketPriceMargin(double useMarketBasedPrice) { this.marketPriceMargin = useMarketBasedPrice; return this; } - public OfferInfoBuilder withAmount(long amount) { + public Builder withAmount(long amount) { this.amount = amount; return this; } - public OfferInfoBuilder withMinAmount(long minAmount) { + public Builder withMinAmount(long minAmount) { this.minAmount = minAmount; return this; } - public OfferInfoBuilder withVolume(long volume) { + public Builder withVolume(long volume) { this.volume = volume; return this; } - public OfferInfoBuilder withMinVolume(long minVolume) { + public Builder withMinVolume(long minVolume) { this.minVolume = minVolume; return this; } - public OfferInfoBuilder withTxFee(long txFee) { + public Builder withTxFee(long txFee) { this.txFee = txFee; return this; } - public OfferInfoBuilder withMakerFee(long makerFee) { + public Builder withMakerFee(long makerFee) { this.makerFee = makerFee; return this; } - public OfferInfoBuilder withOfferFeePaymentTxId(String offerFeePaymentTxId) { + public Builder withOfferFeePaymentTxId(String offerFeePaymentTxId) { this.offerFeePaymentTxId = offerFeePaymentTxId; return this; } - public OfferInfoBuilder withBuyerSecurityDeposit(long buyerSecurityDeposit) { + public Builder withBuyerSecurityDeposit(long buyerSecurityDeposit) { this.buyerSecurityDeposit = buyerSecurityDeposit; return this; } - public OfferInfoBuilder withSellerSecurityDeposit(long sellerSecurityDeposit) { + public Builder withSellerSecurityDeposit(long sellerSecurityDeposit) { this.sellerSecurityDeposit = sellerSecurityDeposit; return this; } - public OfferInfoBuilder withTriggerPrice(long triggerPrice) { + public Builder withTriggerPrice(long triggerPrice) { this.triggerPrice = triggerPrice; return this; } - public OfferInfoBuilder withIsCurrencyForMakerFeeBtc(boolean isCurrencyForMakerFeeBtc) { + public Builder withIsCurrencyForMakerFeeBtc(boolean isCurrencyForMakerFeeBtc) { this.isCurrencyForMakerFeeBtc = isCurrencyForMakerFeeBtc; return this; } - public OfferInfoBuilder withPaymentAccountId(String paymentAccountId) { + public Builder withPaymentAccountId(String paymentAccountId) { this.paymentAccountId = paymentAccountId; return this; } - public OfferInfoBuilder withPaymentMethodId(String paymentMethodId) { + public Builder withPaymentMethodId(String paymentMethodId) { this.paymentMethodId = paymentMethodId; return this; } - public OfferInfoBuilder withPaymentMethodShortName(String paymentMethodShortName) { + public Builder withPaymentMethodShortName(String paymentMethodShortName) { this.paymentMethodShortName = paymentMethodShortName; return this; } - public OfferInfoBuilder withBaseCurrencyCode(String baseCurrencyCode) { + public Builder withBaseCurrencyCode(String baseCurrencyCode) { this.baseCurrencyCode = baseCurrencyCode; return this; } - public OfferInfoBuilder withCounterCurrencyCode(String counterCurrencyCode) { + public Builder withCounterCurrencyCode(String counterCurrencyCode) { this.counterCurrencyCode = counterCurrencyCode; return this; } - public OfferInfoBuilder withDate(long date) { + public Builder withDate(long date) { this.date = date; return this; } - public OfferInfoBuilder withState(String state) { + public Builder withState(String state) { this.state = state; return this; } - public OfferInfoBuilder withIsActivated(boolean isActivated) { + public Builder withIsActivated(boolean isActivated) { this.isActivated = isActivated; return this; } - public OfferInfoBuilder withIsMyOffer(boolean isMyOffer) { + public Builder withIsMyOffer(boolean isMyOffer) { this.isMyOffer = isMyOffer; return this; } - public OfferInfoBuilder withIsMyPendingOffer(boolean isMyPendingOffer) { + public Builder withIsMyPendingOffer(boolean isMyPendingOffer) { this.isMyPendingOffer = isMyPendingOffer; return this; } + public Builder withIsBsqSwapOffer(boolean isBsqSwapOffer) { + this.isBsqSwapOffer = isBsqSwapOffer; + return this; + } + + public Builder withOwnerNodeAddress(String ownerNodeAddress) { + this.ownerNodeAddress = ownerNodeAddress; + return this; + } + + public Builder withPubKeyRing(String pubKeyRing) { + this.pubKeyRing = pubKeyRing; + return this; + } + + public Builder withVersionNumber(String versionNumber) { + this.versionNumber = versionNumber; + return this; + } + + public Builder withProtocolVersion(int protocolVersion) { + this.protocolVersion = protocolVersion; + return this; + } + public OfferInfo build() { return new OfferInfo(this); } diff --git a/core/src/main/java/bisq/core/api/model/TradeInfo.java b/core/src/main/java/bisq/core/api/model/TradeInfo.java index 024eb69fa2f..3e2bc8b56ea 100644 --- a/core/src/main/java/bisq/core/api/model/TradeInfo.java +++ b/core/src/main/java/bisq/core/api/model/TradeInfo.java @@ -27,6 +27,7 @@ import lombok.EqualsAndHashCode; import lombok.Getter; +import static bisq.core.api.model.OfferInfo.toMyOfferInfo; import static bisq.core.api.model.OfferInfo.toOfferInfo; import static bisq.core.api.model.PaymentAccountPayloadInfo.toPaymentAccountPayloadInfo; @@ -65,7 +66,7 @@ public class TradeInfo implements Payload { private final String contractAsJson; private final ContractInfo contract; - public TradeInfo(TradeInfoBuilder builder) { + public TradeInfo(Builder builder) { this.offer = builder.offer; this.tradeId = builder.tradeId; this.shortId = builder.shortId; @@ -118,9 +119,8 @@ public static TradeInfo toTradeInfo(Trade trade, String role, boolean isMyOffer) contractInfo = ContractInfo.emptyContract.get(); } - OfferInfo offerInfo = toOfferInfo(trade.getOffer()); - offerInfo.setIsMyOffer(isMyOffer); - return new TradeInfoBuilder() + OfferInfo offerInfo = isMyOffer ? toMyOfferInfo(trade.getOffer()) : toOfferInfo(trade.getOffer()); + return new Builder() .withOffer(offerInfo) .withTradeId(trade.getId()) .withShortId(trade.getShortId()) @@ -189,7 +189,7 @@ public bisq.proto.grpc.TradeInfo toProtoMessage() { } public static TradeInfo fromProto(bisq.proto.grpc.TradeInfo proto) { - return new TradeInfoBuilder() + return new Builder() .withOffer(OfferInfo.fromProto(proto.getOffer())) .withTradeId(proto.getTradeId()) .withShortId(proto.getShortId()) @@ -220,12 +220,12 @@ public static TradeInfo fromProto(bisq.proto.grpc.TradeInfo proto) { } /* - * TradeInfoBuilder helps avoid bungling use of a large TradeInfo constructor + * Builder helps avoid bungling use of a large TradeInfo constructor * argument list. If consecutive argument values of the same type are not * ordered correctly, the compiler won't complain but the resulting bugs could * be hard to find and fix. */ - public static class TradeInfoBuilder { + private static class Builder { private OfferInfo offer; private String tradeId; private String shortId; @@ -253,132 +253,132 @@ public static class TradeInfoBuilder { private String contractAsJson; private ContractInfo contract; - public TradeInfoBuilder withOffer(OfferInfo offer) { + public Builder withOffer(OfferInfo offer) { this.offer = offer; return this; } - public TradeInfoBuilder withTradeId(String tradeId) { + public Builder withTradeId(String tradeId) { this.tradeId = tradeId; return this; } - public TradeInfoBuilder withShortId(String shortId) { + public Builder withShortId(String shortId) { this.shortId = shortId; return this; } - public TradeInfoBuilder withDate(long date) { + public Builder withDate(long date) { this.date = date; return this; } - public TradeInfoBuilder withRole(String role) { + public Builder withRole(String role) { this.role = role; return this; } - public TradeInfoBuilder withIsCurrencyForTakerFeeBtc(boolean isCurrencyForTakerFeeBtc) { + public Builder withIsCurrencyForTakerFeeBtc(boolean isCurrencyForTakerFeeBtc) { this.isCurrencyForTakerFeeBtc = isCurrencyForTakerFeeBtc; return this; } - public TradeInfoBuilder withTxFeeAsLong(long txFeeAsLong) { + public Builder withTxFeeAsLong(long txFeeAsLong) { this.txFeeAsLong = txFeeAsLong; return this; } - public TradeInfoBuilder withTakerFeeAsLong(long takerFeeAsLong) { + public Builder withTakerFeeAsLong(long takerFeeAsLong) { this.takerFeeAsLong = takerFeeAsLong; return this; } - public TradeInfoBuilder withTakerFeeTxId(String takerFeeTxId) { + public Builder withTakerFeeTxId(String takerFeeTxId) { this.takerFeeTxId = takerFeeTxId; return this; } - public TradeInfoBuilder withDepositTxId(String depositTxId) { + public Builder withDepositTxId(String depositTxId) { this.depositTxId = depositTxId; return this; } - public TradeInfoBuilder withPayoutTxId(String payoutTxId) { + public Builder withPayoutTxId(String payoutTxId) { this.payoutTxId = payoutTxId; return this; } - public TradeInfoBuilder withTradeAmountAsLong(long tradeAmountAsLong) { + public Builder withTradeAmountAsLong(long tradeAmountAsLong) { this.tradeAmountAsLong = tradeAmountAsLong; return this; } - public TradeInfoBuilder withTradePrice(long tradePrice) { + public Builder withTradePrice(long tradePrice) { this.tradePrice = tradePrice; return this; } - public TradeInfoBuilder withTradeVolume(long tradeVolume) { + public Builder withTradeVolume(long tradeVolume) { this.tradeVolume = tradeVolume; return this; } - public TradeInfoBuilder withTradePeriodState(String tradePeriodState) { + public Builder withTradePeriodState(String tradePeriodState) { this.tradePeriodState = tradePeriodState; return this; } - public TradeInfoBuilder withState(String state) { + public Builder withState(String state) { this.state = state; return this; } - public TradeInfoBuilder withPhase(String phase) { + public Builder withPhase(String phase) { this.phase = phase; return this; } - public TradeInfoBuilder withTradingPeerNodeAddress(String tradingPeerNodeAddress) { + public Builder withTradingPeerNodeAddress(String tradingPeerNodeAddress) { this.tradingPeerNodeAddress = tradingPeerNodeAddress; return this; } - public TradeInfoBuilder withIsDepositPublished(boolean isDepositPublished) { + public Builder withIsDepositPublished(boolean isDepositPublished) { this.isDepositPublished = isDepositPublished; return this; } - public TradeInfoBuilder withIsDepositConfirmed(boolean isDepositConfirmed) { + public Builder withIsDepositConfirmed(boolean isDepositConfirmed) { this.isDepositConfirmed = isDepositConfirmed; return this; } - public TradeInfoBuilder withIsFiatSent(boolean isFiatSent) { + public Builder withIsFiatSent(boolean isFiatSent) { this.isFiatSent = isFiatSent; return this; } - public TradeInfoBuilder withIsFiatReceived(boolean isFiatReceived) { + public Builder withIsFiatReceived(boolean isFiatReceived) { this.isFiatReceived = isFiatReceived; return this; } - public TradeInfoBuilder withIsPayoutPublished(boolean isPayoutPublished) { + public Builder withIsPayoutPublished(boolean isPayoutPublished) { this.isPayoutPublished = isPayoutPublished; return this; } - public TradeInfoBuilder withIsWithdrawn(boolean isWithdrawn) { + public Builder withIsWithdrawn(boolean isWithdrawn) { this.isWithdrawn = isWithdrawn; return this; } - public TradeInfoBuilder withContractAsJson(String contractAsJson) { + public Builder withContractAsJson(String contractAsJson) { this.contractAsJson = contractAsJson; return this; } - public TradeInfoBuilder withContract(ContractInfo contract) { + public Builder withContract(ContractInfo contract) { this.contract = contract; return this; } diff --git a/core/src/main/java/bisq/core/api/model/TxInfo.java b/core/src/main/java/bisq/core/api/model/TxInfo.java index 3bd937c96e5..54023b2ec3a 100644 --- a/core/src/main/java/bisq/core/api/model/TxInfo.java +++ b/core/src/main/java/bisq/core/api/model/TxInfo.java @@ -46,7 +46,7 @@ public class TxInfo implements Payload { private final boolean isPending; private final String memo; - public TxInfo(TxInfoBuilder builder) { + public TxInfo(Builder builder) { this.txId = builder.txId; this.inputSum = builder.inputSum; this.outputSum = builder.outputSum; @@ -61,7 +61,7 @@ public static TxInfo toTxInfo(Transaction transaction) { throw new IllegalStateException("server created a null transaction"); if (transaction.getFee() != null) - return new TxInfoBuilder() + return new Builder() .withTxId(transaction.getTxId().toString()) .withInputSum(transaction.getInputSum().value) .withOutputSum(transaction.getOutputSum().value) @@ -71,7 +71,7 @@ public static TxInfo toTxInfo(Transaction transaction) { .withMemo(transaction.getMemo()) .build(); else - return new TxInfoBuilder() + return new Builder() .withTxId(transaction.getTxId().toString()) .withInputSum(transaction.getInputSum().value) .withOutputSum(transaction.getOutputSum().value) @@ -101,7 +101,7 @@ public bisq.proto.grpc.TxInfo toProtoMessage() { @SuppressWarnings("unused") public static TxInfo fromProto(bisq.proto.grpc.TxInfo proto) { - return new TxInfoBuilder() + return new Builder() .withTxId(proto.getTxId()) .withInputSum(proto.getInputSum()) .withOutputSum(proto.getOutputSum()) @@ -112,7 +112,7 @@ public static TxInfo fromProto(bisq.proto.grpc.TxInfo proto) { .build(); } - public static class TxInfoBuilder { + private static class Builder { private String txId; private long inputSum; private long outputSum; @@ -121,37 +121,37 @@ public static class TxInfoBuilder { private boolean isPending; private String memo; - public TxInfoBuilder withTxId(String txId) { + public Builder withTxId(String txId) { this.txId = txId; return this; } - public TxInfoBuilder withInputSum(long inputSum) { + public Builder withInputSum(long inputSum) { this.inputSum = inputSum; return this; } - public TxInfoBuilder withOutputSum(long outputSum) { + public Builder withOutputSum(long outputSum) { this.outputSum = outputSum; return this; } - public TxInfoBuilder withFee(long fee) { + public Builder withFee(long fee) { this.fee = fee; return this; } - public TxInfoBuilder withSize(int size) { + public Builder withSize(int size) { this.size = size; return this; } - public TxInfoBuilder withIsPending(boolean isPending) { + public Builder withIsPending(boolean isPending) { this.isPending = isPending; return this; } - public TxInfoBuilder withMemo(String memo) { + public Builder withMemo(String memo) { this.memo = memo; return this; } From 713b309f4a3f4141847e658b3a210702089052de Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Thu, 11 Nov 2021 13:06:23 -0300 Subject: [PATCH 04/17] Add String getRole(BsqSwapTrade trade) method --- .../bisq/core/trade/bisq_v1/TradeUtil.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/core/src/main/java/bisq/core/trade/bisq_v1/TradeUtil.java b/core/src/main/java/bisq/core/trade/bisq_v1/TradeUtil.java index 3f99e7dea9b..9d8212a060b 100644 --- a/core/src/main/java/bisq/core/trade/bisq_v1/TradeUtil.java +++ b/core/src/main/java/bisq/core/trade/bisq_v1/TradeUtil.java @@ -25,6 +25,7 @@ import bisq.core.trade.model.TradeModel; import bisq.core.trade.model.bisq_v1.Contract; import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.model.bsq_swap.BsqSwapTrade; import bisq.network.p2p.NodeAddress; @@ -57,6 +58,8 @@ @Singleton public class TradeUtil { + // TODO change non-state dependent instance methods to static methods. + private final BtcWalletService btcWalletService; private final KeyRing keyRing; @@ -203,6 +206,24 @@ public String getRole(Trade trade) { offer.getCurrencyCode()); } + /** + * Returns a string describing a trader's role for a given bsq swap. + * @param trade BsqSwapTrade + * @return String describing a trader's role for a given bsq swap + */ + public String getRole(BsqSwapTrade trade) { + Offer offer = trade.getOffer(); + if (offer == null) + throw new IllegalStateException( + format("could not get role because no offer was found for bsq swap '%s'", + trade.getShortId())); + + KeyRing keyRing = trade.getBsqSwapProtocolModel().getKeyRing(); + return getRole(offer.isBuyOffer(), + offer.isMyOffer(keyRing), + offer.getCurrencyCode()); + } + /** * Returns a string describing a trader's role. * From 521495c41d88ceb94cf9454342649a29f166e543 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Thu, 11 Nov 2021 13:07:49 -0300 Subject: [PATCH 05/17] Add conveniences isFiatOffer(offer), isAltcoinOffer(offer) --- core/src/main/java/bisq/core/offer/OfferUtil.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/src/main/java/bisq/core/offer/OfferUtil.java b/core/src/main/java/bisq/core/offer/OfferUtil.java index c676c57bbdc..d13d45742f7 100644 --- a/core/src/main/java/bisq/core/offer/OfferUtil.java +++ b/core/src/main/java/bisq/core/offer/OfferUtil.java @@ -488,6 +488,14 @@ private Optional getFeeInUserFiatCurrency(Coin makerFee, } } + public static boolean isFiatOffer(Offer offer) { + return offer.getBaseCurrencyCode().equals("BTC") && !offer.isBsqSwapOffer(); + } + + public static boolean isAltcoinOffer(Offer offer) { + return offer.getCounterCurrencyCode().equals("BTC") && !offer.isBsqSwapOffer(); + } + public static Optional getInvalidMakerFeeTxErrorMessage(Offer offer, BtcWalletService btcWalletService) { String offerFeePaymentTxId = offer.getOfferFeePaymentTxId(); if (offerFeePaymentTxId == null) { From 3dfbf3f6f0c2b08a86a8a9455f01ca90d7392779 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Thu, 11 Nov 2021 13:12:41 -0300 Subject: [PATCH 06/17] Partially adjust core api for bsq-swap support - Add core api methods to help CLI determine which type of offer to take for a given offerId. CLI's 'takeoffer` will need to determine which gRPC/proto request type to send to server. - Add implemetations for getBsqSwapTradeRole(), for tradeId or trade. --- core/src/main/java/bisq/core/api/CoreApi.java | 20 +++++++++++ .../java/bisq/core/api/CoreOffersService.java | 33 ++++++++++++++----- .../java/bisq/core/api/CoreTradesService.java | 16 +++++++-- 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/bisq/core/api/CoreApi.java b/core/src/main/java/bisq/core/api/CoreApi.java index 510c4cfcbc7..409299c3330 100644 --- a/core/src/main/java/bisq/core/api/CoreApi.java +++ b/core/src/main/java/bisq/core/api/CoreApi.java @@ -119,6 +119,18 @@ public String getMethodHelp(String methodName) { // Offers /////////////////////////////////////////////////////////////////////////////////////////// + public boolean isAvailableFiatOffer(String id) { + return coreOffersService.isAvailableFiatOffer(id); + } + + public boolean isAvailableAltcoinOffer(String id) { + return coreOffersService.isAvailableAltcoinOffer(id); + } + + public boolean isAvailableBsqSwapOffer(String id) { + return coreOffersService.isAvailableBsqSwapOffer(id); + } + public Offer getBsqSwapOffer(String id) { return coreOffersService.getBsqSwapOffer(id); } @@ -317,6 +329,14 @@ public String getTradeRole(String tradeId) { return coreTradesService.getTradeRole(tradeId); } + public String getBsqSwapTradeRole(String tradeId) { + return coreTradesService.getBsqSwapTradeRole(tradeId); + } + + public String getBsqSwapTradeRole(BsqSwapTrade bsqSwapTrade) { + return coreTradesService.getBsqSwapTradeRole(bsqSwapTrade); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Wallets /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/src/main/java/bisq/core/api/CoreOffersService.java b/core/src/main/java/bisq/core/api/CoreOffersService.java index adbcee01dd4..74e8af6c304 100644 --- a/core/src/main/java/bisq/core/api/CoreOffersService.java +++ b/core/src/main/java/bisq/core/api/CoreOffersService.java @@ -60,6 +60,9 @@ import static bisq.core.locale.CurrencyUtil.isCryptoCurrency; import static bisq.core.offer.Offer.State; import static bisq.core.offer.OfferDirection.BUY; +import static bisq.core.offer.OfferUtil.getRandomOfferId; +import static bisq.core.offer.OfferUtil.isAltcoinOffer; +import static bisq.core.offer.OfferUtil.isFiatOffer; import static bisq.core.offer.OpenOffer.State.AVAILABLE; import static bisq.core.offer.OpenOffer.State.DEACTIVATED; import static bisq.core.payment.PaymentAccountUtil.isPaymentAccountValidForOffer; @@ -118,6 +121,19 @@ public CoreOffersService(CoreContext coreContext, this.user = user; } + boolean isAvailableFiatOffer(String id) { + return isFiatOffer(getOffer(id)); + } + + boolean isAvailableAltcoinOffer(String id) { + return isAltcoinOffer(getOffer(id)); + } + + boolean isAvailableBsqSwapOffer(String id) { + var offer = getOffer(id); + return offer.isBsqSwapOffer(); + } + Offer getBsqSwapOffer(String id) { return offerBookService.getOffers().stream() .filter(o -> o.getId().equals(id)) @@ -154,7 +170,6 @@ Offer getMyBsqSwapOffer(String id) { new IllegalStateException(format("offer with id '%s' not found", id))); } - List getBsqSwapOffers(String direction) { var offers = offerBookService.getOffers().stream() .filter(o -> !o.isMyOffer(keyRing)) @@ -208,9 +223,12 @@ OpenOffer getMyOpenOffer(String id) { } boolean isMyOffer(String id) { - return openOfferManager.getOpenOfferById(id) + boolean isMyOpenOffer = openOfferManager.getOpenOfferById(id) .filter(open -> open.getOffer().isMyOffer(keyRing)) .isPresent(); + boolean wasMyOffer = offerBookService.getOffers().stream() + .anyMatch(o -> o.getId().equals(id) && o.isMyOffer(keyRing)); + return isMyOpenOffer || wasMyOffer; } void createAndPlaceBsqSwapOffer(String directionAsString, @@ -222,7 +240,7 @@ void createAndPlaceBsqSwapOffer(String directionAsString, coreWalletsService.verifyEncryptedWalletIsUnlocked(); String currencyCode = "BSQ"; - String offerId = OfferUtil.getRandomOfferId(); + String offerId = getRandomOfferId(); OfferDirection direction = OfferDirection.valueOf(directionAsString.toUpperCase()); Coin amount = Coin.valueOf(amountAsLong); Coin minAmount = Coin.valueOf(minAmountAsLong); @@ -256,7 +274,7 @@ void createAndPlaceOffer(String currencyCode, throw new IllegalArgumentException(format("payment account with id %s not found", paymentAccountId)); String upperCaseCurrencyCode = currencyCode.toUpperCase(); - String offerId = OfferUtil.getRandomOfferId(); + String offerId = getRandomOfferId(); OfferDirection direction = OfferDirection.valueOf(directionAsString.toUpperCase()); Price price = Price.valueOf(upperCaseCurrencyCode, priceStringToLong(priceAsString, upperCaseCurrencyCode)); Coin amount = Coin.valueOf(amountAsLong); @@ -427,10 +445,9 @@ private void verifyPaymentAccountIsValidForNewOffer(Offer offer, PaymentAccount private boolean offerMatchesDirectionAndCurrency(Offer offer, String direction, String currencyCode) { - var offerOfWantedDirection = offer.getDirection().name().equalsIgnoreCase(direction); - var offerInWantedCurrency = offer.getCounterCurrencyCode() - .equalsIgnoreCase(currencyCode); - return offerOfWantedDirection && offerInWantedCurrency; + var isDirectionMatch = offer.getDirection().name().equalsIgnoreCase(direction); + var isCurrencyMatch = offer.getCounterCurrencyCode().equalsIgnoreCase(currencyCode); + return isDirectionMatch && isCurrencyMatch; } private Comparator openOfferPriceComparator(String direction) { diff --git a/core/src/main/java/bisq/core/api/CoreTradesService.java b/core/src/main/java/bisq/core/api/CoreTradesService.java index 5c08a61a48f..6fdb23434db 100644 --- a/core/src/main/java/bisq/core/api/CoreTradesService.java +++ b/core/src/main/java/bisq/core/api/CoreTradesService.java @@ -108,8 +108,10 @@ void takeBsqSwapOffer(Offer offer, log.info("Initiating take {} offer, {}", offer.isBuyOffer() ? "buy" : "sell", bsqSwapTakeOfferModel); - - bsqSwapTakeOfferModel.onTakeOffer(tradeResultHandler, log::warn, errorMessageHandler, coreContext.isApiUser()); + bsqSwapTakeOfferModel.onTakeOffer(tradeResultHandler, + log::warn, + errorMessageHandler, + coreContext.isApiUser()); } void takeOffer(Offer offer, @@ -239,6 +241,16 @@ BsqSwapTrade getBsqSwapTrade(String tradeId) { new IllegalArgumentException(format("trade with id '%s' not found", tradeId))); } + String getBsqSwapTradeRole(String tradeId) { + return getBsqSwapTradeRole(getBsqSwapTrade(tradeId)); + } + + String getBsqSwapTradeRole(BsqSwapTrade bsqSwapTrade) { + coreWalletsService.verifyWalletsAreAvailable(); + coreWalletsService.verifyEncryptedWalletIsUnlocked(); + return tradeUtil.getRole(bsqSwapTrade); + } + String getTradeRole(String tradeId) { coreWalletsService.verifyWalletsAreAvailable(); coreWalletsService.verifyEncryptedWalletIsUnlocked(); From 16be35790b2af4dec60853639ad2c5002cee856a Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Thu, 11 Nov 2021 13:20:58 -0300 Subject: [PATCH 07/17] Paritally adjust bsq-swap-offer related gRPC CLI side classes - Adjust to removal of BsqSwapOfferInfo proto, use ammended OfferInfo instead. - Remove currency-code param from all get(My)BsqSwapOffer(s) requests. - Add new OfferCategory getAvailableOfferCategory(String offerId) service. CLI uses this to determine which kind of gRPC request object should be sent with a 'takeoffer' request. - Adjust GetOffersSmokeTest to help see offer/swap-offer CLI output. --- cli/src/main/java/bisq/cli/GrpcClient.java | 64 ++++++++--------- .../cli/request/OffersServiceRequest.java | 68 ++++++++++++------- .../cli/request/TradesServiceRequest.java | 13 ++++ .../java/bisq/cli/GetOffersSmokeTest.java | 37 +++++++++- 4 files changed, 119 insertions(+), 63 deletions(-) diff --git a/cli/src/main/java/bisq/cli/GrpcClient.java b/cli/src/main/java/bisq/cli/GrpcClient.java index dcdaddc5508..fe27e1ea9c7 100644 --- a/cli/src/main/java/bisq/cli/GrpcClient.java +++ b/cli/src/main/java/bisq/cli/GrpcClient.java @@ -20,17 +20,15 @@ import bisq.proto.grpc.AddressBalanceInfo; import bisq.proto.grpc.BalancesInfo; import bisq.proto.grpc.BsqBalanceInfo; -import bisq.proto.grpc.BsqSwapOfferInfo; import bisq.proto.grpc.BsqSwapTradeInfo; import bisq.proto.grpc.BtcBalanceInfo; -import bisq.proto.grpc.CreateBsqSwapOfferRequest; import bisq.proto.grpc.GetMethodHelpRequest; +import bisq.proto.grpc.GetOfferCategoryReply; import bisq.proto.grpc.GetVersionRequest; import bisq.proto.grpc.OfferInfo; import bisq.proto.grpc.RegisterDisputeAgentRequest; import bisq.proto.grpc.StopRequest; import bisq.proto.grpc.TakeBsqSwapOfferReply; -import bisq.proto.grpc.TakeBsqSwapOfferRequest; import bisq.proto.grpc.TakeOfferReply; import bisq.proto.grpc.TradeInfo; import bisq.proto.grpc.TxFeeRateInfo; @@ -142,19 +140,20 @@ public TxInfo getTransaction(String txId) { return walletsServiceRequest.getTransaction(txId); } - public BsqSwapOfferInfo createBsqSwapOffer(String direction, - long amount, - long minAmount, - String fixedPrice, - String paymentAcctId) { - var request = CreateBsqSwapOfferRequest.newBuilder() - .setDirection(direction) - .setAmount(amount) - .setMinAmount(minAmount) - .setPrice(fixedPrice) - .setPaymentAccountId(paymentAcctId) - .build(); - return grpcStubs.offersService.createBsqSwapOffer(request).getBsqSwapOffer(); + public GetOfferCategoryReply.OfferCategory getAvailableOfferCategory(String offerId) { + return offersServiceRequest.getAvailableOfferCategory(offerId); + } + + public OfferInfo createBsqSwapOffer(String direction, + long amount, + long minAmount, + String fixedPrice, + String paymentAcctId) { + return offersServiceRequest.createBsqSwapOffer(direction, + amount, + minAmount, + fixedPrice, + paymentAcctId); } public OfferInfo createFixedPricedOffer(String direction, @@ -263,7 +262,7 @@ public void cancelOffer(String offerId) { offersServiceRequest.cancelOffer(offerId); } - public BsqSwapOfferInfo getBsqSwapOffer(String offerId) { + public OfferInfo getBsqSwapOffer(String offerId) { return offersServiceRequest.getBsqSwapOffer(offerId); } @@ -271,7 +270,7 @@ public OfferInfo getOffer(String offerId) { return offersServiceRequest.getOffer(offerId); } - public BsqSwapOfferInfo getMyBsqSwapOffer(String offerId) { + public OfferInfo getMyBsqSwapOffer(String offerId) { return offersServiceRequest.getMyBsqSwapOffer(offerId); } @@ -279,8 +278,8 @@ public OfferInfo getMyOffer(String offerId) { return offersServiceRequest.getMyOffer(offerId); } - public List getBsqSwapOffers(String direction, String currencyCode) { - return offersServiceRequest.getBsqSwapOffers(direction, currencyCode); + public List getBsqSwapOffers(String direction) { + return offersServiceRequest.getBsqSwapOffers(direction); } public List getOffers(String direction, String currencyCode) { @@ -303,12 +302,12 @@ public List getBsqOffersSortedByDate() { return offersServiceRequest.getBsqOffersSortedByDate(); } - public List getBsqSwapOffersSortedByDate() { + public List getBsqSwapOffersSortedByDate() { return offersServiceRequest.getBsqSwapOffersSortedByDate(); } - public List getMyBsqSwapOffers(String direction, String currencyCode) { - return offersServiceRequest.getMyBsqSwapOffers(direction, currencyCode); + public List getMyBsqSwapOffers(String direction) { + return offersServiceRequest.getMyBsqSwapOffers(direction); } public List getMyOffers(String direction, String currencyCode) { @@ -335,7 +334,7 @@ public List getMyBsqOffersSortedByDate() { return offersServiceRequest.getMyBsqOffersSortedByDate(); } - public List getMyBsqSwapBsqOffersSortedByDate() { + public List getMyBsqSwapBsqOffersSortedByDate() { return offersServiceRequest.getMyBsqSwapOffersSortedByDate(); } @@ -343,23 +342,20 @@ public OfferInfo getMostRecentOffer(String direction, String currencyCode) { return offersServiceRequest.getMostRecentOffer(direction, currencyCode); } - public List sortBsqSwapOffersByDate(List offerInfoList) { - return offersServiceRequest.sortBsqSwapOffersByDate(offerInfoList); + public List sortBsqSwapOffersByDate(List offers) { + return offersServiceRequest.sortOffersByDate(offers); } - public List sortOffersByDate(List offerInfoList) { - return offersServiceRequest.sortOffersByDate(offerInfoList); + public List sortOffersByDate(List offers) { + return offersServiceRequest.sortOffersByDate(offers); } public TakeBsqSwapOfferReply getTakeBsqSwapOfferReply(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { - var request = TakeBsqSwapOfferRequest.newBuilder() - .setOfferId(offerId) - .setPaymentAccountId(paymentAccountId) - .setTakerFeeCurrencyCode(takerFeeCurrencyCode) - .build(); - return grpcStubs.tradesService.takeBsqSwapOffer(request); + return tradesServiceRequest.getTakeBsqSwapOfferReply(offerId, + paymentAccountId, + takerFeeCurrencyCode); } public TakeOfferReply getTakeOfferReply(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { diff --git a/cli/src/main/java/bisq/cli/request/OffersServiceRequest.java b/cli/src/main/java/bisq/cli/request/OffersServiceRequest.java index 259ff8e142d..273d95073f4 100644 --- a/cli/src/main/java/bisq/cli/request/OffersServiceRequest.java +++ b/cli/src/main/java/bisq/cli/request/OffersServiceRequest.java @@ -17,12 +17,15 @@ package bisq.cli.request; -import bisq.proto.grpc.BsqSwapOfferInfo; import bisq.proto.grpc.CancelOfferRequest; +import bisq.proto.grpc.CreateBsqSwapOfferRequest; import bisq.proto.grpc.CreateOfferRequest; import bisq.proto.grpc.EditOfferRequest; +import bisq.proto.grpc.GetBsqSwapOffersRequest; import bisq.proto.grpc.GetMyOfferRequest; import bisq.proto.grpc.GetMyOffersRequest; +import bisq.proto.grpc.GetOfferCategoryReply; +import bisq.proto.grpc.GetOfferCategoryRequest; import bisq.proto.grpc.GetOfferRequest; import bisq.proto.grpc.GetOffersRequest; import bisq.proto.grpc.OfferInfo; @@ -60,6 +63,28 @@ public OffersServiceRequest(GrpcStubs grpcStubs) { this.grpcStubs = grpcStubs; } + public GetOfferCategoryReply.OfferCategory getAvailableOfferCategory(String offerId) { + var request = GetOfferCategoryRequest.newBuilder() + .setId(offerId) + .build(); + return grpcStubs.offersService.getOfferCategory(request).getOfferCategory(); + } + + public OfferInfo createBsqSwapOffer(String direction, + long amount, + long minAmount, + String fixedPrice, + String paymentAcctId) { + var request = CreateBsqSwapOfferRequest.newBuilder() + .setDirection(direction) + .setAmount(amount) + .setMinAmount(minAmount) + .setPrice(fixedPrice) + .setPaymentAccountId(paymentAcctId) + .build(); + return grpcStubs.offersService.createBsqSwapOffer(request).getBsqSwapOffer(); + } + @SuppressWarnings("unused") public OfferInfo createFixedPricedOffer(String direction, String currencyCode, @@ -210,7 +235,7 @@ public void cancelOffer(String offerId) { grpcStubs.offersService.cancelOffer(request); } - public BsqSwapOfferInfo getBsqSwapOffer(String offerId) { + public OfferInfo getBsqSwapOffer(String offerId) { var request = GetOfferRequest.newBuilder() .setId(offerId) .build(); @@ -224,7 +249,7 @@ public OfferInfo getOffer(String offerId) { return grpcStubs.offersService.getOffer(request).getOffer(); } - public BsqSwapOfferInfo getMyBsqSwapOffer(String offerId) { + public OfferInfo getMyBsqSwapOffer(String offerId) { var request = GetMyOfferRequest.newBuilder() .setId(offerId) .build(); @@ -239,10 +264,9 @@ public OfferInfo getMyOffer(String offerId) { return grpcStubs.offersService.getMyOffer(request).getOffer(); } - public List getBsqSwapOffers(String direction, String currencyCode) { - var request = GetOffersRequest.newBuilder() + public List getBsqSwapOffers(String direction) { + var request = GetBsqSwapOffersRequest.newBuilder() .setDirection(direction) - .setCurrencyCode(currencyCode) .build(); return grpcStubs.offersService.getBsqSwapOffers(request).getBsqSwapOffersList(); @@ -278,11 +302,11 @@ public List getOffersSortedByDate(String direction, String currencyCo return offers.isEmpty() ? offers : sortOffersByDate(offers); } - public List getBsqSwapOffersSortedByDate() { - ArrayList offers = new ArrayList<>(); - offers.addAll(getBsqSwapOffers(BUY.name(), "BSQ")); - offers.addAll(getBsqSwapOffers(SELL.name(), "BSQ")); - return sortBsqSwapOffersByDate(offers); + public List getBsqSwapOffersSortedByDate() { + ArrayList offers = new ArrayList<>(); + offers.addAll(getBsqSwapOffers(BUY.name())); + offers.addAll(getBsqSwapOffers(SELL.name())); + return sortOffersByDate(offers); } public List getBsqOffersSortedByDate() { @@ -292,10 +316,9 @@ public List getBsqOffersSortedByDate() { return sortOffersByDate(offers); } - public List getMyBsqSwapOffers(String direction, String currencyCode) { - var request = GetMyOffersRequest.newBuilder() + public List getMyBsqSwapOffers(String direction) { + var request = GetBsqSwapOffersRequest.newBuilder() .setDirection(direction) - .setCurrencyCode(currencyCode) .build(); return grpcStubs.offersService.getMyBsqSwapOffers(request).getBsqSwapOffersList(); } @@ -344,11 +367,11 @@ public List getMyBsqOffersSortedByDate() { return sortOffersByDate(offers); } - public List getMyBsqSwapOffersSortedByDate() { - ArrayList offers = new ArrayList<>(); - offers.addAll(getMyBsqSwapOffers(BUY.name(), "BSQ")); - offers.addAll(getMyBsqSwapOffers(SELL.name(), "BSQ")); - return sortBsqSwapOffersByDate(offers); + public List getMyBsqSwapOffersSortedByDate() { + ArrayList offers = new ArrayList<>(); + offers.addAll(getMyBsqSwapOffers(BUY.name())); + offers.addAll(getMyBsqSwapOffers(SELL.name())); + return sortOffersByDate(offers); } public OfferInfo getMostRecentOffer(String direction, String currencyCode) { @@ -356,13 +379,6 @@ public OfferInfo getMostRecentOffer(String direction, String currencyCode) { return offers.isEmpty() ? null : offers.get(offers.size() - 1); } - public List sortBsqSwapOffersByDate(List offerInfoList) { - return offerInfoList.stream() - .sorted(comparing(BsqSwapOfferInfo::getDate)) - .collect(toList()); - - } - public List sortOffersByDate(List offerInfoList) { return offerInfoList.stream() .sorted(comparing(OfferInfo::getDate)) diff --git a/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java b/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java index 97d7d2a5efe..9c18685ca7f 100644 --- a/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java +++ b/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java @@ -22,6 +22,8 @@ import bisq.proto.grpc.ConfirmPaymentStartedRequest; import bisq.proto.grpc.GetTradeRequest; import bisq.proto.grpc.KeepFundsRequest; +import bisq.proto.grpc.TakeBsqSwapOfferReply; +import bisq.proto.grpc.TakeBsqSwapOfferRequest; import bisq.proto.grpc.TakeOfferReply; import bisq.proto.grpc.TakeOfferRequest; import bisq.proto.grpc.TradeInfo; @@ -39,6 +41,17 @@ public TradesServiceRequest(GrpcStubs grpcStubs) { this.grpcStubs = grpcStubs; } + public TakeBsqSwapOfferReply getTakeBsqSwapOfferReply(String offerId, + String paymentAccountId, + String takerFeeCurrencyCode) { + var request = TakeBsqSwapOfferRequest.newBuilder() + .setOfferId(offerId) + .setPaymentAccountId(paymentAccountId) + .setTakerFeeCurrencyCode(takerFeeCurrencyCode) + .build(); + return grpcStubs.tradesService.takeBsqSwapOffer(request); + } + public TakeOfferReply getTakeOfferReply(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { var request = TakeOfferRequest.newBuilder() .setOfferId(offerId) diff --git a/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java b/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java index f613aea358c..aa871c3e863 100644 --- a/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java +++ b/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java @@ -14,12 +14,44 @@ public class GetOffersSmokeTest { public static void main(String[] args) { + getMyBsqOffers(); + // getAvailableBsqOffers(); + // getMyUsdOffers(); + // getAvailableUsdOffers(); + } + + private static void getMyBsqOffers() { + out.println(">>> getmyoffers buy bsq"); + CliMain.main(new String[]{"--password=xyz", "--port=9998", "getmyoffers", "--direction=buy", "--currency-code=bsq"}); + out.println(">>> getmyoffers sell bsq"); + CliMain.main(new String[]{"--password=xyz", "--port=9998", "getmyoffers", "--direction=sell", "--currency-code=bsq"}); + out.println(">>> getmyoffer --offer-id=KRONTTMO-11cef1a9-c636-4dc7-b3f2-1616e4960c28-175"); + CliMain.main(new String[]{"--password=xyz", "--port=9998", "getmyoffer", "--offer-id=KRONTTMO-11cef1a9-c636-4dc7-b3f2-1616e4960c28-175"}); + } + + private static void getAvailableBsqOffers() { + out.println(">>> getoffers buy bsq"); + CliMain.main(new String[]{"--password=xyz", "--port=9998", "getoffers", "--direction=buy", "--currency-code=bsq"}); + out.println(">>> getoffers sell bsq"); + CliMain.main(new String[]{"--password=xyz", "--port=9998", "getoffers", "--direction=sell", "--currency-code=bsq"}); + } + + private static void getMyUsdOffers() { + out.println(">>> getmyoffers buy usd"); + CliMain.main(new String[]{"--password=xyz", "--port=9998", "getmyoffers", "--direction=buy", "--currency-code=usd"}); + out.println(">>> getmyoffers sell usd"); + CliMain.main(new String[]{"--password=xyz", "--port=9998", "getmyoffers", "--direction=sell", "--currency-code=usd"}); + } + + private static void getAvailableUsdOffers() { out.println(">>> getoffers buy usd"); - CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=buy", "--currency-code=usd"}); + CliMain.main(new String[]{"--password=xyz", "--port=9998", "getoffers", "--direction=buy", "--currency-code=usd"}); out.println(">>> getoffers sell usd"); - CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=sell", "--currency-code=usd"}); + CliMain.main(new String[]{"--password=xyz", "--port=9998", "getoffers", "--direction=sell", "--currency-code=usd"}); + } + private static void TODO() { out.println(">>> getoffers buy eur"); CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=buy", "--currency-code=eur"}); out.println(">>> getoffers sell eur"); @@ -35,5 +67,4 @@ public static void main(String[] args) { out.println(">>> getoffers sell brl"); CliMain.main(new String[]{"--password=xyz", "getoffers", "--direction=sell", "--currency-code=brl"}); } - } From c5f50b53e485cfca81c98c4b663deb31f53939ee Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Thu, 11 Nov 2021 13:24:45 -0300 Subject: [PATCH 08/17] Paritally adjust bsq-swap-offer related apitest cases - Adjust to removal of BsqSwapOfferInfo proto, use ammended OfferInfo instead. - Remove currency-code param from all get(My)BsqSwapOffer(s) requests. --- .../method/offer/AbstractOfferTest.java | 6 --- .../method/offer/BsqSwapOfferTest.java | 15 +++--- .../method/trade/BsqSwapTradeTest.java | 51 ++++++++++--------- .../java/bisq/apitest/scenario/TradeTest.java | 2 + 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java b/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java index f5b8904815c..fb8c2d76330 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java @@ -17,7 +17,6 @@ package bisq.apitest.method.offer; -import bisq.proto.grpc.BsqSwapOfferInfo; import bisq.proto.grpc.OfferInfo; import protobuf.PaymentAccount; @@ -112,11 +111,6 @@ public static void setUp() { protected final Function, String> toOffersTable = (offers) -> new TableBuilder(OFFER_TBL, offers).build().toString(); - // TODO - protected final Function toBsqSwapOfferTable = (offer) -> - new TableBuilder(OFFER_TBL, offer).build().toString(); - - public static void initSwapPaymentAccounts() { // A bot may not know what the default 'BSQ Swap' account name is, // but API test cases do: the value of the i18n property 'BSQ_SWAP'. diff --git a/apitest/src/test/java/bisq/apitest/method/offer/BsqSwapOfferTest.java b/apitest/src/test/java/bisq/apitest/method/offer/BsqSwapOfferTest.java index bdb516c5157..2d65c55c35f 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/BsqSwapOfferTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/BsqSwapOfferTest.java @@ -17,7 +17,7 @@ package bisq.apitest.method.offer; -import bisq.proto.grpc.BsqSwapOfferInfo; +import bisq.proto.grpc.OfferInfo; import lombok.extern.slf4j.Slf4j; @@ -121,7 +121,6 @@ private void createBsqSwapOffer() { assertEquals(5_000, bsqSwapOffer.getPrice()); assertEquals(1_000_000L, bsqSwapOffer.getAmount()); assertEquals(1_000_000L, bsqSwapOffer.getMinAmount()); - // assertEquals(alicesBsqAcct.getId(), atomicOffer.getMakerPaymentAccountId()); assertEquals(BSQ, bsqSwapOffer.getBaseCurrencyCode()); assertEquals(BTC, bsqSwapOffer.getCounterCurrencyCode()); @@ -129,13 +128,13 @@ private void createBsqSwapOffer() { testGetBsqSwapOffer(bsqSwapOffer); } - private void testGetMyBsqSwapOffer(BsqSwapOfferInfo bsqSwapOfferInfo) { + private void testGetMyBsqSwapOffer(OfferInfo bsqSwapOffer) { int numFetchAttempts = 0; while (true) { try { numFetchAttempts++; - var fetchedBsqSwapOffer = aliceClient.getMyBsqSwapOffer(bsqSwapOfferInfo.getId()); - assertEquals(bsqSwapOfferInfo.getId(), fetchedBsqSwapOffer.getId()); + var fetchedBsqSwapOffer = aliceClient.getMyOffer(bsqSwapOffer.getId()); + assertEquals(bsqSwapOffer.getId(), fetchedBsqSwapOffer.getId()); log.debug("Alice found her (my) new bsq swap offer on attempt # {}.", numFetchAttempts); break; } catch (Exception ex) { @@ -149,13 +148,13 @@ private void testGetMyBsqSwapOffer(BsqSwapOfferInfo bsqSwapOfferInfo) { } } - private void testGetBsqSwapOffer(BsqSwapOfferInfo bsqSwapOfferInfo) { + private void testGetBsqSwapOffer(OfferInfo bsqSwapOffer) { int numFetchAttempts = 0; while (true) { try { numFetchAttempts++; - var fetchedBsqSwapOffer = bobClient.getBsqSwapOffer(bsqSwapOfferInfo.getId()); - assertEquals(bsqSwapOfferInfo.getId(), fetchedBsqSwapOffer.getId()); + var fetchedBsqSwapOffer = bobClient.getOffer(bsqSwapOffer.getId()); + assertEquals(bsqSwapOffer.getId(), fetchedBsqSwapOffer.getId()); log.debug("Bob found new available bsq swap offer on attempt # {}.", numFetchAttempts); break; } catch (Exception ex) { diff --git a/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java b/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java index 73261907db2..654ed4a594a 100644 --- a/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java +++ b/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java @@ -17,8 +17,8 @@ package bisq.apitest.method.trade; -import bisq.proto.grpc.BsqSwapOfferInfo; import bisq.proto.grpc.BsqSwapTradeInfo; +import bisq.proto.grpc.OfferInfo; import java.util.ArrayList; import java.util.List; @@ -81,54 +81,59 @@ public void testGetBalancesBeforeTrade() { @Test @Order(2) public void testAliceCreateBsqSwapBuyOffer() { - var bsqSwapOffer = aliceClient.createBsqSwapOffer(BUY.name(), - 1_000_000L, + var mySwapOffer = aliceClient.createBsqSwapOffer(BUY.name(), + 1_000_000L, // 0.01 BTC 1_000_000L, "0.00005", alicesBsqSwapAcct.getId()); - log.debug("BsqSwap Sell BSQ (Buy BTC) OFFER:\n{}", bsqSwapOffer); - var newOfferId = bsqSwapOffer.getId(); + log.debug("Pending BsqSwap Sell BSQ (Buy BTC) OFFER:\n{}", toOfferTable.apply(mySwapOffer)); + var newOfferId = mySwapOffer.getId(); assertNotEquals("", newOfferId); - assertEquals(BUY.name(), bsqSwapOffer.getDirection()); - assertEquals(5_000, bsqSwapOffer.getPrice()); - assertEquals(1_000_000L, bsqSwapOffer.getAmount()); - assertEquals(1_000_000L, bsqSwapOffer.getMinAmount()); - // assertEquals(alicesBsqAcct.getId(), atomicOffer.getMakerPaymentAccountId()); - assertEquals(BSQ, bsqSwapOffer.getBaseCurrencyCode()); - assertEquals(BTC, bsqSwapOffer.getCounterCurrencyCode()); + assertEquals(BUY.name(), mySwapOffer.getDirection()); + assertEquals(5_000, mySwapOffer.getPrice()); + assertEquals(1_000_000L, mySwapOffer.getAmount()); + assertEquals(1_000_000L, mySwapOffer.getMinAmount()); + assertEquals(BSQ, mySwapOffer.getBaseCurrencyCode()); + assertEquals(BTC, mySwapOffer.getCounterCurrencyCode()); + + genBtcBlocksThenWait(1, 2_500); + + mySwapOffer = aliceClient.getMyOffer(newOfferId); + log.debug("My fetched BsqSwap Sell BSQ (Buy BTC) OFFER:\n{}", toOfferTable.apply(mySwapOffer)); + assertNotEquals(0, mySwapOffer.getMakerFee()); } @Test @Order(3) public void testBobTakesBsqSwapOffer() { - var bsqSwapOffer = getAvailableBsqSwapOffer(); - var bsqSwapTradeInfo = bobClient.takeBsqSwapOffer(bsqSwapOffer.getId(), + var availableSwapOffer = getAvailableBsqSwapOffer(); + var swapTrade = bobClient.takeBsqSwapOffer(availableSwapOffer.getId(), bobsBsqSwapAcct.getId(), BISQ_FEE_CURRENCY_CODE); - log.debug("Trade at t1: {}", bsqSwapTradeInfo); - assertEquals(PREPARATION.name(), bsqSwapTradeInfo.getState()); + log.debug("BsqSwap Trade at PREPARATION: {}", swapTrade); + assertEquals(PREPARATION.name(), swapTrade.getState()); genBtcBlocksThenWait(1, 3_000); - bsqSwapTradeInfo = getBsqSwapTrade(bsqSwapTradeInfo.getTradeId()); - log.debug("Trade at t2: {}", bsqSwapTradeInfo); - assertEquals(COMPLETED.name(), bsqSwapTradeInfo.getState()); + swapTrade = getBsqSwapTrade(swapTrade.getTradeId()); + log.debug("BsqSwap Trade at COMPLETION: {}", swapTrade); + assertEquals(COMPLETED.name(), swapTrade.getState()); } @Test @Order(4) public void testGetBalancesAfterTrade() { - sleep(2_500); // Give wallet time to finish processing TX. + genBtcBlocksThenWait(1, 5_000); var alicesBalances = aliceClient.getBalances(); log.debug("Alice's After Trade Balance:\n{}", formatBalancesTbls(alicesBalances)); var bobsBalances = bobClient.getBalances(); log.debug("Bob's After Trade Balance:\n{}", formatBalancesTbls(bobsBalances)); } - private BsqSwapOfferInfo getAvailableBsqSwapOffer() { - List bsqSwapOffers = new ArrayList<>(); + private OfferInfo getAvailableBsqSwapOffer() { + List bsqSwapOffers = new ArrayList<>(); int numFetchAttempts = 0; while (bsqSwapOffers.size() == 0) { - bsqSwapOffers.addAll(bobClient.getBsqSwapOffers(BUY.name(), BSQ)); + bsqSwapOffers.addAll(bobClient.getBsqSwapOffers(BUY.name())); numFetchAttempts++; if (bsqSwapOffers.size() == 0) { log.warn("No available bsq swap offers found after {} fetch attempts.", numFetchAttempts); diff --git a/apitest/src/test/java/bisq/apitest/scenario/TradeTest.java b/apitest/src/test/java/bisq/apitest/scenario/TradeTest.java index 63612712514..c4e03ffa2f2 100644 --- a/apitest/src/test/java/bisq/apitest/scenario/TradeTest.java +++ b/apitest/src/test/java/bisq/apitest/scenario/TradeTest.java @@ -101,7 +101,9 @@ public void testTakeSellBSQOffer(final TestInfo testInfo) { @Order(6) public void testBsqSwapTradeTest(final TestInfo testInfo) { BsqSwapTradeTest test = new BsqSwapTradeTest(); + test.testGetBalancesBeforeTrade(); test.testAliceCreateBsqSwapBuyOffer(); test.testBobTakesBsqSwapOffer(); + test.testGetBalancesAfterTrade(); } } From 564303ac20f320fa22627bbb4b7d6d0a9b4ea0f3 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Fri, 12 Nov 2021 18:48:35 -0300 Subject: [PATCH 09/17] Normalize API gRPC bsq-swap related protos & wrappers This commit refactors the first cut of the BsqSwapTradeInfo and TradeInfo gRPC proto defs and wrappers. The change avoids duplication of fields between BsqSwapTradeInfo and TradeInfo, and adds a bsqSwapTradeInfo field to the old TradeInfo proto & wrapper. The immediate goal is moving towards getting the API's 'gettrade' method to work for both Bisq v1 trades and BSQ swap trades: the TradeInfo proto sent to the CLI should represent either a Bisq v1 trade or a BSQ swap trade. A mid-term term goal is to also make a new 'gettrades' method return a List to the CLI, where items in the List can be either v1 trades or bsq-swap trades. --- .../method/trade/AbstractTradeTest.java | 4 +- .../method/trade/BsqSwapTradeTest.java | 19 +- cli/src/main/java/bisq/cli/GrpcClient.java | 5 +- .../cli/request/TradesServiceRequest.java | 3 +- .../bisq/core/api/model/BsqSwapTradeInfo.java | 222 ++--------- .../bisq/core/api/model/ContractInfo.java | 1 + .../java/bisq/core/api/model/OfferInfo.java | 270 ++------------ .../java/bisq/core/api/model/TradeInfo.java | 350 ++++++------------ .../builder/BsqSwapTradeInfoBuilder.java | 107 ++++++ .../api/model/builder/OfferInfoBuilder.java | 223 +++++++++++ .../api/model/builder/TradeInfoV1Builder.java | 195 ++++++++++ .../bsq_swap/model/BsqSwapProtocolModel.java | 1 + .../bisq/daemon/grpc/GrpcTradesService.java | 11 +- proto/src/main/proto/grpc.proto | 51 +-- 14 files changed, 755 insertions(+), 707 deletions(-) create mode 100644 core/src/main/java/bisq/core/api/model/builder/BsqSwapTradeInfoBuilder.java create mode 100644 core/src/main/java/bisq/core/api/model/builder/OfferInfoBuilder.java create mode 100644 core/src/main/java/bisq/core/api/model/builder/TradeInfoV1Builder.java diff --git a/apitest/src/test/java/bisq/apitest/method/trade/AbstractTradeTest.java b/apitest/src/test/java/bisq/apitest/method/trade/AbstractTradeTest.java index ba59c1a98f5..53b9f176f84 100644 --- a/apitest/src/test/java/bisq/apitest/method/trade/AbstractTradeTest.java +++ b/apitest/src/test/java/bisq/apitest/method/trade/AbstractTradeTest.java @@ -37,7 +37,9 @@ public class AbstractTradeTest extends AbstractOfferTest { protected static String tradeId; protected final Supplier maxTradeStateAndPhaseChecks = () -> isLongRunningTest ? 10 : 2; - private final Function toUserName = (client) -> client.equals(aliceClient) ? "Alice" : "Bob"; + protected final Function toTradeDetailTable = (trade) -> + new TableBuilder(TRADE_DETAIL_TBL, trade).build().toString(); + protected final Function toUserName = (client) -> client.equals(aliceClient) ? "Alice" : "Bob"; @BeforeAll public static void initStaticFixtures() { diff --git a/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java b/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java index 654ed4a594a..efea480e7bd 100644 --- a/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java +++ b/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java @@ -17,8 +17,8 @@ package bisq.apitest.method.trade; -import bisq.proto.grpc.BsqSwapTradeInfo; import bisq.proto.grpc.OfferInfo; +import bisq.proto.grpc.TradeInfo; import java.util.ArrayList; import java.util.List; @@ -47,11 +47,12 @@ import bisq.apitest.method.offer.AbstractOfferTest; +import bisq.cli.GrpcClient; @Disabled @Slf4j @TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class BsqSwapTradeTest extends AbstractOfferTest { +public class BsqSwapTradeTest extends AbstractTradeTest { private static final String BISQ_FEE_CURRENCY_CODE = BSQ; @@ -106,16 +107,18 @@ public void testAliceCreateBsqSwapBuyOffer() { @Test @Order(3) public void testBobTakesBsqSwapOffer() { - var availableSwapOffer = getAvailableBsqSwapOffer(); + var availableSwapOffer = getAvailableBsqSwapOffer(bobClient); var swapTrade = bobClient.takeBsqSwapOffer(availableSwapOffer.getId(), bobsBsqSwapAcct.getId(), BISQ_FEE_CURRENCY_CODE); log.debug("BsqSwap Trade at PREPARATION: {}", swapTrade); + log.debug("BsqSwap Trade at PREPARATION:\n{}", toTradeDetailTable.apply(swapTrade)); assertEquals(PREPARATION.name(), swapTrade.getState()); genBtcBlocksThenWait(1, 3_000); - swapTrade = getBsqSwapTrade(swapTrade.getTradeId()); + swapTrade = getBsqSwapTrade(bobClient, swapTrade.getTradeId()); log.debug("BsqSwap Trade at COMPLETION: {}", swapTrade); + log.debug("BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(swapTrade)); assertEquals(COMPLETED.name(), swapTrade.getState()); } @@ -129,11 +132,11 @@ public void testGetBalancesAfterTrade() { log.debug("Bob's After Trade Balance:\n{}", formatBalancesTbls(bobsBalances)); } - private OfferInfo getAvailableBsqSwapOffer() { + private OfferInfo getAvailableBsqSwapOffer(GrpcClient client) { List bsqSwapOffers = new ArrayList<>(); int numFetchAttempts = 0; while (bsqSwapOffers.size() == 0) { - bsqSwapOffers.addAll(bobClient.getBsqSwapOffers(BUY.name())); + bsqSwapOffers.addAll(client.getBsqSwapOffers(BUY.name())); numFetchAttempts++; if (bsqSwapOffers.size() == 0) { log.warn("No available bsq swap offers found after {} fetch attempts.", numFetchAttempts); @@ -155,12 +158,12 @@ private OfferInfo getAvailableBsqSwapOffer() { return bsqSwapOffer; } - private BsqSwapTradeInfo getBsqSwapTrade(String tradeId) { + private TradeInfo getBsqSwapTrade(GrpcClient client, String tradeId) { int numFetchAttempts = 0; while (true) { try { numFetchAttempts++; - return bobClient.getBsqSwapTrade(tradeId); + return client.getBsqSwapTrade(tradeId); } catch (Exception ex) { log.warn(ex.getMessage()); if (numFetchAttempts > 9) { diff --git a/cli/src/main/java/bisq/cli/GrpcClient.java b/cli/src/main/java/bisq/cli/GrpcClient.java index fe27e1ea9c7..87a8aa01229 100644 --- a/cli/src/main/java/bisq/cli/GrpcClient.java +++ b/cli/src/main/java/bisq/cli/GrpcClient.java @@ -20,7 +20,6 @@ import bisq.proto.grpc.AddressBalanceInfo; import bisq.proto.grpc.BalancesInfo; import bisq.proto.grpc.BsqBalanceInfo; -import bisq.proto.grpc.BsqSwapTradeInfo; import bisq.proto.grpc.BtcBalanceInfo; import bisq.proto.grpc.GetMethodHelpRequest; import bisq.proto.grpc.GetOfferCategoryReply; @@ -362,7 +361,7 @@ public TakeOfferReply getTakeOfferReply(String offerId, String paymentAccountId, return tradesServiceRequest.getTakeOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode); } - public BsqSwapTradeInfo takeBsqSwapOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { + public TradeInfo takeBsqSwapOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { var reply = getTakeBsqSwapOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode); if (reply.hasBsqSwapTrade()) return reply.getBsqSwapTrade(); @@ -374,7 +373,7 @@ public TradeInfo takeOffer(String offerId, String paymentAccountId, String taker return tradesServiceRequest.takeOffer(offerId, paymentAccountId, takerFeeCurrencyCode); } - public BsqSwapTradeInfo getBsqSwapTrade(String tradeId) { + public TradeInfo getBsqSwapTrade(String tradeId) { return tradesServiceRequest.getBsqSwapTrade(tradeId); } diff --git a/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java b/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java index 9c18685ca7f..3395c0e220f 100644 --- a/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java +++ b/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java @@ -17,7 +17,6 @@ package bisq.cli.request; -import bisq.proto.grpc.BsqSwapTradeInfo; import bisq.proto.grpc.ConfirmPaymentReceivedRequest; import bisq.proto.grpc.ConfirmPaymentStartedRequest; import bisq.proto.grpc.GetTradeRequest; @@ -69,7 +68,7 @@ public TradeInfo takeOffer(String offerId, String paymentAccountId, String taker throw new IllegalStateException(reply.getFailureReason().getDescription()); } - public BsqSwapTradeInfo getBsqSwapTrade(String tradeId) { + public TradeInfo getBsqSwapTrade(String tradeId) { var request = GetTradeRequest.newBuilder() .setTradeId(tradeId) .build(); diff --git a/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java b/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java index ce1fa745ebb..1dbd3b10abf 100644 --- a/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java +++ b/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java @@ -17,94 +17,62 @@ package bisq.core.api.model; +import bisq.core.api.model.builder.BsqSwapTradeInfoBuilder; import bisq.core.trade.model.bsq_swap.BsqSwapTrade; import bisq.common.Payload; import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.ToString; - -import static bisq.core.api.model.OfferInfo.toMyOfferInfo; -import static bisq.core.api.model.OfferInfo.toOfferInfo; @EqualsAndHashCode -@ToString @Getter public class BsqSwapTradeInfo implements Payload { - private final OfferInfo bsqSwapOffer; - private final String tradeId; - private final String tempTradingPeerNodeAddress; - private final String peerNodeAddress; private final String txId; private final long bsqTradeAmount; private final long btcTradeAmount; - private final long tradePrice; private final long bsqMakerTradeFee; private final long bsqTakerTradeFee; private final long txFeePerVbyte; - private final long txFee; private final String makerBsqAddress; private final String makerBtcAddress; private final String takerBsqAddress; private final String takerBtcAddress; - private final long takeOfferDate; - private final String role; - private final String state; private final String errorMessage; - public BsqSwapTradeInfo(Builder builder) { - this.bsqSwapOffer = builder.bsqSwapOffer; - this.tradeId = builder.tradeId; - this.tempTradingPeerNodeAddress = builder.tempTradingPeerNodeAddress; - this.peerNodeAddress = builder.peerNodeAddress; - this.txId = builder.txId; - this.bsqTradeAmount = builder.bsqTradeAmount; - this.btcTradeAmount = builder.btcTradeAmount; - this.tradePrice = builder.tradePrice; - this.bsqMakerTradeFee = builder.bsqMakerTradeFee; - this.bsqTakerTradeFee = builder.bsqTakerTradeFee; - this.txFeePerVbyte = builder.txFeePerVbyte; - this.txFee = builder.txFee; - this.makerBsqAddress = builder.makerBsqAddress; - this.makerBtcAddress = builder.makerBtcAddress; - this.takerBsqAddress = builder.takerBsqAddress; - this.takerBtcAddress = builder.takerBtcAddress; - this.takeOfferDate = builder.takeOfferDate; - this.role = builder.role; - this.state = builder.state; - this.errorMessage = builder.errorMessage; + public BsqSwapTradeInfo(BsqSwapTradeInfoBuilder builder) { + this.txId = builder.getTxId(); + this.bsqTradeAmount = builder.getBsqTradeAmount(); + this.btcTradeAmount = builder.getBtcTradeAmount(); + this.bsqMakerTradeFee = builder.getBsqMakerTradeFee(); + this.bsqTakerTradeFee = builder.getBsqTakerTradeFee(); + this.txFeePerVbyte = builder.getTxFeePerVbyte(); + this.makerBsqAddress = builder.getMakerBsqAddress(); + this.makerBtcAddress = builder.getMakerBtcAddress(); + this.takerBsqAddress = builder.getTakerBsqAddress(); + this.takerBtcAddress = builder.getTakerBtcAddress(); + this.errorMessage = builder.getErrorMessage(); } - public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade, String role, boolean wasMyOffer) { + public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade, boolean wasMyOffer) { var protocolModel = trade.getBsqSwapProtocolModel(); var swapPeer = protocolModel.getTradePeer(); var makerBsqAddress = wasMyOffer ? protocolModel.getBsqAddress() : swapPeer.getBsqAddress(); var makerBtcAddress = wasMyOffer ? protocolModel.getBtcAddress() : swapPeer.getBtcAddress(); var takerBsqAddress = wasMyOffer ? swapPeer.getBsqAddress() : protocolModel.getBsqAddress(); var takerBtcAddress = wasMyOffer ? swapPeer.getBtcAddress() : protocolModel.getBtcAddress(); - var offerInfo = wasMyOffer ? toMyOfferInfo(trade.getOffer()) : toOfferInfo(trade.getOffer()); - return new Builder() - .withBsqSwapOffer(offerInfo) - .withTradeId(trade.getId()) - .withTempTradingPeerNodeAddress(trade.getBsqSwapProtocolModel().getTempTradingPeerNodeAddress().getFullAddress()) - .withPeerNodeAddress(trade.getTradingPeerNodeAddress().getFullAddress()) + return new BsqSwapTradeInfoBuilder() .withTxId(trade.getTxId()) .withBsqTradeAmount(trade.getBsqTradeAmount()) .withBtcTradeAmount(trade.getAmountAsLong()) - .withTradePrice(trade.getPrice().getValue()) .withBsqMakerTradeFee(trade.getMakerFeeAsLong()) .withBsqTakerTradeFee(trade.getTakerFeeAsLong()) .withTxFeePerVbyte(trade.getTxFeePerVbyte()) - .withTxFee(trade.getTxFee().value) .withMakerBsqAddress(makerBsqAddress) .withMakerBtcAddress(makerBtcAddress) .withTakerBsqAddress(takerBsqAddress) .withTakerBtcAddress(takerBtcAddress) - .withTakeOfferDate(trade.getTakeOfferDate()) - .withRole(role == null ? "" : role) - .withState(trade.getTradeState().name()) .withErrorMessage(trade.getErrorMessage()) .build(); } @@ -116,178 +84,50 @@ public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade, String rol @Override public bisq.proto.grpc.BsqSwapTradeInfo toProtoMessage() { return bisq.proto.grpc.BsqSwapTradeInfo.newBuilder() - .setOffer(bsqSwapOffer.toProtoMessage()) - .setTradeId(tradeId) - .setTempTradingPeerNodeAddress(tempTradingPeerNodeAddress != null ? tempTradingPeerNodeAddress : "") - .setPeerNodeAddress(peerNodeAddress != null ? peerNodeAddress : "") .setTxId(txId != null ? txId : "") .setBsqTradeAmount(bsqTradeAmount) .setBtcTradeAmount(btcTradeAmount) - .setTradePrice(tradePrice) .setBsqMakerTradeFee(bsqMakerTradeFee) .setBsqTakerTradeFee(bsqTakerTradeFee) .setTxFeePerVbyte(txFeePerVbyte) - .setTxFee(txFee) .setMakerBsqAddress(makerBsqAddress != null ? makerBsqAddress : "") .setTakerBsqAddress(takerBsqAddress != null ? takerBsqAddress : "") .setMakerBtcAddress(makerBtcAddress != null ? makerBtcAddress : "") .setTakerBtcAddress(takerBtcAddress != null ? takerBtcAddress : "") - .setTakeOfferDate(takeOfferDate) - .setRole(role) - .setState(state) .setErrorMessage(errorMessage != null ? errorMessage : "") .build(); } public static BsqSwapTradeInfo fromProto(bisq.proto.grpc.BsqSwapTradeInfo proto) { - return new Builder() - .withBsqSwapOffer(OfferInfo.fromProto(proto.getOffer())) - .withTradeId(proto.getTradeId()) - .withTempTradingPeerNodeAddress(proto.getTempTradingPeerNodeAddress()) - .withPeerNodeAddress(proto.getPeerNodeAddress()) + return new BsqSwapTradeInfoBuilder() .withTxId(proto.getTxId()) .withBsqTradeAmount(proto.getBsqTradeAmount()) .withBtcTradeAmount(proto.getBtcTradeAmount()) - .withTradePrice(proto.getTradePrice()) .withBsqMakerTradeFee(proto.getBsqMakerTradeFee()) .withBsqTakerTradeFee(proto.getBsqTakerTradeFee()) .withTxFeePerVbyte(proto.getTxFeePerVbyte()) - .withTxFee(proto.getTxFee()) .withMakerBsqAddress(proto.getMakerBsqAddress()) .withMakerBtcAddress(proto.getMakerBtcAddress()) .withTakerBsqAddress(proto.getTakerBsqAddress()) .withTakerBtcAddress(proto.getTakerBtcAddress()) - .withTakeOfferDate(proto.getTakeOfferDate()) - .withRole(proto.getRole()) - .withState(proto.getState()) .withErrorMessage(proto.getErrorMessage()) .build(); } - private static class Builder { - private OfferInfo bsqSwapOffer; - private String tradeId; - private String tempTradingPeerNodeAddress; - private String peerNodeAddress; - private String txId; - private long bsqTradeAmount; - private long btcTradeAmount; - private long tradePrice; - private long bsqMakerTradeFee; - private long bsqTakerTradeFee; - private long txFeePerVbyte; - private long txFee; - private String makerBsqAddress; - private String makerBtcAddress; - private String takerBsqAddress; - private String takerBtcAddress; - private long takeOfferDate; - private String role; - private String state; - private String errorMessage; - - public Builder withBsqSwapOffer(OfferInfo bsqSwapOffer) { - this.bsqSwapOffer = bsqSwapOffer; - return this; - } - - public Builder withTradeId(String tradeId) { - this.tradeId = tradeId; - return this; - } - - public Builder withTempTradingPeerNodeAddress(String tempTradingPeerNodeAddress) { - this.tempTradingPeerNodeAddress = tempTradingPeerNodeAddress; - return this; - } - - public Builder withPeerNodeAddress(String peerNodeAddress) { - this.peerNodeAddress = peerNodeAddress; - return this; - } - - public Builder withTxId(String txId) { - this.txId = txId; - return this; - } - - public Builder withBsqTradeAmount(long bsqTradeAmount) { - this.bsqTradeAmount = bsqTradeAmount; - return this; - } - - public Builder withBtcTradeAmount(long btcTradeAmount) { - this.btcTradeAmount = btcTradeAmount; - return this; - } - - public Builder withTradePrice(long tradePrice) { - this.tradePrice = tradePrice; - return this; - } - - public Builder withBsqMakerTradeFee(long bsqMakerTradeFee) { - this.bsqMakerTradeFee = bsqMakerTradeFee; - return this; - } - - public Builder withBsqTakerTradeFee(long bsqTakerTradeFee) { - this.bsqTakerTradeFee = bsqTakerTradeFee; - return this; - } - - public Builder withTxFeePerVbyte(long txFeePerVbyte) { - this.txFeePerVbyte = txFeePerVbyte; - return this; - } - - public Builder withTxFee(long txFee) { - this.txFee = txFee; - return this; - } - - public Builder withMakerBsqAddress(String makerBsqAddress) { - this.makerBsqAddress = makerBsqAddress; - return this; - } - - public Builder withMakerBtcAddress(String makerBtcAddress) { - this.makerBtcAddress = makerBtcAddress; - return this; - } - - public Builder withTakerBsqAddress(String takerBsqAddress) { - this.takerBsqAddress = takerBsqAddress; - return this; - } - - public Builder withTakerBtcAddress(String takerBtcAddress) { - this.takerBtcAddress = takerBtcAddress; - return this; - } - - public Builder withTakeOfferDate(long takeOfferDate) { - this.takeOfferDate = takeOfferDate; - return this; - } - - public Builder withRole(String role) { - this.role = role; - return this; - } - - public Builder withState(String state) { - this.state = state; - return this; - } - - public Builder withErrorMessage(String errorMessage) { - this.errorMessage = errorMessage; - return this; - } - - public BsqSwapTradeInfo build() { - return new BsqSwapTradeInfo(this); - } + @Override + public String toString() { + return "BsqSwapTradeInfo{" + + ", txId='" + txId + '\'' + + ", bsqTradeAmount=" + bsqTradeAmount + + ", btcTradeAmount=" + btcTradeAmount + + ", bsqMakerTradeFee=" + bsqMakerTradeFee + + ", bsqTakerTradeFee=" + bsqTakerTradeFee + + ", txFeePerVbyte=" + txFeePerVbyte + + ", makerBsqAddress='" + makerBsqAddress + '\'' + + ", makerBtcAddress='" + makerBtcAddress + '\'' + + ", takerBsqAddress='" + takerBsqAddress + '\'' + + ", takerBtcAddress='" + takerBtcAddress + '\'' + + ", errorMessage='" + errorMessage + '\'' + + '}'; } } diff --git a/core/src/main/java/bisq/core/api/model/ContractInfo.java b/core/src/main/java/bisq/core/api/model/ContractInfo.java index 404335c9c7f..d4ce1e8ccb4 100644 --- a/core/src/main/java/bisq/core/api/model/ContractInfo.java +++ b/core/src/main/java/bisq/core/api/model/ContractInfo.java @@ -73,6 +73,7 @@ public ContractInfo(String buyerNodeAddress, // For transmitting TradeInfo messages when no contract is available. + // TODO Is this necessary as protobuf will send a DEFAULT_INSTANCE. public static Supplier emptyContract = () -> new ContractInfo("", "", diff --git a/core/src/main/java/bisq/core/api/model/OfferInfo.java b/core/src/main/java/bisq/core/api/model/OfferInfo.java index f84e69ad001..69d0455de08 100644 --- a/core/src/main/java/bisq/core/api/model/OfferInfo.java +++ b/core/src/main/java/bisq/core/api/model/OfferInfo.java @@ -17,6 +17,7 @@ package bisq.core.api.model; +import bisq.core.api.model.builder.OfferInfoBuilder; import bisq.core.offer.Offer; import bisq.core.offer.OpenOffer; import bisq.core.util.coin.CoinUtil; @@ -74,38 +75,38 @@ public class OfferInfo implements Payload { private final String versionNumber; private final int protocolVersion; - public OfferInfo(Builder builder) { - this.id = builder.id; - this.direction = builder.direction; - this.price = builder.price; - this.useMarketBasedPrice = builder.useMarketBasedPrice; - this.marketPriceMargin = builder.marketPriceMargin; - this.amount = builder.amount; - this.minAmount = builder.minAmount; - this.volume = builder.volume; - this.minVolume = builder.minVolume; - this.txFee = builder.txFee; - this.makerFee = builder.makerFee; - this.offerFeePaymentTxId = builder.offerFeePaymentTxId; - this.buyerSecurityDeposit = builder.buyerSecurityDeposit; - this.sellerSecurityDeposit = builder.sellerSecurityDeposit; - this.triggerPrice = builder.triggerPrice; - this.isCurrencyForMakerFeeBtc = builder.isCurrencyForMakerFeeBtc; - this.paymentAccountId = builder.paymentAccountId; - this.paymentMethodId = builder.paymentMethodId; - this.paymentMethodShortName = builder.paymentMethodShortName; - this.baseCurrencyCode = builder.baseCurrencyCode; - this.counterCurrencyCode = builder.counterCurrencyCode; - this.date = builder.date; - this.state = builder.state; - this.isActivated = builder.isActivated; - this.isMyOffer = builder.isMyOffer; - this.isMyPendingOffer = builder.isMyPendingOffer; - this.isBsqSwapOffer = builder.isBsqSwapOffer; - this.ownerNodeAddress = builder.ownerNodeAddress; - this.pubKeyRing = builder.pubKeyRing; - this.versionNumber = builder.versionNumber; - this.protocolVersion = builder.protocolVersion; + public OfferInfo(OfferInfoBuilder builder) { + this.id = builder.getId(); + this.direction = builder.getDirection(); + this.price = builder.getPrice(); + this.useMarketBasedPrice = builder.isUseMarketBasedPrice(); + this.marketPriceMargin = builder.getMarketPriceMargin(); + this.amount = builder.getAmount(); + this.minAmount = builder.getMinAmount(); + this.volume = builder.getVolume(); + this.minVolume = builder.getMinVolume(); + this.txFee = builder.getTxFee(); + this.makerFee = builder.getMakerFee(); + this.offerFeePaymentTxId = builder.getOfferFeePaymentTxId(); + this.buyerSecurityDeposit = builder.getBuyerSecurityDeposit(); + this.sellerSecurityDeposit = builder.getSellerSecurityDeposit(); + this.triggerPrice = builder.getTriggerPrice(); + this.isCurrencyForMakerFeeBtc = builder.isCurrencyForMakerFeeBtc(); + this.paymentAccountId = builder.getPaymentAccountId(); + this.paymentMethodId = builder.getPaymentMethodId(); + this.paymentMethodShortName = builder.getPaymentMethodShortName(); + this.baseCurrencyCode = builder.getBaseCurrencyCode(); + this.counterCurrencyCode = builder.getCounterCurrencyCode(); + this.date = builder.getDate(); + this.state = builder.getState(); + this.isActivated = builder.isActivated(); + this.isMyOffer = builder.isMyOffer(); + this.isMyPendingOffer = builder.isMyPendingOffer(); + this.isBsqSwapOffer = builder.isBsqSwapOffer(); + this.ownerNodeAddress = builder.getOwnerNodeAddress(); + this.pubKeyRing = builder.getPubKeyRing(); + this.versionNumber = builder.getVersionNumber(); + this.protocolVersion = builder.getProtocolVersion(); } public static OfferInfo toMyOfferInfo(Offer offer) { @@ -136,8 +137,8 @@ public static OfferInfo toMyOfferInfo(OpenOffer openOffer) { .build(); } - private static Builder getBuilder(Offer offer, boolean isMyOffer) { - return new Builder() + private static OfferInfoBuilder getBuilder(Offer offer, boolean isMyOffer) { + return new OfferInfoBuilder() .withId(offer.getId()) .withDirection(offer.getDirection().name()) .withPrice(Objects.requireNonNull(offer.getPrice()).getValue()) @@ -217,7 +218,7 @@ public bisq.proto.grpc.OfferInfo toProtoMessage() { @SuppressWarnings("unused") public static OfferInfo fromProto(bisq.proto.grpc.OfferInfo proto) { - return new Builder() + return new OfferInfoBuilder() .withId(proto.getId()) .withDirection(proto.getDirection()) .withPrice(proto.getPrice()) @@ -251,203 +252,4 @@ public static OfferInfo fromProto(bisq.proto.grpc.OfferInfo proto) { .withProtocolVersion(proto.getProtocolVersion()) .build(); } - - /* - * Builder helps avoid bungling use of a large OfferInfo constructor - * argument list. If consecutive argument values of the same type are not - * ordered correctly, the compiler won't complain but the resulting bugs could - * be hard to find and fix. - */ - private static class Builder { - private String id; - private String direction; - private long price; - private boolean useMarketBasedPrice; - private double marketPriceMargin; - private long amount; - private long minAmount; - private long volume; - private long minVolume; - private long txFee; - private long makerFee; - private String offerFeePaymentTxId; - private long buyerSecurityDeposit; - private long sellerSecurityDeposit; - private long triggerPrice; - private boolean isCurrencyForMakerFeeBtc; - private String paymentAccountId; - private String paymentMethodId; - private String paymentMethodShortName; - private String baseCurrencyCode; - private String counterCurrencyCode; - private long date; - private String state; - private boolean isActivated; - private boolean isMyOffer; - private boolean isMyPendingOffer; - private boolean isBsqSwapOffer; - private String ownerNodeAddress; - private String pubKeyRing; - private String versionNumber; - private int protocolVersion; - - public Builder withId(String id) { - this.id = id; - return this; - } - - public Builder withDirection(String direction) { - this.direction = direction; - return this; - } - - public Builder withPrice(long price) { - this.price = price; - return this; - } - - public Builder withUseMarketBasedPrice(boolean useMarketBasedPrice) { - this.useMarketBasedPrice = useMarketBasedPrice; - return this; - } - - public Builder withMarketPriceMargin(double useMarketBasedPrice) { - this.marketPriceMargin = useMarketBasedPrice; - return this; - } - - public Builder withAmount(long amount) { - this.amount = amount; - return this; - } - - public Builder withMinAmount(long minAmount) { - this.minAmount = minAmount; - return this; - } - - public Builder withVolume(long volume) { - this.volume = volume; - return this; - } - - public Builder withMinVolume(long minVolume) { - this.minVolume = minVolume; - return this; - } - - public Builder withTxFee(long txFee) { - this.txFee = txFee; - return this; - } - - public Builder withMakerFee(long makerFee) { - this.makerFee = makerFee; - return this; - } - - public Builder withOfferFeePaymentTxId(String offerFeePaymentTxId) { - this.offerFeePaymentTxId = offerFeePaymentTxId; - return this; - } - - public Builder withBuyerSecurityDeposit(long buyerSecurityDeposit) { - this.buyerSecurityDeposit = buyerSecurityDeposit; - return this; - } - - public Builder withSellerSecurityDeposit(long sellerSecurityDeposit) { - this.sellerSecurityDeposit = sellerSecurityDeposit; - return this; - } - - public Builder withTriggerPrice(long triggerPrice) { - this.triggerPrice = triggerPrice; - return this; - } - - public Builder withIsCurrencyForMakerFeeBtc(boolean isCurrencyForMakerFeeBtc) { - this.isCurrencyForMakerFeeBtc = isCurrencyForMakerFeeBtc; - return this; - } - - public Builder withPaymentAccountId(String paymentAccountId) { - this.paymentAccountId = paymentAccountId; - return this; - } - - public Builder withPaymentMethodId(String paymentMethodId) { - this.paymentMethodId = paymentMethodId; - return this; - } - - public Builder withPaymentMethodShortName(String paymentMethodShortName) { - this.paymentMethodShortName = paymentMethodShortName; - return this; - } - - public Builder withBaseCurrencyCode(String baseCurrencyCode) { - this.baseCurrencyCode = baseCurrencyCode; - return this; - } - - public Builder withCounterCurrencyCode(String counterCurrencyCode) { - this.counterCurrencyCode = counterCurrencyCode; - return this; - } - - public Builder withDate(long date) { - this.date = date; - return this; - } - - public Builder withState(String state) { - this.state = state; - return this; - } - - public Builder withIsActivated(boolean isActivated) { - this.isActivated = isActivated; - return this; - } - - public Builder withIsMyOffer(boolean isMyOffer) { - this.isMyOffer = isMyOffer; - return this; - } - - public Builder withIsMyPendingOffer(boolean isMyPendingOffer) { - this.isMyPendingOffer = isMyPendingOffer; - return this; - } - - public Builder withIsBsqSwapOffer(boolean isBsqSwapOffer) { - this.isBsqSwapOffer = isBsqSwapOffer; - return this; - } - - public Builder withOwnerNodeAddress(String ownerNodeAddress) { - this.ownerNodeAddress = ownerNodeAddress; - return this; - } - - public Builder withPubKeyRing(String pubKeyRing) { - this.pubKeyRing = pubKeyRing; - return this; - } - - public Builder withVersionNumber(String versionNumber) { - this.versionNumber = versionNumber; - return this; - } - - public Builder withProtocolVersion(int protocolVersion) { - this.protocolVersion = protocolVersion; - return this; - } - - public OfferInfo build() { - return new OfferInfo(this); - } - } } diff --git a/core/src/main/java/bisq/core/api/model/TradeInfo.java b/core/src/main/java/bisq/core/api/model/TradeInfo.java index 3e2bc8b56ea..70b929839a4 100644 --- a/core/src/main/java/bisq/core/api/model/TradeInfo.java +++ b/core/src/main/java/bisq/core/api/model/TradeInfo.java @@ -17,19 +17,22 @@ package bisq.core.api.model; +import bisq.core.api.model.builder.TradeInfoV1Builder; +import bisq.core.trade.model.TradeModel; import bisq.core.trade.model.bisq_v1.Contract; import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.model.bsq_swap.BsqSwapTrade; import bisq.common.Payload; -import java.util.Objects; - import lombok.EqualsAndHashCode; import lombok.Getter; +import static bisq.core.api.model.BsqSwapTradeInfo.toBsqSwapTradeInfo; import static bisq.core.api.model.OfferInfo.toMyOfferInfo; import static bisq.core.api.model.OfferInfo.toOfferInfo; import static bisq.core.api.model.PaymentAccountPayloadInfo.toPaymentAccountPayloadInfo; +import static java.util.Objects.requireNonNull; @EqualsAndHashCode @Getter @@ -39,6 +42,7 @@ public class TradeInfo implements Payload { // lighter weight TradeInfo proto wrapper instead, containing just enough fields to // view and interact with trades. + // Bisq v1 trade protocol fields (some are in common with the BSQ Swap protocol). private final OfferInfo offer; private final String tradeId; private final String shortId; @@ -65,41 +69,85 @@ public class TradeInfo implements Payload { private final boolean isWithdrawn; private final String contractAsJson; private final ContractInfo contract; + // Optional BSQ swap trade protocol details (post v1). + private BsqSwapTradeInfo bsqSwapTradeInfo; + + public TradeInfo(TradeInfoV1Builder builder) { + this.offer = builder.getOffer(); + this.tradeId = builder.getTradeId(); + this.shortId = builder.getShortId(); + this.date = builder.getDate(); + this.role = builder.getRole(); + this.isCurrencyForTakerFeeBtc = builder.isCurrencyForTakerFeeBtc(); + this.txFeeAsLong = builder.getTxFeeAsLong(); + this.takerFeeAsLong = builder.getTakerFeeAsLong(); + this.takerFeeTxId = builder.getTakerFeeTxId(); + this.depositTxId = builder.getDepositTxId(); + this.payoutTxId = builder.getPayoutTxId(); + this.tradeAmountAsLong = builder.getTradeAmountAsLong(); + this.tradePrice = builder.getTradePrice(); + this.tradeVolume = builder.getTradeVolume(); + this.tradingPeerNodeAddress = builder.getTradingPeerNodeAddress(); + this.state = builder.getState(); + this.phase = builder.getPhase(); + this.tradePeriodState = builder.getTradePeriodState(); + this.isDepositPublished = builder.isDepositPublished(); + this.isDepositConfirmed = builder.isDepositConfirmed(); + this.isFiatSent = builder.isFiatSent(); + this.isFiatReceived = builder.isFiatReceived(); + this.isPayoutPublished = builder.isPayoutPublished(); + this.isWithdrawn = builder.isWithdrawn(); + this.contractAsJson = builder.getContractAsJson(); + this.contract = builder.getContract(); + this.bsqSwapTradeInfo = null; + } - public TradeInfo(Builder builder) { - this.offer = builder.offer; - this.tradeId = builder.tradeId; - this.shortId = builder.shortId; - this.date = builder.date; - this.role = builder.role; - this.isCurrencyForTakerFeeBtc = builder.isCurrencyForTakerFeeBtc; - this.txFeeAsLong = builder.txFeeAsLong; - this.takerFeeAsLong = builder.takerFeeAsLong; - this.takerFeeTxId = builder.takerFeeTxId; - this.depositTxId = builder.depositTxId; - this.payoutTxId = builder.payoutTxId; - this.tradeAmountAsLong = builder.tradeAmountAsLong; - this.tradePrice = builder.tradePrice; - this.tradeVolume = builder.tradeVolume; - this.tradingPeerNodeAddress = builder.tradingPeerNodeAddress; - this.state = builder.state; - this.phase = builder.phase; - this.tradePeriodState = builder.tradePeriodState; - this.isDepositPublished = builder.isDepositPublished; - this.isDepositConfirmed = builder.isDepositConfirmed; - this.isFiatSent = builder.isFiatSent; - this.isFiatReceived = builder.isFiatReceived; - this.isPayoutPublished = builder.isPayoutPublished; - this.isWithdrawn = builder.isWithdrawn; - this.contractAsJson = builder.contractAsJson; - this.contract = builder.contract; + public static TradeInfo toNewTradeInfo(BsqSwapTrade trade, String role) { + // Always called by the taker, isMyOffer=false. + return toTradeInfo(trade, role, false); } public static TradeInfo toNewTradeInfo(Trade trade) { + // Always called by the taker, isMyOffer=false. return toTradeInfo(trade, null, false); } - public static TradeInfo toTradeInfo(Trade trade, String role, boolean isMyOffer) { + public static TradeInfo toTradeInfo(TradeModel tradeModel, String role, boolean isMyOffer) { + if (tradeModel instanceof Trade) + return toTradeInfo((Trade) tradeModel, role, isMyOffer); + else if (tradeModel instanceof BsqSwapTrade) + return toTradeInfo((BsqSwapTrade) tradeModel, role, isMyOffer); + else + throw new IllegalStateException("unsupported trade type: " + tradeModel.getClass().getSimpleName()); + } + + public static TradeInfo toTradeInfo(BsqSwapTrade bsqSwapTrade, String role, boolean isMyOffer) { + OfferInfo offerInfo = isMyOffer ? toMyOfferInfo(bsqSwapTrade.getOffer()) : toOfferInfo(bsqSwapTrade.getOffer()); + TradeInfo tradeInfo = new TradeInfoV1Builder() + .withOffer(offerInfo) + .withTradeId(bsqSwapTrade.getId()) + .withShortId(bsqSwapTrade.getShortId()) + .withDate(bsqSwapTrade.getDate().getTime()) + .withRole(role == null ? "" : role) + .withIsCurrencyForTakerFeeBtc(false) // BSQ Swap fees always paid in BSQ. + .withTxFeeAsLong(bsqSwapTrade.getTxFee().value) + .withTakerFeeAsLong(bsqSwapTrade.getTakerFeeAsLong()) + // N/A: .withTakerFeeTxId(""), .withDepositTxId(""), .withPayoutTxId("") + .withTradeAmountAsLong(bsqSwapTrade.getAmountAsLong()) + .withTradePrice(bsqSwapTrade.getPrice().getValue()) + .withTradeVolume(bsqSwapTrade.getVolume() == null ? 0 : bsqSwapTrade.getVolume().getValue()) + .withTradingPeerNodeAddress(requireNonNull(bsqSwapTrade.getTradingPeerNodeAddress().getFullAddress())) + .withState(bsqSwapTrade.getTradeState().name()) + .withPhase(bsqSwapTrade.getTradePhase().name()) + // N/A: .withTradePeriodState(""), .withIsDepositPublished(false), .withIsDepositConfirmed(false) + // N/A: .withIsFiatSent(false), .withIsFiatReceived(false), .withIsPayoutPublished(false) + // N/A: .withIsWithdrawn(false), .withContractAsJson(""), .withContract(null) + .build(); + tradeInfo.bsqSwapTradeInfo = toBsqSwapTradeInfo(bsqSwapTrade, isMyOffer); + return tradeInfo; + } + + private static TradeInfo toTradeInfo(Trade trade, String role, boolean isMyOffer) { ContractInfo contractInfo; if (trade.getContract() != null) { Contract contract = trade.getContract(); @@ -120,7 +168,7 @@ public static TradeInfo toTradeInfo(Trade trade, String role, boolean isMyOffer) } OfferInfo offerInfo = isMyOffer ? toMyOfferInfo(trade.getOffer()) : toOfferInfo(trade.getOffer()); - return new Builder() + return new TradeInfoV1Builder() .withOffer(offerInfo) .withTradeId(trade.getId()) .withShortId(trade.getShortId()) @@ -129,15 +177,13 @@ public static TradeInfo toTradeInfo(Trade trade, String role, boolean isMyOffer) .withIsCurrencyForTakerFeeBtc(trade.isCurrencyForTakerFeeBtc()) .withTxFeeAsLong(trade.getTradeTxFeeAsLong()) .withTakerFeeAsLong(trade.getTakerFeeAsLong()) - .withTakerFeeAsLong(trade.getTakerFeeAsLong()) .withTakerFeeTxId(trade.getTakerFeeTxId()) .withDepositTxId(trade.getDepositTxId()) .withPayoutTxId(trade.getPayoutTxId()) .withTradeAmountAsLong(trade.getAmountAsLong()) .withTradePrice(trade.getPrice().getValue()) .withTradeVolume(trade.getVolume() == null ? 0 : trade.getVolume().getValue()) - .withTradingPeerNodeAddress(Objects.requireNonNull( - trade.getTradingPeerNodeAddress()).getHostNameWithoutPostFix()) + .withTradingPeerNodeAddress(requireNonNull(trade.getTradingPeerNodeAddress().getFullAddress())) .withState(trade.getTradeState().name()) .withPhase(trade.getTradePhase().name()) .withTradePeriodState(trade.getTradePeriodState().name()) @@ -158,38 +204,45 @@ public static TradeInfo toTradeInfo(Trade trade, String role, boolean isMyOffer) @Override public bisq.proto.grpc.TradeInfo toProtoMessage() { - return bisq.proto.grpc.TradeInfo.newBuilder() - .setOffer(offer.toProtoMessage()) - .setTradeId(tradeId) - .setShortId(shortId) - .setDate(date) - .setRole(role) - .setIsCurrencyForTakerFeeBtc(isCurrencyForTakerFeeBtc) - .setTxFeeAsLong(txFeeAsLong) - .setTakerFeeAsLong(takerFeeAsLong) - .setTakerFeeTxId(takerFeeTxId == null ? "" : takerFeeTxId) - .setDepositTxId(depositTxId == null ? "" : depositTxId) - .setPayoutTxId(payoutTxId == null ? "" : payoutTxId) - .setTradeAmountAsLong(tradeAmountAsLong) - .setTradePrice(tradePrice) - .setTradeVolume(tradeVolume) - .setTradingPeerNodeAddress(tradingPeerNodeAddress) - .setState(state) - .setPhase(phase) - .setTradePeriodState(tradePeriodState) - .setIsDepositPublished(isDepositPublished) - .setIsDepositConfirmed(isDepositConfirmed) - .setIsFiatSent(isFiatSent) - .setIsFiatReceived(isFiatReceived) - .setIsPayoutPublished(isPayoutPublished) - .setIsWithdrawn(isWithdrawn) - .setContractAsJson(contractAsJson == null ? "" : contractAsJson) - .setContract(contract.toProtoMessage()) - .build(); + var protoBuilder = + bisq.proto.grpc.TradeInfo.newBuilder() + .setOffer(offer.toProtoMessage()) + .setTradeId(tradeId) + .setShortId(shortId) + .setDate(date) + .setRole(role) + .setIsCurrencyForTakerFeeBtc(isCurrencyForTakerFeeBtc) + .setTxFeeAsLong(txFeeAsLong) + .setTakerFeeAsLong(takerFeeAsLong) + .setTakerFeeTxId(takerFeeTxId == null ? "" : takerFeeTxId) + .setDepositTxId(depositTxId == null ? "" : depositTxId) + .setPayoutTxId(payoutTxId == null ? "" : payoutTxId) + .setTradeAmountAsLong(tradeAmountAsLong) + .setTradePrice(tradePrice) + .setTradeVolume(tradeVolume) + .setTradingPeerNodeAddress(tradingPeerNodeAddress) + .setState(state == null ? "" : state) + .setPhase(phase == null ? "" : phase) + .setTradePeriodState(tradePeriodState == null ? "" : tradePeriodState) + .setIsDepositPublished(isDepositPublished) + .setIsDepositConfirmed(isDepositConfirmed) + .setIsFiatSent(isFiatSent) + .setIsFiatReceived(isFiatReceived) + .setIsPayoutPublished(isPayoutPublished) + .setIsWithdrawn(isWithdrawn); + + if (offer.isBsqSwapOffer()) { + protoBuilder.setBsqSwapTradeInfo(bsqSwapTradeInfo.toProtoMessage()); + } else { + protoBuilder.setContractAsJson(contractAsJson == null ? "" : contractAsJson); + protoBuilder.setContract(contract.toProtoMessage()); + } + + return protoBuilder.build(); } public static TradeInfo fromProto(bisq.proto.grpc.TradeInfo proto) { - return new Builder() + var tradeInfo = new TradeInfoV1Builder() .withOffer(OfferInfo.fromProto(proto.getOffer())) .withTradeId(proto.getTradeId()) .withShortId(proto.getShortId()) @@ -217,175 +270,11 @@ public static TradeInfo fromProto(bisq.proto.grpc.TradeInfo proto) { .withContractAsJson(proto.getContractAsJson()) .withContract((ContractInfo.fromProto(proto.getContract()))) .build(); - } - - /* - * Builder helps avoid bungling use of a large TradeInfo constructor - * argument list. If consecutive argument values of the same type are not - * ordered correctly, the compiler won't complain but the resulting bugs could - * be hard to find and fix. - */ - private static class Builder { - private OfferInfo offer; - private String tradeId; - private String shortId; - private long date; - private String role; - private boolean isCurrencyForTakerFeeBtc; - private long txFeeAsLong; - private long takerFeeAsLong; - private String takerFeeTxId; - private String depositTxId; - private String payoutTxId; - private long tradeAmountAsLong; - private long tradePrice; - private long tradeVolume; - private String tradingPeerNodeAddress; - private String state; - private String phase; - private String tradePeriodState; - private boolean isDepositPublished; - private boolean isDepositConfirmed; - private boolean isFiatSent; - private boolean isFiatReceived; - private boolean isPayoutPublished; - private boolean isWithdrawn; - private String contractAsJson; - private ContractInfo contract; - - public Builder withOffer(OfferInfo offer) { - this.offer = offer; - return this; - } - - public Builder withTradeId(String tradeId) { - this.tradeId = tradeId; - return this; - } - - public Builder withShortId(String shortId) { - this.shortId = shortId; - return this; - } - - public Builder withDate(long date) { - this.date = date; - return this; - } - - public Builder withRole(String role) { - this.role = role; - return this; - } - - public Builder withIsCurrencyForTakerFeeBtc(boolean isCurrencyForTakerFeeBtc) { - this.isCurrencyForTakerFeeBtc = isCurrencyForTakerFeeBtc; - return this; - } - - public Builder withTxFeeAsLong(long txFeeAsLong) { - this.txFeeAsLong = txFeeAsLong; - return this; - } - - public Builder withTakerFeeAsLong(long takerFeeAsLong) { - this.takerFeeAsLong = takerFeeAsLong; - return this; - } - - public Builder withTakerFeeTxId(String takerFeeTxId) { - this.takerFeeTxId = takerFeeTxId; - return this; - } - public Builder withDepositTxId(String depositTxId) { - this.depositTxId = depositTxId; - return this; - } - - public Builder withPayoutTxId(String payoutTxId) { - this.payoutTxId = payoutTxId; - return this; - } - - public Builder withTradeAmountAsLong(long tradeAmountAsLong) { - this.tradeAmountAsLong = tradeAmountAsLong; - return this; - } - - public Builder withTradePrice(long tradePrice) { - this.tradePrice = tradePrice; - return this; - } - - public Builder withTradeVolume(long tradeVolume) { - this.tradeVolume = tradeVolume; - return this; - } - - public Builder withTradePeriodState(String tradePeriodState) { - this.tradePeriodState = tradePeriodState; - return this; - } - - public Builder withState(String state) { - this.state = state; - return this; - } - - public Builder withPhase(String phase) { - this.phase = phase; - return this; - } - - public Builder withTradingPeerNodeAddress(String tradingPeerNodeAddress) { - this.tradingPeerNodeAddress = tradingPeerNodeAddress; - return this; - } + if (proto.getOffer().getIsBsqSwapOffer()) + tradeInfo.bsqSwapTradeInfo = BsqSwapTradeInfo.fromProto(proto.getBsqSwapTradeInfo()); - public Builder withIsDepositPublished(boolean isDepositPublished) { - this.isDepositPublished = isDepositPublished; - return this; - } - - public Builder withIsDepositConfirmed(boolean isDepositConfirmed) { - this.isDepositConfirmed = isDepositConfirmed; - return this; - } - - public Builder withIsFiatSent(boolean isFiatSent) { - this.isFiatSent = isFiatSent; - return this; - } - - public Builder withIsFiatReceived(boolean isFiatReceived) { - this.isFiatReceived = isFiatReceived; - return this; - } - - public Builder withIsPayoutPublished(boolean isPayoutPublished) { - this.isPayoutPublished = isPayoutPublished; - return this; - } - - public Builder withIsWithdrawn(boolean isWithdrawn) { - this.isWithdrawn = isWithdrawn; - return this; - } - - public Builder withContractAsJson(String contractAsJson) { - this.contractAsJson = contractAsJson; - return this; - } - - public Builder withContract(ContractInfo contract) { - this.contract = contract; - return this; - } - - public TradeInfo build() { - return new TradeInfo(this); - } + return tradeInfo; } @Override @@ -417,6 +306,7 @@ public String toString() { ", offer=" + offer + "\n" + ", contractAsJson=" + contractAsJson + "\n" + ", contract=" + contract + "\n" + + ", bsqSwapTradeInfo=" + bsqSwapTradeInfo + "\n" + '}'; } } diff --git a/core/src/main/java/bisq/core/api/model/builder/BsqSwapTradeInfoBuilder.java b/core/src/main/java/bisq/core/api/model/builder/BsqSwapTradeInfoBuilder.java new file mode 100644 index 00000000000..dcbaaa4d401 --- /dev/null +++ b/core/src/main/java/bisq/core/api/model/builder/BsqSwapTradeInfoBuilder.java @@ -0,0 +1,107 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.api.model.builder; + +import bisq.core.api.model.BsqSwapTradeInfo; + +import lombok.Getter; + +/** + * Proto wrapper for BSQ swap protocol details not common to Bisq v1 + * trade protocol details. + * + * This builder helps avoid bungling use of a large BsqSwapTradeInfo constructor + * argument list. If consecutive argument values of the same type are not + * ordered correctly, the compiler won't complain but the resulting bugs could + * be hard to find and fix. + */ +@Getter +public final class BsqSwapTradeInfoBuilder { + + private String txId; + private long bsqTradeAmount; + private long btcTradeAmount; + private long bsqMakerTradeFee; + private long bsqTakerTradeFee; + private long txFeePerVbyte; + private String makerBsqAddress; + private String makerBtcAddress; + private String takerBsqAddress; + private String takerBtcAddress; + private String errorMessage; + + public BsqSwapTradeInfoBuilder withTxId(String txId) { + this.txId = txId; + return this; + } + + public BsqSwapTradeInfoBuilder withBsqTradeAmount(long bsqTradeAmount) { + this.bsqTradeAmount = bsqTradeAmount; + return this; + } + + public BsqSwapTradeInfoBuilder withBtcTradeAmount(long btcTradeAmount) { + this.btcTradeAmount = btcTradeAmount; + return this; + } + + public BsqSwapTradeInfoBuilder withBsqMakerTradeFee(long bsqMakerTradeFee) { + this.bsqMakerTradeFee = bsqMakerTradeFee; + return this; + } + + public BsqSwapTradeInfoBuilder withBsqTakerTradeFee(long bsqTakerTradeFee) { + this.bsqTakerTradeFee = bsqTakerTradeFee; + return this; + } + + public BsqSwapTradeInfoBuilder withTxFeePerVbyte(long txFeePerVbyte) { + this.txFeePerVbyte = txFeePerVbyte; + return this; + } + + public BsqSwapTradeInfoBuilder withMakerBsqAddress(String makerBsqAddress) { + this.makerBsqAddress = makerBsqAddress; + return this; + } + + public BsqSwapTradeInfoBuilder withMakerBtcAddress(String makerBtcAddress) { + this.makerBtcAddress = makerBtcAddress; + return this; + } + + public BsqSwapTradeInfoBuilder withTakerBsqAddress(String takerBsqAddress) { + this.takerBsqAddress = takerBsqAddress; + return this; + } + + public BsqSwapTradeInfoBuilder withTakerBtcAddress(String takerBtcAddress) { + this.takerBtcAddress = takerBtcAddress; + return this; + } + + public BsqSwapTradeInfoBuilder withErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + return this; + } + + public BsqSwapTradeInfo build() { + return new BsqSwapTradeInfo(this); + } +} + diff --git a/core/src/main/java/bisq/core/api/model/builder/OfferInfoBuilder.java b/core/src/main/java/bisq/core/api/model/builder/OfferInfoBuilder.java new file mode 100644 index 00000000000..3773b465f72 --- /dev/null +++ b/core/src/main/java/bisq/core/api/model/builder/OfferInfoBuilder.java @@ -0,0 +1,223 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.api.model.builder; + +import bisq.core.api.model.OfferInfo; + +import lombok.Getter; + +/* + * A builder helps avoid bungling use of a large OfferInfo constructor + * argument list. If consecutive argument values of the same type are not + * ordered correctly, the compiler won't complain but the resulting bugs could + * be hard to find and fix. + */ +@Getter +public final class OfferInfoBuilder { + + private String id; + private String direction; + private long price; + private boolean useMarketBasedPrice; + private double marketPriceMargin; + private long amount; + private long minAmount; + private long volume; + private long minVolume; + private long txFee; + private long makerFee; + private String offerFeePaymentTxId; + private long buyerSecurityDeposit; + private long sellerSecurityDeposit; + private long triggerPrice; + private boolean isCurrencyForMakerFeeBtc; + private String paymentAccountId; + private String paymentMethodId; + private String paymentMethodShortName; + private String baseCurrencyCode; + private String counterCurrencyCode; + private long date; + private String state; + private boolean isActivated; + private boolean isMyOffer; + private boolean isMyPendingOffer; + private boolean isBsqSwapOffer; + private String ownerNodeAddress; + private String pubKeyRing; + private String versionNumber; + private int protocolVersion; + + public OfferInfoBuilder withId(String id) { + this.id = id; + return this; + } + + public OfferInfoBuilder withDirection(String direction) { + this.direction = direction; + return this; + } + + public OfferInfoBuilder withPrice(long price) { + this.price = price; + return this; + } + + public OfferInfoBuilder withUseMarketBasedPrice(boolean useMarketBasedPrice) { + this.useMarketBasedPrice = useMarketBasedPrice; + return this; + } + + public OfferInfoBuilder withMarketPriceMargin(double useMarketBasedPrice) { + this.marketPriceMargin = useMarketBasedPrice; + return this; + } + + public OfferInfoBuilder withAmount(long amount) { + this.amount = amount; + return this; + } + + public OfferInfoBuilder withMinAmount(long minAmount) { + this.minAmount = minAmount; + return this; + } + + public OfferInfoBuilder withVolume(long volume) { + this.volume = volume; + return this; + } + + public OfferInfoBuilder withMinVolume(long minVolume) { + this.minVolume = minVolume; + return this; + } + + public OfferInfoBuilder withTxFee(long txFee) { + this.txFee = txFee; + return this; + } + + public OfferInfoBuilder withMakerFee(long makerFee) { + this.makerFee = makerFee; + return this; + } + + public OfferInfoBuilder withOfferFeePaymentTxId(String offerFeePaymentTxId) { + this.offerFeePaymentTxId = offerFeePaymentTxId; + return this; + } + + public OfferInfoBuilder withBuyerSecurityDeposit(long buyerSecurityDeposit) { + this.buyerSecurityDeposit = buyerSecurityDeposit; + return this; + } + + public OfferInfoBuilder withSellerSecurityDeposit(long sellerSecurityDeposit) { + this.sellerSecurityDeposit = sellerSecurityDeposit; + return this; + } + + public OfferInfoBuilder withTriggerPrice(long triggerPrice) { + this.triggerPrice = triggerPrice; + return this; + } + + public OfferInfoBuilder withIsCurrencyForMakerFeeBtc(boolean isCurrencyForMakerFeeBtc) { + this.isCurrencyForMakerFeeBtc = isCurrencyForMakerFeeBtc; + return this; + } + + public OfferInfoBuilder withPaymentAccountId(String paymentAccountId) { + this.paymentAccountId = paymentAccountId; + return this; + } + + public OfferInfoBuilder withPaymentMethodId(String paymentMethodId) { + this.paymentMethodId = paymentMethodId; + return this; + } + + public OfferInfoBuilder withPaymentMethodShortName(String paymentMethodShortName) { + this.paymentMethodShortName = paymentMethodShortName; + return this; + } + + public OfferInfoBuilder withBaseCurrencyCode(String baseCurrencyCode) { + this.baseCurrencyCode = baseCurrencyCode; + return this; + } + + public OfferInfoBuilder withCounterCurrencyCode(String counterCurrencyCode) { + this.counterCurrencyCode = counterCurrencyCode; + return this; + } + + public OfferInfoBuilder withDate(long date) { + this.date = date; + return this; + } + + public OfferInfoBuilder withState(String state) { + this.state = state; + return this; + } + + public OfferInfoBuilder withIsActivated(boolean isActivated) { + this.isActivated = isActivated; + return this; + } + + public OfferInfoBuilder withIsMyOffer(boolean isMyOffer) { + this.isMyOffer = isMyOffer; + return this; + } + + public OfferInfoBuilder withIsMyPendingOffer(boolean isMyPendingOffer) { + this.isMyPendingOffer = isMyPendingOffer; + return this; + } + + public OfferInfoBuilder withIsBsqSwapOffer(boolean isBsqSwapOffer) { + this.isBsqSwapOffer = isBsqSwapOffer; + return this; + } + + public OfferInfoBuilder withOwnerNodeAddress(String ownerNodeAddress) { + this.ownerNodeAddress = ownerNodeAddress; + return this; + } + + public OfferInfoBuilder withPubKeyRing(String pubKeyRing) { + this.pubKeyRing = pubKeyRing; + return this; + } + + public OfferInfoBuilder withVersionNumber(String versionNumber) { + this.versionNumber = versionNumber; + return this; + } + + public OfferInfoBuilder withProtocolVersion(int protocolVersion) { + this.protocolVersion = protocolVersion; + return this; + } + + public OfferInfo build() { + return new OfferInfo(this); + } +} diff --git a/core/src/main/java/bisq/core/api/model/builder/TradeInfoV1Builder.java b/core/src/main/java/bisq/core/api/model/builder/TradeInfoV1Builder.java new file mode 100644 index 00000000000..2bff2254a85 --- /dev/null +++ b/core/src/main/java/bisq/core/api/model/builder/TradeInfoV1Builder.java @@ -0,0 +1,195 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.core.api.model.builder; + +import bisq.core.api.model.ContractInfo; +import bisq.core.api.model.OfferInfo; +import bisq.core.api.model.TradeInfo; + +import lombok.Getter; + +/** + * A builder helps avoid bungling use of a large TradeInfo constructor + * argument list. If consecutive argument values of the same type are not + * ordered correctly, the compiler won't complain but the resulting bugs could + * be hard to find and fix. + */ +@Getter +public final class TradeInfoV1Builder { + + private OfferInfo offer; + private String tradeId; + private String shortId; + private long date; + private String role; + private boolean isCurrencyForTakerFeeBtc; + private long txFeeAsLong; + private long takerFeeAsLong; + private String takerFeeTxId; + private String depositTxId; + private String payoutTxId; + private long tradeAmountAsLong; + private long tradePrice; + private long tradeVolume; + private String tradingPeerNodeAddress; + private String state; + private String phase; + private String tradePeriodState; + private boolean isDepositPublished; + private boolean isDepositConfirmed; + private boolean isFiatSent; + private boolean isFiatReceived; + private boolean isPayoutPublished; + private boolean isWithdrawn; + private String contractAsJson; + private ContractInfo contract; + + public TradeInfoV1Builder withOffer(OfferInfo offer) { + this.offer = offer; + return this; + } + + public TradeInfoV1Builder withTradeId(String tradeId) { + this.tradeId = tradeId; + return this; + } + + public TradeInfoV1Builder withShortId(String shortId) { + this.shortId = shortId; + return this; + } + + public TradeInfoV1Builder withDate(long date) { + this.date = date; + return this; + } + + public TradeInfoV1Builder withRole(String role) { + this.role = role; + return this; + } + + public TradeInfoV1Builder withIsCurrencyForTakerFeeBtc(boolean isCurrencyForTakerFeeBtc) { + this.isCurrencyForTakerFeeBtc = isCurrencyForTakerFeeBtc; + return this; + } + + public TradeInfoV1Builder withTxFeeAsLong(long txFeeAsLong) { + this.txFeeAsLong = txFeeAsLong; + return this; + } + + public TradeInfoV1Builder withTakerFeeAsLong(long takerFeeAsLong) { + this.takerFeeAsLong = takerFeeAsLong; + return this; + } + + public TradeInfoV1Builder withTakerFeeTxId(String takerFeeTxId) { + this.takerFeeTxId = takerFeeTxId; + return this; + } + + public TradeInfoV1Builder withDepositTxId(String depositTxId) { + this.depositTxId = depositTxId; + return this; + } + + public TradeInfoV1Builder withPayoutTxId(String payoutTxId) { + this.payoutTxId = payoutTxId; + return this; + } + + public TradeInfoV1Builder withTradeAmountAsLong(long tradeAmountAsLong) { + this.tradeAmountAsLong = tradeAmountAsLong; + return this; + } + + public TradeInfoV1Builder withTradePrice(long tradePrice) { + this.tradePrice = tradePrice; + return this; + } + + public TradeInfoV1Builder withTradeVolume(long tradeVolume) { + this.tradeVolume = tradeVolume; + return this; + } + + public TradeInfoV1Builder withTradePeriodState(String tradePeriodState) { + this.tradePeriodState = tradePeriodState; + return this; + } + + public TradeInfoV1Builder withState(String state) { + this.state = state; + return this; + } + + public TradeInfoV1Builder withPhase(String phase) { + this.phase = phase; + return this; + } + + public TradeInfoV1Builder withTradingPeerNodeAddress(String tradingPeerNodeAddress) { + this.tradingPeerNodeAddress = tradingPeerNodeAddress; + return this; + } + + public TradeInfoV1Builder withIsDepositPublished(boolean isDepositPublished) { + this.isDepositPublished = isDepositPublished; + return this; + } + + public TradeInfoV1Builder withIsDepositConfirmed(boolean isDepositConfirmed) { + this.isDepositConfirmed = isDepositConfirmed; + return this; + } + + public TradeInfoV1Builder withIsFiatSent(boolean isFiatSent) { + this.isFiatSent = isFiatSent; + return this; + } + + public TradeInfoV1Builder withIsFiatReceived(boolean isFiatReceived) { + this.isFiatReceived = isFiatReceived; + return this; + } + + public TradeInfoV1Builder withIsPayoutPublished(boolean isPayoutPublished) { + this.isPayoutPublished = isPayoutPublished; + return this; + } + + public TradeInfoV1Builder withIsWithdrawn(boolean isWithdrawn) { + this.isWithdrawn = isWithdrawn; + return this; + } + + public TradeInfoV1Builder withContractAsJson(String contractAsJson) { + this.contractAsJson = contractAsJson; + return this; + } + + public TradeInfoV1Builder withContract(ContractInfo contract) { + this.contract = contract; + return this; + } + + public TradeInfo build() { + return new TradeInfo(this); + } +} diff --git a/core/src/main/java/bisq/core/trade/protocol/bsq_swap/model/BsqSwapProtocolModel.java b/core/src/main/java/bisq/core/trade/protocol/bsq_swap/model/BsqSwapProtocolModel.java index bdf5dd88b2c..47b09d10b45 100644 --- a/core/src/main/java/bisq/core/trade/protocol/bsq_swap/model/BsqSwapProtocolModel.java +++ b/core/src/main/java/bisq/core/trade/protocol/bsq_swap/model/BsqSwapProtocolModel.java @@ -69,6 +69,7 @@ public class BsqSwapProtocolModel implements ProtocolModel { transient private Offer offer; @Setter transient private TradeMessage tradeMessage; + // TODO rename tradingPeerNodeAddress ? @Nullable @Setter transient private NodeAddress tempTradingPeerNodeAddress; diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java index 00ec52305a9..641d9ab2eb0 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java @@ -18,7 +18,6 @@ package bisq.daemon.grpc; import bisq.core.api.CoreApi; -import bisq.core.api.model.BsqSwapTradeInfo; import bisq.core.api.model.TradeInfo; import bisq.core.trade.model.bisq_v1.Trade; @@ -48,7 +47,6 @@ import lombok.extern.slf4j.Slf4j; -import static bisq.core.api.model.BsqSwapTradeInfo.toBsqSwapTradeInfo; import static bisq.core.api.model.TradeInfo.toNewTradeInfo; import static bisq.core.api.model.TradeInfo.toTradeInfo; import static bisq.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; @@ -80,8 +78,9 @@ public void getBsqSwapTrade(GetTradeRequest req, var bsqSwapTrade = coreApi.getBsqSwapTrade(req.getTradeId()); boolean wasMyOffer = coreApi.isMyOffer(bsqSwapTrade.getOffer().getId()); String role = coreApi.getBsqSwapTradeRole(req.getTradeId()); + var tradeInfo = toTradeInfo(bsqSwapTrade, role, wasMyOffer); var reply = GetBsqSwapTradeReply.newBuilder() - .setBsqSwapTrade(toBsqSwapTradeInfo(bsqSwapTrade, role, wasMyOffer).toProtoMessage()) + .setBsqSwapTrade(tradeInfo.toProtoMessage()) .build(); responseObserver.onNext(reply); responseObserver.onCompleted(); @@ -107,11 +106,9 @@ public void takeBsqSwapOffer(TakeBsqSwapOfferRequest req, req.getTakerFeeCurrencyCode(), bsqSwapTrade -> { String role = coreApi.getBsqSwapTradeRole(bsqSwapTrade); - BsqSwapTradeInfo bsqSwapTradeInfo = toBsqSwapTradeInfo(bsqSwapTrade, - role, - false); + var tradeInfo = toNewTradeInfo(bsqSwapTrade, role); var reply = TakeBsqSwapOfferReply.newBuilder() - .setBsqSwapTrade(bsqSwapTradeInfo.toProtoMessage()) + .setBsqSwapTrade(tradeInfo.toProtoMessage()) .build(); responseObserver.onNext(reply); responseObserver.onCompleted(); diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index e050f951051..5a5d81c88fe 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -408,7 +408,7 @@ message TakeBsqSwapOfferRequest { } message TakeBsqSwapOfferReply { - BsqSwapTradeInfo bsqSwapTrade = 1; + TradeInfo bsqSwapTrade = 1; AvailabilityResultWithDescription failureReason = 2; } @@ -438,7 +438,7 @@ message ConfirmPaymentReceivedReply { } message GetBsqSwapTradeReply { - BsqSwapTradeInfo bsqSwapTrade = 1; + TradeInfo bsqSwapTrade = 1; } message GetTradeRequest { @@ -465,34 +465,8 @@ message WithdrawFundsRequest { message WithdrawFundsReply { } -message BsqSwapTradeInfo { - OfferInfo offer = 1; - string tradeId = 2; - string tempTradingPeerNodeAddress = 3; - string peerNodeAddress = 4; - string txId = 5; - uint64 bsqTradeAmount = 6; - uint64 btcTradeAmount = 7; - uint64 tradePrice = 8; - bool isCurrencyForMakerFeeBtc = 9; - bool isCurrencyForTakerFeeBtc = 10; - uint64 bsqMakerTradeFee = 11; - uint64 btcMakerTradeFee = 12; - uint64 bsqTakerTradeFee = 13; - uint64 btcTakerTradeFee = 14; - uint64 txFeePerVbyte = 15; - uint64 txFee = 16; - string makerBsqAddress = 17; - string makerBtcAddress = 18; - string takerBsqAddress = 19; - string takerBtcAddress = 20; - uint64 takeOfferDate = 21; - string role = 22; - string state = 23; - string errorMessage = 24; -} - message TradeInfo { + // Bisq v1 trade protocol fields. OfferInfo offer = 1; string tradeId = 2; string shortId = 3; @@ -519,8 +493,8 @@ message TradeInfo { string contractAsJson = 24; ContractInfo contract = 25; uint64 tradeVolume = 26; - // TODO See if a sub-message BsqSwapTradeInfo field could be added here. - // Use the existing BsqSwapTradeInfo message, without the redundant fields. + // Optional Bisq v2+ trade protocol fields. + BsqSwapTradeInfo bsqSwapTradeInfo = 28; } message ContractInfo { @@ -538,6 +512,21 @@ message ContractInfo { uint64 lockTime = 12; } +message BsqSwapTradeInfo { + // BSQ Swap protocol specific fields not common to Bisq v1 trade protocol fields. + string txId = 1; + uint64 bsqTradeAmount = 2; + uint64 btcTradeAmount = 3; + uint64 bsqMakerTradeFee = 4; + uint64 bsqTakerTradeFee = 5; + uint64 txFeePerVbyte = 6; + string makerBsqAddress = 7; + string makerBtcAddress = 8; + string takerBsqAddress = 9; + string takerBtcAddress = 10; + string errorMessage = 11; +} + message PaymentAccountPayloadInfo { string id = 1; string paymentMethodId = 2; From fc53ca48c1a22998655c37915087c81ab511ee32 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Sun, 14 Nov 2021 13:40:59 -0300 Subject: [PATCH 10/17] Add CLI output IntegerColumn --- .../bisq/cli/table/column/IntegerColumn.java | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 cli/src/main/java/bisq/cli/table/column/IntegerColumn.java diff --git a/cli/src/main/java/bisq/cli/table/column/IntegerColumn.java b/cli/src/main/java/bisq/cli/table/column/IntegerColumn.java new file mode 100644 index 00000000000..5c4e04af9d0 --- /dev/null +++ b/cli/src/main/java/bisq/cli/table/column/IntegerColumn.java @@ -0,0 +1,93 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see . + */ + +package bisq.cli.table.column; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.IntStream; + +import static bisq.cli.table.column.Column.JUSTIFICATION.RIGHT; + +/** + * For displaying Integer values. + */ +public class IntegerColumn extends NumberColumn { + + protected final List rows = new ArrayList<>(); + + protected final Predicate isNewMaxWidth = (s) -> s != null && !s.isEmpty() && s.length() > maxWidth; + + // The default IntegerColumn JUSTIFICATION is RIGHT. + public IntegerColumn(String name) { + this(name, RIGHT); + } + + public IntegerColumn(String name, JUSTIFICATION justification) { + super(name, justification); + this.maxWidth = name.length(); + } + + @Override + public void addRow(Integer value) { + rows.add(value); + + String s = String.valueOf(value); + if (isNewMaxWidth.test(s)) + maxWidth = s.length(); + } + + @Override + public List getRows() { + return rows; + } + + @Override + public int rowCount() { + return rows.size(); + } + + @Override + public boolean isEmpty() { + return rows.isEmpty(); + } + + @Override + public Integer getRow(int rowIndex) { + return rows.get(rowIndex); + } + + @Override + public void updateRow(int rowIndex, Integer newValue) { + rows.set(rowIndex, newValue); + } + + @Override + public String getRowAsFormattedString(int rowIndex) { + String s = String.valueOf(getRow(rowIndex)); + return toJustifiedString(s); + } + + @Override + public StringColumn asStringColumn() { + IntStream.range(0, rows.size()).forEachOrdered(rowIndex -> + stringColumn.addRow(getRowAsFormattedString(rowIndex))); + + return stringColumn; + } +} From 4ca878a8e1cf2a6c400a4d95a4c5a86faeaa4ba6 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Sun, 14 Nov 2021 13:48:12 -0300 Subject: [PATCH 11/17] Adjust API 'gettrade' for Bsq swaps - Made several adjustments to CLI's 'gettrade' output related code so it can show single trade details for either Bisq v1 trades, or BSQ swap trades. - Did minor refactoring of API's core to retrieve # tx confirmations for an addresses and transactions. - Show # of tx confirmations in bsq swap trade detail. --- .../method/trade/BsqSwapTradeTest.java | 24 +++- .../builder/AbstractTradeListBuilder.java | 40 +++++-- .../table/builder/TableBuilderConstants.java | 3 +- .../builder/TradeDetailTableBuilder.java | 112 ++++++++++++++---- .../builder/TradeTableColumnSupplier.java | 88 ++++++++++---- core/src/main/java/bisq/core/api/CoreApi.java | 4 + .../bisq/core/api/CoreWalletsService.java | 54 +++++---- .../bisq/core/api/model/BsqSwapTradeInfo.java | 12 +- .../java/bisq/core/api/model/OfferInfo.java | 8 +- .../java/bisq/core/api/model/TradeInfo.java | 11 +- .../builder/BsqSwapTradeInfoBuilder.java | 6 + .../bisq/daemon/grpc/GrpcTradesService.java | 6 +- proto/src/main/proto/grpc.proto | 3 +- 13 files changed, 275 insertions(+), 96 deletions(-) diff --git a/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java b/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java index efea480e7bd..674109f569f 100644 --- a/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java +++ b/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java @@ -111,21 +111,39 @@ public void testBobTakesBsqSwapOffer() { var swapTrade = bobClient.takeBsqSwapOffer(availableSwapOffer.getId(), bobsBsqSwapAcct.getId(), BISQ_FEE_CURRENCY_CODE); - log.debug("BsqSwap Trade at PREPARATION: {}", swapTrade); + tradeId = swapTrade.getTradeId(); // Cache the tradeId for following test case(s). log.debug("BsqSwap Trade at PREPARATION:\n{}", toTradeDetailTable.apply(swapTrade)); assertEquals(PREPARATION.name(), swapTrade.getState()); genBtcBlocksThenWait(1, 3_000); swapTrade = getBsqSwapTrade(bobClient, swapTrade.getTradeId()); - log.debug("BsqSwap Trade at COMPLETION: {}", swapTrade); log.debug("BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(swapTrade)); assertEquals(COMPLETED.name(), swapTrade.getState()); } @Test @Order(4) + public void testCompletedSwapTxConfirmations() { + sleep(2_000); // Wait for TX confirmation to happen on node. + + var alicesTrade = getBsqSwapTrade(aliceClient, tradeId); + log.debug("Alice's BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(alicesTrade)); + assertEquals(1, alicesTrade.getBsqSwapTradeInfo().getNumConfirmations()); + + var bobsTrade = getBsqSwapTrade(bobClient, tradeId); + log.debug("Bob's BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(bobsTrade)); + assertEquals(1, bobsTrade.getBsqSwapTradeInfo().getNumConfirmations()); + + genBtcBlocksThenWait(1, 2_000); + + bobsTrade = getBsqSwapTrade(bobClient, tradeId); + log.debug("Bob's BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(bobsTrade)); + assertEquals(2, bobsTrade.getBsqSwapTradeInfo().getNumConfirmations()); + } + + @Test + @Order(5) public void testGetBalancesAfterTrade() { - genBtcBlocksThenWait(1, 5_000); var alicesBalances = aliceClient.getBalances(); log.debug("Alice's After Trade Balance:\n{}", formatBalancesTbls(alicesBalances)); var bobsBalances = bobClient.getBalances(); diff --git a/cli/src/main/java/bisq/cli/table/builder/AbstractTradeListBuilder.java b/cli/src/main/java/bisq/cli/table/builder/AbstractTradeListBuilder.java index 23a265a45ce..5c7b109e574 100644 --- a/cli/src/main/java/bisq/cli/table/builder/AbstractTradeListBuilder.java +++ b/cli/src/main/java/bisq/cli/table/builder/AbstractTradeListBuilder.java @@ -102,6 +102,15 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder { @Nullable protected final Column colAltcoinReceiveAddressColumn; + // BSQ swap trade detail specific columns + + @Nullable + protected final Column status; + @Nullable + protected final Column colTxId; + @Nullable + protected final Column colNumConfirmations; + AbstractTradeListBuilder(TableType tableType, List protos) { super(tableType, protos); validate(); @@ -125,7 +134,9 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder { this.colRole = colSupplier.roleColumn.get(); this.colOfferType = colSupplier.offerTypeColumn.get(); this.colStatusDescription = colSupplier.statusDescriptionColumn.get(); - // Trade detail specific columns + + // Trade detail specific columns, some in common with BSQ swap trades detail. + this.colIsDepositPublished = colSupplier.depositPublishedColumn.get(); this.colIsDepositConfirmed = colSupplier.depositConfirmedColumn.get(); this.colIsPayoutPublished = colSupplier.payoutPublishedColumn.get(); @@ -135,6 +146,12 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder { this.colIsPaymentSent = colSupplier.paymentSentColumn.get(); this.colIsPaymentReceived = colSupplier.paymentReceivedColumn.get(); this.colAltcoinReceiveAddressColumn = colSupplier.altcoinReceiveAddressColumn.get(); + + // BSQ swap trade detail specific columns + + this.status = colSupplier.bsqSwapStatusColumn.get(); + this.colTxId = colSupplier.bsqSwapTxIdColumn.get(); + this.colNumConfirmations = colSupplier.numConfirmationsColumn.get(); } protected void validate() { @@ -149,9 +166,8 @@ protected void validate() { // Helper Functions private final Supplier isTradeDetailTblBuilder = () -> tableType.equals(TRADE_DETAIL_TBL); - protected final Predicate isFiatTrade = (t) -> isFiatOffer.test(t.getOffer()); - + protected final Predicate isBsqSwapTrade = (t) -> t.getOffer().getIsBsqSwapOffer(); protected final Predicate isTaker = (t) -> t.getRole().toLowerCase().contains("taker"); // Column Value Functions @@ -185,7 +201,6 @@ protected void validate() { } }; - // TODO Move to TradeUtil ? protected final Function toPriceDeviation = (t) -> t.getOffer().getUseMarketBasedPrice() ? formatToPercent(t.getOffer().getMarketPriceMargin()) @@ -196,8 +211,6 @@ protected void validate() { ? t.getTxFeeAsLong() : t.getOffer().getTxFee(); - - // TODO Move to TradeUtil ? protected final BiFunction toTradeFeeBsq = (t, isMyOffer) -> { if (isMyOffer) { return t.getOffer().getIsCurrencyForMakerFeeBtc() @@ -210,7 +223,6 @@ protected void validate() { } }; - // TODO Move to TradeUtil ? protected final BiFunction toTradeFeeBtc = (t, isMyOffer) -> { if (isMyOffer) { return t.getOffer().getIsCurrencyForMakerFeeBtc() @@ -223,12 +235,18 @@ protected void validate() { } }; - protected final Function toMyMakerOrTakerFee = (t) -> - isTaker.test(t) + protected final Function toMyMakerOrTakerFee = (t) -> { + if (isBsqSwapTrade.test(t)) { + return isTaker.test(t) + ? t.getBsqSwapTradeInfo().getBsqTakerTradeFee() + : t.getBsqSwapTradeInfo().getBsqMakerTradeFee(); + } else { + return isTaker.test(t) ? t.getTakerFeeAsLong() : t.getOffer().getMakerFee(); + } + }; - // TODO Move to TradeUtil ? SEE ClosedTradesViewModel # getDirectionLabel protected final Function toOfferType = (t) -> { if (isFiatTrade.test(t)) { return t.getOffer().getDirection() + " " + t.getOffer().getBaseCurrencyCode(); @@ -267,7 +285,7 @@ protected void validate() { } }; - // TODO Stuff to move into bisq/cli/CurrencyFormat.java ? + // TODO Move to bisq/cli/CurrencyFormat.java ? public static String formatToPercent(double value) { DecimalFormat decimalFormat = new DecimalFormat("#.##"); diff --git a/cli/src/main/java/bisq/cli/table/builder/TableBuilderConstants.java b/cli/src/main/java/bisq/cli/table/builder/TableBuilderConstants.java index 1ea28b63ecc..b29aa3e3ec9 100644 --- a/cli/src/main/java/bisq/cli/table/builder/TableBuilderConstants.java +++ b/cli/src/main/java/bisq/cli/table/builder/TableBuilderConstants.java @@ -35,6 +35,7 @@ class TableBuilderConstants { static final String COL_HEADER_LOCKUP_BONDS_BALANCE = "Lockup Bonds Balance"; static final String COL_HEADER_UNLOCKING_BONDS_BALANCE = "Unlocking Bonds Balance"; static final String COL_HEADER_UNVERIFIED_BALANCE = "Unverified Balance"; + static final String COL_HEADER_BSQ_SWAP_TRADE_ROLE = "My BSQ Swap Role"; static final String COL_HEADER_BUYER_DEPOSIT = "Buyer Deposit"; static final String COL_HEADER_SELLER_DEPOSIT = "Seller Deposit"; static final String COL_HEADER_CONFIRMATIONS = "Confirmations"; @@ -65,8 +66,6 @@ class TableBuilderConstants { static final String COL_HEADER_TRADE_ID = "Trade ID"; static final String COL_HEADER_TRADE_ROLE = "My Role"; static final String COL_HEADER_TRADE_SHORT_ID = "ID"; - @Deprecated - static final String COL_HEADER_TRADE_TX_FEE = "Tx Fee(BTC)"; static final String COL_HEADER_TRADE_MAKER_FEE = "Maker Fee(%-3s)"; static final String COL_HEADER_TRADE_TAKER_FEE = "Taker Fee(%-3s)"; static final String COL_HEADER_TRADE_FEE = "Trade Fee"; diff --git a/cli/src/main/java/bisq/cli/table/builder/TradeDetailTableBuilder.java b/cli/src/main/java/bisq/cli/table/builder/TradeDetailTableBuilder.java index 693a0c916a0..9d577ca1f6d 100644 --- a/cli/src/main/java/bisq/cli/table/builder/TradeDetailTableBuilder.java +++ b/cli/src/main/java/bisq/cli/table/builder/TradeDetailTableBuilder.java @@ -17,10 +17,16 @@ package bisq.cli.table.builder; +import bisq.proto.grpc.TradeInfo; + import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; import static bisq.cli.table.builder.TableType.TRADE_DETAIL_TBL; +import static java.lang.String.format; +import static protobuf.BsqSwapTrade.State.COMPLETED; +import static protobuf.BsqSwapTrade.State.PREPARATION; @@ -30,8 +36,12 @@ /** * Builds a {@code bisq.cli.table.Table} from a {@code bisq.proto.grpc.TradeInfo} object. */ +@SuppressWarnings("ConstantConditions") class TradeDetailTableBuilder extends AbstractTradeListBuilder { + private final Predicate isPendingBsqSwap = (t) -> t.getState().equals(PREPARATION.name()); + private final Predicate isCompletedBsqSwap = (t) -> t.getState().equals(COMPLETED.name()); + TradeDetailTableBuilder(List protos) { super(TRADE_DETAIL_TBL, protos); } @@ -41,33 +51,70 @@ class TradeDetailTableBuilder extends AbstractTradeListBuilder { * @return Table containing one row */ public Table build() { - populateColumns(); - List> columns = defineColumnList(); + // A trade detail table only has one row. + var trade = trades.get(0); + populateColumns(trade); + List> columns = defineColumnList(trade); return new Table(columns.toArray(new Column[0])); } - private void populateColumns() { - trades.stream().forEachOrdered(t -> { - colTradeId.addRow(t.getShortId()); - colRole.addRow(t.getRole()); - colPrice.addRow(t.getTradePrice()); - colAmountInBtc.addRow(toAmount.apply(t)); - colMinerTxFee.addRow(toMyMinerTxFee.apply(t)); - colBisqTradeFee.addRow(toMyMakerOrTakerFee.apply(t)); - colIsDepositPublished.addRow(t.getIsDepositPublished()); - colIsDepositConfirmed.addRow(t.getIsDepositConfirmed()); - colTradeCost.addRow(toTradeVolume.apply(t)); - colIsPaymentSent.addRow(t.getIsFiatSent()); - colIsPaymentReceived.addRow(t.getIsFiatReceived()); - colIsPayoutPublished.addRow(t.getIsPayoutPublished()); - colIsFundsWithdrawn.addRow(t.getIsWithdrawn()); - - if (colAltcoinReceiveAddressColumn != null) - colAltcoinReceiveAddressColumn.addRow(toAltcoinReceiveAddress.apply(t)); - }); + private void populateColumns(TradeInfo trade) { + if (isBsqSwapTrade.test(trade)) { + var isPending = isPendingBsqSwap.test(trade); + var isCompleted = isCompletedBsqSwap.test(trade); + if (isPending == isCompleted) + throw new IllegalStateException( + format("programmer error: trade must be either pending or completed, is pending=%s and completed=%s", + isPending, + isCompleted)); + populateBsqSwapTradeColumns(trade); + } else { + populateBisqV1TradeColumns(trade); + } } - private List> defineColumnList() { + private void populateBisqV1TradeColumns(TradeInfo trade) { + colTradeId.addRow(trade.getShortId()); + colRole.addRow(trade.getRole()); + colPrice.addRow(trade.getTradePrice()); + colAmountInBtc.addRow(toAmount.apply(trade)); + colMinerTxFee.addRow(toMyMinerTxFee.apply(trade)); + colBisqTradeFee.addRow(toMyMakerOrTakerFee.apply(trade)); + colIsDepositPublished.addRow(trade.getIsDepositPublished()); + colIsDepositConfirmed.addRow(trade.getIsDepositConfirmed()); + colTradeCost.addRow(toTradeVolume.apply(trade)); + colIsPaymentSent.addRow(trade.getIsFiatSent()); + colIsPaymentReceived.addRow(trade.getIsFiatReceived()); + colIsPayoutPublished.addRow(trade.getIsPayoutPublished()); + colIsFundsWithdrawn.addRow(trade.getIsWithdrawn()); + if (colAltcoinReceiveAddressColumn != null) + colAltcoinReceiveAddressColumn.addRow(toAltcoinReceiveAddress.apply(trade)); + } + + private void populateBsqSwapTradeColumns(TradeInfo trade) { + colTradeId.addRow(trade.getShortId()); + colRole.addRow(trade.getRole()); + colPrice.addRow(trade.getTradePrice()); + colAmountInBtc.addRow(toAmount.apply(trade)); + colMinerTxFee.addRow(toMyMinerTxFee.apply(trade)); + colBisqTradeFee.addRow(toMyMakerOrTakerFee.apply(trade)); + colTradeCost.addRow(toTradeVolume.apply(trade)); + + var isCompleted = isCompletedBsqSwap.test(trade); + status.addRow(isCompleted ? "COMPLETED" : "PENDING"); + if (isCompleted) { + colTxId.addRow(trade.getBsqSwapTradeInfo().getTxId()); + colNumConfirmations.addRow(trade.getBsqSwapTradeInfo().getNumConfirmations()); + } + } + + private List> defineColumnList(TradeInfo trade) { + return isBsqSwapTrade.test(trade) + ? getBsqSwapTradeColumnList(isCompletedBsqSwap.test(trade)) + : getBisqV1TradeColumnList(); + } + + private List> getBisqV1TradeColumnList() { List> columns = new ArrayList<>() {{ add(colTradeId); add(colRole); @@ -89,4 +136,25 @@ private List> defineColumnList() { return columns; } + + private List> getBsqSwapTradeColumnList(boolean isCompleted) { + List> columns = new ArrayList<>() {{ + add(colTradeId); + add(colRole); + add(colPrice.asStringColumn()); + add(colAmountInBtc.asStringColumn()); + add(colMinerTxFee.asStringColumn()); + add(colBisqTradeFee.asStringColumn()); + add(colTradeCost.asStringColumn()); + add(status); + }}; + + if (isCompleted) + columns.add(colTxId); + + if (!colNumConfirmations.isEmpty()) + columns.add(colNumConfirmations.asStringColumn()); + + return columns; + } } diff --git a/cli/src/main/java/bisq/cli/table/builder/TradeTableColumnSupplier.java b/cli/src/main/java/bisq/cli/table/builder/TradeTableColumnSupplier.java index 967ee1779f6..ae03cb14e87 100644 --- a/cli/src/main/java/bisq/cli/table/builder/TradeTableColumnSupplier.java +++ b/cli/src/main/java/bisq/cli/table/builder/TradeTableColumnSupplier.java @@ -40,6 +40,7 @@ import static bisq.cli.table.column.Column.JUSTIFICATION.LEFT; import static bisq.cli.table.column.Column.JUSTIFICATION.RIGHT; import static bisq.cli.table.column.FiatColumn.DISPLAY_MODE.VOLUME; +import static java.lang.String.format; @@ -49,6 +50,7 @@ import bisq.cli.table.column.Column; import bisq.cli.table.column.FiatColumn; import bisq.cli.table.column.Iso8601DateTimeColumn; +import bisq.cli.table.column.LongColumn; import bisq.cli.table.column.MixedPriceColumn; import bisq.cli.table.column.MixedTradeFeeColumn; import bisq.cli.table.column.MixedVolumeColumn; @@ -79,7 +81,10 @@ public TradeTableColumnSupplier(TableType tableType, List trades) { private final Supplier firstRow = () -> getTrades().get(0); private final Predicate isFiatOffer = (o) -> o.getBaseCurrencyCode().equals("BTC"); private final Predicate isFiatTrade = (t) -> isFiatOffer.test(t.getOffer()); + private final Predicate isBsqSwapTrade = (t) -> t.getOffer().getIsBsqSwapOffer(); private final Predicate isTaker = (t) -> t.getRole().toLowerCase().contains("taker"); + private final Supplier isSwapTradeDetail = () -> + isTradeDetailTblBuilder.get() && isBsqSwapTrade.test(firstRow.get()); final Supplier tradeIdColumn = () -> isTradeDetailTblBuilder.get() ? new StringColumn(COL_HEADER_TRADE_SHORT_ID) @@ -95,8 +100,8 @@ public TradeTableColumnSupplier(TableType tableType, List trades) { private final Function> toDetailedPriceColumn = (t) -> { String colHeader = isFiatTrade.test(t) - ? String.format(COL_HEADER_DETAILED_PRICE, t.getOffer().getCounterCurrencyCode()) - : String.format(COL_HEADER_DETAILED_PRICE_OF_ALTCOIN, t.getOffer().getBaseCurrencyCode()); + ? format(COL_HEADER_DETAILED_PRICE, t.getOffer().getCounterCurrencyCode()) + : format(COL_HEADER_DETAILED_PRICE_OF_ALTCOIN, t.getOffer().getBaseCurrencyCode()); return isFiatTrade.test(t) ? new FiatColumn(colHeader) : new AltcoinColumn(colHeader); @@ -116,7 +121,7 @@ public TradeTableColumnSupplier(TableType tableType, List trades) { private final Function> toDetailedAmountColumn = (t) -> { String headerCurrencyCode = t.getOffer().getBaseCurrencyCode(); - String colHeader = String.format(COL_HEADER_DETAILED_AMOUNT, headerCurrencyCode); + String colHeader = format(COL_HEADER_DETAILED_AMOUNT, headerCurrencyCode); return isFiatTrade.test(t) ? new SatoshiColumn(colHeader) : new AltcoinColumn(colHeader, ALTCOIN_OFFER_VOLUME); @@ -142,10 +147,14 @@ public TradeTableColumnSupplier(TableType tableType, List trades) { ? null : new StringColumn(COL_HEADER_PAYMENT_METHOD, LEFT); - final Supplier roleColumn = () -> - isTradeDetailTblBuilder.get() || isOpenTradeTblBuilder.get() || isFailedTradeTblBuilder.get() + final Supplier roleColumn = () -> { + if (isSwapTradeDetail.get()) + return new StringColumn(COL_HEADER_BSQ_SWAP_TRADE_ROLE); + else + return isTradeDetailTblBuilder.get() || isOpenTradeTblBuilder.get() || isFailedTradeTblBuilder.get() ? new StringColumn(COL_HEADER_TRADE_ROLE) : null; + }; final Function> toSecurityDepositColumn = (name) -> isClosedTradeTblBuilder.get() ? new SatoshiColumn(name) @@ -161,21 +170,42 @@ public TradeTableColumnSupplier(TableType tableType, List trades) { private final Function> toBooleanColumn = BooleanColumn::new; - final Supplier> depositPublishedColumn = () -> isTradeDetailTblBuilder.get() - ? toBooleanColumn.apply(COL_HEADER_TRADE_DEPOSIT_PUBLISHED) - : null; + final Supplier> depositPublishedColumn = () -> { + if (isSwapTradeDetail.get()) + return null; + else + return isTradeDetailTblBuilder.get() + ? toBooleanColumn.apply(COL_HEADER_TRADE_DEPOSIT_PUBLISHED) + : null; + }; - final Supplier> depositConfirmedColumn = () -> isTradeDetailTblBuilder.get() - ? toBooleanColumn.apply(COL_HEADER_TRADE_DEPOSIT_CONFIRMED) - : null; + final Supplier> depositConfirmedColumn = () -> { + if (isSwapTradeDetail.get()) + return null; + else + return isTradeDetailTblBuilder.get() + ? toBooleanColumn.apply(COL_HEADER_TRADE_DEPOSIT_CONFIRMED) + : null; - final Supplier> payoutPublishedColumn = () -> isTradeDetailTblBuilder.get() - ? toBooleanColumn.apply(COL_HEADER_TRADE_PAYOUT_PUBLISHED) - : null; + }; - final Supplier> fundsWithdrawnColumn = () -> isTradeDetailTblBuilder.get() - ? toBooleanColumn.apply(COL_HEADER_TRADE_WITHDRAWN) - : null; + final Supplier> payoutPublishedColumn = () -> { + if (isSwapTradeDetail.get()) + return null; + else + return isTradeDetailTblBuilder.get() + ? toBooleanColumn.apply(COL_HEADER_TRADE_PAYOUT_PUBLISHED) + : null; + }; + + final Supplier> fundsWithdrawnColumn = () -> { + if (isSwapTradeDetail.get()) + return null; + else + return isTradeDetailTblBuilder.get() + ? toBooleanColumn.apply(COL_HEADER_TRADE_WITHDRAWN) + : null; + }; final Supplier> bisqTradeDetailFeeColumn = () -> { if (isTradeDetailTblBuilder.get()) { @@ -184,8 +214,8 @@ public TradeTableColumnSupplier(TableType tableType, List trades) { ? t.getIsCurrencyForTakerFeeBtc() ? "BTC" : "BSQ" : t.getOffer().getIsCurrencyForMakerFeeBtc() ? "BTC" : "BSQ"; String colHeader = isTaker.test(t) - ? String.format(COL_HEADER_TRADE_TAKER_FEE, headerCurrencyCode) - : String.format(COL_HEADER_TRADE_MAKER_FEE, headerCurrencyCode); + ? format(COL_HEADER_TRADE_TAKER_FEE, headerCurrencyCode) + : format(COL_HEADER_TRADE_MAKER_FEE, headerCurrencyCode); boolean isBsqSatoshis = headerCurrencyCode.equals("BSQ"); return new SatoshiColumn(colHeader, isBsqSatoshis); } else { @@ -201,7 +231,7 @@ public TradeTableColumnSupplier(TableType tableType, List trades) { final Supplier> paymentSentColumn = () -> { if (isTradeDetailTblBuilder.get()) { String headerCurrencyCode = toPaymentCurrencyCode.apply(firstRow.get()); - String colHeader = String.format(COL_HEADER_TRADE_PAYMENT_SENT, headerCurrencyCode); + String colHeader = format(COL_HEADER_TRADE_PAYMENT_SENT, headerCurrencyCode); return new BooleanColumn(colHeader); } else { return null; @@ -211,7 +241,7 @@ public TradeTableColumnSupplier(TableType tableType, List trades) { final Supplier> paymentReceivedColumn = () -> { if (isTradeDetailTblBuilder.get()) { String headerCurrencyCode = toPaymentCurrencyCode.apply(firstRow.get()); - String colHeader = String.format(COL_HEADER_TRADE_PAYMENT_RECEIVED, headerCurrencyCode); + String colHeader = format(COL_HEADER_TRADE_PAYMENT_RECEIVED, headerCurrencyCode); return new BooleanColumn(colHeader); } else { return null; @@ -222,7 +252,7 @@ public TradeTableColumnSupplier(TableType tableType, List trades) { if (isTradeDetailTblBuilder.get()) { TradeInfo t = firstRow.get(); String headerCurrencyCode = t.getOffer().getCounterCurrencyCode(); - String colHeader = String.format(COL_HEADER_TRADE_BUYER_COST, headerCurrencyCode); + String colHeader = format(COL_HEADER_TRADE_BUYER_COST, headerCurrencyCode); return isFiatTrade.test(t) ? new FiatColumn(colHeader, VOLUME) : new SatoshiColumn(colHeader); @@ -231,6 +261,18 @@ public TradeTableColumnSupplier(TableType tableType, List trades) { } }; + final Supplier> bsqSwapTxIdColumn = () -> isSwapTradeDetail.get() + ? new StringColumn(COL_HEADER_TX_ID) + : null; + + final Supplier> bsqSwapStatusColumn = () -> isSwapTradeDetail.get() + ? new StringColumn(COL_HEADER_STATUS) + : null; + + final Supplier> numConfirmationsColumn = () -> isSwapTradeDetail.get() + ? new LongColumn(COL_HEADER_CONFIRMATIONS) + : null; + final Predicate showAltCoinBuyerAddress = (t) -> { if (isFiatTrade.test(t)) { return false; @@ -251,7 +293,7 @@ public TradeTableColumnSupplier(TableType tableType, List trades) { TradeInfo t = firstRow.get(); if (showAltCoinBuyerAddress.test(t)) { String headerCurrencyCode = toPaymentCurrencyCode.apply(t); - String colHeader = String.format(COL_HEADER_TRADE_ALTCOIN_BUYER_ADDRESS, headerCurrencyCode); + String colHeader = format(COL_HEADER_TRADE_ALTCOIN_BUYER_ADDRESS, headerCurrencyCode); return new StringColumn(colHeader); } else { return null; diff --git a/core/src/main/java/bisq/core/api/CoreApi.java b/core/src/main/java/bisq/core/api/CoreApi.java index 409299c3330..75e082d18c3 100644 --- a/core/src/main/java/bisq/core/api/CoreApi.java +++ b/core/src/main/java/bisq/core/api/CoreApi.java @@ -401,6 +401,10 @@ public Transaction getTransaction(String txId) { return walletsService.getTransaction(txId); } + public int getTransactionConfirmations(String txId) { + return walletsService.getTransactionConfirmations(txId); + } + public void setWalletPassword(String password, String newPassword) { walletsService.setWalletPassword(password, newPassword); } diff --git a/core/src/main/java/bisq/core/api/CoreWalletsService.java b/core/src/main/java/bisq/core/api/CoreWalletsService.java index f2dec09a530..6579786e147 100644 --- a/core/src/main/java/bisq/core/api/CoreWalletsService.java +++ b/core/src/main/java/bisq/core/api/CoreWalletsService.java @@ -85,6 +85,7 @@ import static bisq.core.btc.wallet.Restrictions.getMinNonDustOutput; import static bisq.core.util.ParsingUtils.parseToCoin; import static java.lang.String.format; +import static java.util.Objects.requireNonNull; import static java.util.concurrent.TimeUnit.SECONDS; @Singleton @@ -209,10 +210,10 @@ List getFundingAddresses() { } return addressStrings.stream().map(address -> - new AddressBalanceInfo(address, - balances.getUnchecked(address), - getNumConfirmationsForMostRecentTransaction(address), - btcWalletService.isAddressUnused(getAddressEntry(address).getAddress()))) + new AddressBalanceInfo(address, + balances.getUnchecked(address), + getNumConfirmationsForMostRecentTransaction(address), + btcWalletService.isAddressUnused(getAddressEntry(address).getAddress()))) .collect(Collectors.toList()); } @@ -324,7 +325,7 @@ boolean verifyBsqSentToAddress(String address, String amount) { for (TransactionOutput txOut : spendableBsqTxOutputs) { if (isTxOutputAddressMatch.test(txOut) && isTxOutputValueMatch.test(txOut)) { log.info("\t\tTx {} output has matching address {} and value {}.", - txOut.getParentTransaction().getTxId(), + requireNonNull(txOut.getParentTransaction()).getTxId(), address, txOut.getValue().toPlainString()); numMatches++; @@ -346,6 +347,7 @@ void getTxFeeRate(ResultHandler resultHandler) { @SuppressWarnings({"unchecked", "Convert2MethodRef"}) ListenableFuture future = (ListenableFuture) executor.submit(() -> feeService.requestFees()); + //noinspection NullableProblems Futures.addCallback(future, new FutureCallback<>() { @Override public void onSuccess(@Nullable Void ignored) { @@ -393,23 +395,11 @@ TxFeeRateInfo getMostRecentTxFeeRateInfo() { } Transaction getTransaction(String txId) { - if (txId.length() != 64) - throw new IllegalArgumentException(format("%s is not a transaction id", txId)); - - try { - Transaction tx = btcWalletService.getTransaction(txId); - if (tx == null) - throw new IllegalArgumentException(format("tx with id %s not found", txId)); - else - return tx; + return getTransactionWithId(txId); + } - } catch (IllegalArgumentException ex) { - log.error("", ex); - throw new IllegalArgumentException( - format("could not get transaction with id %s%ncause: %s", - txId, - ex.getMessage().toLowerCase())); - } + int getTransactionConfirmations(String txId) { + return getTransactionWithId(txId).getConfidence().getDepthInBlocks(); } int getNumConfirmationsForMostRecentTransaction(String addressString) { @@ -654,12 +644,32 @@ private AddressEntry getAddressEntry(String addressString) { return addressEntry.get(); } + private Transaction getTransactionWithId(String txId) { + if (txId.length() != 64) + throw new IllegalArgumentException(format("%s is not a transaction id", txId)); + + try { + Transaction tx = btcWalletService.getTransaction(txId); + if (tx == null) + throw new IllegalArgumentException(format("tx with id %s not found", txId)); + else + return tx; + + } catch (IllegalArgumentException ex) { + log.error("", ex); + throw new IllegalArgumentException( + format("could not get transaction with id %s%ncause: %s", + txId, + ex.getMessage().toLowerCase())); + } + } + /** * Memoization stores the results of expensive function calls and returns * the cached result when the same input occurs again. * * Resulting LoadingCache is used by calling `.get(input I)` or - * `.getUnchecked(input I)`, depending on whether or not `f` can return null. + * `.getUnchecked(input I)`, depending on whether `f` can return null. * That's because CacheLoader throws an exception on null output from `f`. */ private static LoadingCache memoize(Function f) { diff --git a/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java b/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java index 1dbd3b10abf..d46cf877a02 100644 --- a/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java +++ b/core/src/main/java/bisq/core/api/model/BsqSwapTradeInfo.java @@ -39,6 +39,7 @@ public class BsqSwapTradeInfo implements Payload { private final String makerBtcAddress; private final String takerBsqAddress; private final String takerBtcAddress; + private final long numConfirmations; private final String errorMessage; public BsqSwapTradeInfo(BsqSwapTradeInfoBuilder builder) { @@ -52,10 +53,13 @@ public BsqSwapTradeInfo(BsqSwapTradeInfoBuilder builder) { this.makerBtcAddress = builder.getMakerBtcAddress(); this.takerBsqAddress = builder.getTakerBsqAddress(); this.takerBtcAddress = builder.getTakerBtcAddress(); + this.numConfirmations = builder.getNumConfirmations(); this.errorMessage = builder.getErrorMessage(); } - public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade, boolean wasMyOffer) { + public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade, + boolean wasMyOffer, + int numConfirmations) { var protocolModel = trade.getBsqSwapProtocolModel(); var swapPeer = protocolModel.getTradePeer(); var makerBsqAddress = wasMyOffer ? protocolModel.getBsqAddress() : swapPeer.getBsqAddress(); @@ -73,6 +77,7 @@ public static BsqSwapTradeInfo toBsqSwapTradeInfo(BsqSwapTrade trade, boolean wa .withMakerBtcAddress(makerBtcAddress) .withTakerBsqAddress(takerBsqAddress) .withTakerBtcAddress(takerBtcAddress) + .withNumConfirmations(numConfirmations) .withErrorMessage(trade.getErrorMessage()) .build(); } @@ -94,7 +99,8 @@ public bisq.proto.grpc.BsqSwapTradeInfo toProtoMessage() { .setTakerBsqAddress(takerBsqAddress != null ? takerBsqAddress : "") .setMakerBtcAddress(makerBtcAddress != null ? makerBtcAddress : "") .setTakerBtcAddress(takerBtcAddress != null ? takerBtcAddress : "") - .setErrorMessage(errorMessage != null ? errorMessage : "") + .setTakerBtcAddress(takerBtcAddress != null ? takerBtcAddress : "") + .setNumConfirmations(numConfirmations) .build(); } @@ -110,6 +116,7 @@ public static BsqSwapTradeInfo fromProto(bisq.proto.grpc.BsqSwapTradeInfo proto) .withMakerBtcAddress(proto.getMakerBtcAddress()) .withTakerBsqAddress(proto.getTakerBsqAddress()) .withTakerBtcAddress(proto.getTakerBtcAddress()) + .withNumConfirmations(proto.getNumConfirmations()) .withErrorMessage(proto.getErrorMessage()) .build(); } @@ -127,6 +134,7 @@ public String toString() { ", makerBtcAddress='" + makerBtcAddress + '\'' + ", takerBsqAddress='" + takerBsqAddress + '\'' + ", takerBtcAddress='" + takerBtcAddress + '\'' + + ", numConfirmations='" + numConfirmations + '\'' + ", errorMessage='" + errorMessage + '\'' + '}'; } diff --git a/core/src/main/java/bisq/core/api/model/OfferInfo.java b/core/src/main/java/bisq/core/api/model/OfferInfo.java index 69d0455de08..6cf635cb3b2 100644 --- a/core/src/main/java/bisq/core/api/model/OfferInfo.java +++ b/core/src/main/java/bisq/core/api/model/OfferInfo.java @@ -24,8 +24,6 @@ import bisq.common.Payload; -import java.util.Objects; - import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; @@ -141,13 +139,13 @@ private static OfferInfoBuilder getBuilder(Offer offer, boolean isMyOffer) { return new OfferInfoBuilder() .withId(offer.getId()) .withDirection(offer.getDirection().name()) - .withPrice(Objects.requireNonNull(offer.getPrice()).getValue()) + .withPrice(requireNonNull(offer.getPrice()).getValue()) .withUseMarketBasedPrice(offer.isUseMarketBasedPrice()) .withMarketPriceMargin(offer.getMarketPriceMargin()) .withAmount(offer.getAmount().value) .withMinAmount(offer.getMinAmount().value) - .withVolume(Objects.requireNonNull(offer.getVolume()).getValue()) - .withMinVolume(Objects.requireNonNull(offer.getMinVolume()).getValue()) + .withVolume(requireNonNull(offer.getVolume()).getValue()) + .withMinVolume(requireNonNull(offer.getMinVolume()).getValue()) .withMakerFee(getMakerFee(offer, isMyOffer)) .withTxFee(offer.getTxFee().value) .withOfferFeePaymentTxId(offer.getOfferFeePaymentTxId()) diff --git a/core/src/main/java/bisq/core/api/model/TradeInfo.java b/core/src/main/java/bisq/core/api/model/TradeInfo.java index 70b929839a4..b8eb474e6ed 100644 --- a/core/src/main/java/bisq/core/api/model/TradeInfo.java +++ b/core/src/main/java/bisq/core/api/model/TradeInfo.java @@ -104,7 +104,7 @@ public TradeInfo(TradeInfoV1Builder builder) { public static TradeInfo toNewTradeInfo(BsqSwapTrade trade, String role) { // Always called by the taker, isMyOffer=false. - return toTradeInfo(trade, role, false); + return toTradeInfo(trade, role, false, 0); } public static TradeInfo toNewTradeInfo(Trade trade) { @@ -116,12 +116,15 @@ public static TradeInfo toTradeInfo(TradeModel tradeModel, String role, boolean if (tradeModel instanceof Trade) return toTradeInfo((Trade) tradeModel, role, isMyOffer); else if (tradeModel instanceof BsqSwapTrade) - return toTradeInfo((BsqSwapTrade) tradeModel, role, isMyOffer); + return toTradeInfo(tradeModel, role, isMyOffer); else throw new IllegalStateException("unsupported trade type: " + tradeModel.getClass().getSimpleName()); } - public static TradeInfo toTradeInfo(BsqSwapTrade bsqSwapTrade, String role, boolean isMyOffer) { + public static TradeInfo toTradeInfo(BsqSwapTrade bsqSwapTrade, + String role, + boolean isMyOffer, + int numConfirmations) { OfferInfo offerInfo = isMyOffer ? toMyOfferInfo(bsqSwapTrade.getOffer()) : toOfferInfo(bsqSwapTrade.getOffer()); TradeInfo tradeInfo = new TradeInfoV1Builder() .withOffer(offerInfo) @@ -143,7 +146,7 @@ public static TradeInfo toTradeInfo(BsqSwapTrade bsqSwapTrade, String role, bool // N/A: .withIsFiatSent(false), .withIsFiatReceived(false), .withIsPayoutPublished(false) // N/A: .withIsWithdrawn(false), .withContractAsJson(""), .withContract(null) .build(); - tradeInfo.bsqSwapTradeInfo = toBsqSwapTradeInfo(bsqSwapTrade, isMyOffer); + tradeInfo.bsqSwapTradeInfo = toBsqSwapTradeInfo(bsqSwapTrade, isMyOffer, numConfirmations); return tradeInfo; } diff --git a/core/src/main/java/bisq/core/api/model/builder/BsqSwapTradeInfoBuilder.java b/core/src/main/java/bisq/core/api/model/builder/BsqSwapTradeInfoBuilder.java index dcbaaa4d401..3ae01d4ea8c 100644 --- a/core/src/main/java/bisq/core/api/model/builder/BsqSwapTradeInfoBuilder.java +++ b/core/src/main/java/bisq/core/api/model/builder/BsqSwapTradeInfoBuilder.java @@ -43,6 +43,7 @@ public final class BsqSwapTradeInfoBuilder { private String makerBtcAddress; private String takerBsqAddress; private String takerBtcAddress; + private long numConfirmations; private String errorMessage; public BsqSwapTradeInfoBuilder withTxId(String txId) { @@ -95,6 +96,11 @@ public BsqSwapTradeInfoBuilder withTakerBtcAddress(String takerBtcAddress) { return this; } + public BsqSwapTradeInfoBuilder withNumConfirmations(long numConfirmations) { + this.numConfirmations = numConfirmations; + return this; + } + public BsqSwapTradeInfoBuilder withErrorMessage(String errorMessage) { this.errorMessage = errorMessage; return this; diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java index 641d9ab2eb0..d9619dc51c6 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java @@ -78,7 +78,11 @@ public void getBsqSwapTrade(GetTradeRequest req, var bsqSwapTrade = coreApi.getBsqSwapTrade(req.getTradeId()); boolean wasMyOffer = coreApi.isMyOffer(bsqSwapTrade.getOffer().getId()); String role = coreApi.getBsqSwapTradeRole(req.getTradeId()); - var tradeInfo = toTradeInfo(bsqSwapTrade, role, wasMyOffer); + var numConfirmations = coreApi.getTransactionConfirmations(bsqSwapTrade.getTxId()); + var tradeInfo = toTradeInfo(bsqSwapTrade, + role, + wasMyOffer, + numConfirmations); var reply = GetBsqSwapTradeReply.newBuilder() .setBsqSwapTrade(tradeInfo.toProtoMessage()) .build(); diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index 5a5d81c88fe..bf26b3428d2 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -524,7 +524,8 @@ message BsqSwapTradeInfo { string makerBtcAddress = 8; string takerBsqAddress = 9; string takerBtcAddress = 10; - string errorMessage = 11; + uint64 numConfirmations = 11; + string errorMessage = 12; } message PaymentAccountPayloadInfo { From d8f1e446eac1cb183ad81503d27d46808698331f Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Sun, 14 Nov 2021 14:30:41 -0300 Subject: [PATCH 12/17] Try to hide from pesky codacy --- cli/src/test/java/bisq/cli/GetOffersSmokeTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java b/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java index aa871c3e863..6bbec525125 100644 --- a/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java +++ b/cli/src/test/java/bisq/cli/GetOffersSmokeTest.java @@ -11,6 +11,7 @@ This can be run on mainnet. */ +@SuppressWarnings({"CommentedOutCode", "unused"}) public class GetOffersSmokeTest { public static void main(String[] args) { From 17277c4c67fa89de517c0fb840518d73f7b75d60 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Wed, 24 Nov 2021 12:52:58 -0300 Subject: [PATCH 13/17] Remove Get/Take BSQSwap Offer/Trade rpc service defs The old GetTrade and TakeOffer rpc service defs will be used for getting BSQ swap trades, and taking BSQ swap offers. --- proto/src/main/proto/grpc.proto | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index bf26b3428d2..d8c739bd369 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -383,12 +383,8 @@ message StopReply { /////////////////////////////////////////////////////////////////////////////////////////// service Trades { - rpc GetBsqSwapTrade (GetTradeRequest) returns (GetBsqSwapTradeReply) { - } rpc GetTrade (GetTradeRequest) returns (GetTradeReply) { } - rpc TakeBsqSwapOffer (TakeBsqSwapOfferRequest) returns (TakeBsqSwapOfferReply) { - } rpc TakeOffer (TakeOfferRequest) returns (TakeOfferReply) { } rpc ConfirmPaymentStarted (ConfirmPaymentStartedRequest) returns (ConfirmPaymentStartedReply) { @@ -401,17 +397,6 @@ service Trades { } } -message TakeBsqSwapOfferRequest { - string offerId = 1; - string paymentAccountId = 2; - string takerFeeCurrencyCode = 3; -} - -message TakeBsqSwapOfferReply { - TradeInfo bsqSwapTrade = 1; - AvailabilityResultWithDescription failureReason = 2; -} - message TakeOfferRequest { string offerId = 1; string paymentAccountId = 2; @@ -437,10 +422,6 @@ message ConfirmPaymentReceivedRequest { message ConfirmPaymentReceivedReply { } -message GetBsqSwapTradeReply { - TradeInfo bsqSwapTrade = 1; -} - message GetTradeRequest { string tradeId = 1; } From f88c1513ec3e2a7a1bba7a9aaa93f5dfafec3e3b Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Wed, 24 Nov 2021 13:00:30 -0300 Subject: [PATCH 14/17] Refactor GrpcTradesService: use GetTrade & TakeOffer services for BSQ swaps The rpc GetBsqSwapTrade and TakeBsqSwapOffer services were a quick hack to help test BSQ swap feature development more quickly, using apitest cases. Their gRPC service method implementations are removed here and the GetTrade & TakeOffer service methods are refactored to support BSQ swaps. --- .../bisq/daemon/grpc/GrpcTradesService.java | 162 +++++++++--------- 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java index d9619dc51c6..22961043b12 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcTradesService.java @@ -19,19 +19,18 @@ import bisq.core.api.CoreApi; import bisq.core.api.model.TradeInfo; +import bisq.core.trade.model.TradeModel; import bisq.core.trade.model.bisq_v1.Trade; +import bisq.core.trade.model.bsq_swap.BsqSwapTrade; import bisq.proto.grpc.ConfirmPaymentReceivedReply; import bisq.proto.grpc.ConfirmPaymentReceivedRequest; import bisq.proto.grpc.ConfirmPaymentStartedReply; import bisq.proto.grpc.ConfirmPaymentStartedRequest; -import bisq.proto.grpc.GetBsqSwapTradeReply; import bisq.proto.grpc.GetTradeReply; import bisq.proto.grpc.GetTradeRequest; import bisq.proto.grpc.KeepFundsReply; import bisq.proto.grpc.KeepFundsRequest; -import bisq.proto.grpc.TakeBsqSwapOfferReply; -import bisq.proto.grpc.TakeBsqSwapOfferRequest; import bisq.proto.grpc.TakeOfferReply; import bisq.proto.grpc.TakeOfferRequest; import bisq.proto.grpc.WithdrawFundsReply; @@ -72,67 +71,49 @@ public GrpcTradesService(CoreApi coreApi, GrpcExceptionHandler exceptionHandler) } @Override - public void getBsqSwapTrade(GetTradeRequest req, - StreamObserver responseObserver) { - try { - var bsqSwapTrade = coreApi.getBsqSwapTrade(req.getTradeId()); - boolean wasMyOffer = coreApi.isMyOffer(bsqSwapTrade.getOffer().getId()); - String role = coreApi.getBsqSwapTradeRole(req.getTradeId()); - var numConfirmations = coreApi.getTransactionConfirmations(bsqSwapTrade.getTxId()); - var tradeInfo = toTradeInfo(bsqSwapTrade, - role, - wasMyOffer, - numConfirmations); - var reply = GetBsqSwapTradeReply.newBuilder() - .setBsqSwapTrade(tradeInfo.toProtoMessage()) - .build(); - responseObserver.onNext(reply); - responseObserver.onCompleted(); - } catch (IllegalArgumentException cause) { - // Offer makers may call 'gettrade' many times before a trade exists. - // Log a 'trade not found' warning instead of a full stack trace. - exceptionHandler.handleExceptionAsWarning(log, "getBsqSwapTrade", cause, responseObserver); - } catch (Throwable cause) { - exceptionHandler.handleException(log, cause, responseObserver); - } - } - - @Override - public void takeBsqSwapOffer(TakeBsqSwapOfferRequest req, - StreamObserver responseObserver) { + public void takeOffer(TakeOfferRequest req, + StreamObserver responseObserver) { GrpcErrorMessageHandler errorMessageHandler = - new GrpcErrorMessageHandler(getTakeBsqSwapOfferMethod().getFullMethodName(), + new GrpcErrorMessageHandler(getTakeOfferMethod().getFullMethodName(), responseObserver, exceptionHandler, log); - coreApi.takeBsqSwapOffer(req.getOfferId(), - req.getPaymentAccountId(), - req.getTakerFeeCurrencyCode(), - bsqSwapTrade -> { - String role = coreApi.getBsqSwapTradeRole(bsqSwapTrade); - var tradeInfo = toNewTradeInfo(bsqSwapTrade, role); - var reply = TakeBsqSwapOfferReply.newBuilder() - .setBsqSwapTrade(tradeInfo.toProtoMessage()) - .build(); - responseObserver.onNext(reply); - responseObserver.onCompleted(); - }, - errorMessage -> { - if (!errorMessageHandler.isErrorHandled()) - errorMessageHandler.handleErrorMessage(errorMessage); - }); + + if (coreApi.isAvailableBsqSwapOffer(req.getOfferId())) { + coreApi.takeBsqSwapOffer(req.getOfferId(), + bsqSwapTrade -> { + var reply = buildTakeOfferReply(bsqSwapTrade); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + }, + errorMessage -> { + if (!errorMessageHandler.isErrorHandled()) + errorMessageHandler.handleErrorMessage(errorMessage); + }); + } else { + coreApi.takeOffer(req.getOfferId(), + req.getPaymentAccountId(), + req.getTakerFeeCurrencyCode(), + trade -> { + var reply = buildTakeOfferReply(trade); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + }, + errorMessage -> { + if (!errorMessageHandler.isErrorHandled()) + errorMessageHandler.handleErrorMessage(errorMessage); + }); + } } @Override public void getTrade(GetTradeRequest req, StreamObserver responseObserver) { try { - Trade trade = coreApi.getTrade(req.getTradeId()); - boolean wasMyOffer = coreApi.isMyOffer(trade.getOffer().getId()); - String role = coreApi.getTradeRole(req.getTradeId()); - var reply = GetTradeReply.newBuilder() - .setTrade(toTradeInfo(trade, role, wasMyOffer).toProtoMessage()) - .build(); + var tradeModel = coreApi.getTradeModel(req.getTradeId()); + var reply = tradeModel.getOffer().isBsqSwapOffer() + ? buildGetTradeReply((BsqSwapTrade) tradeModel) + : buildGetTradeReply((Trade) tradeModel); responseObserver.onNext(reply); responseObserver.onCompleted(); } catch (IllegalArgumentException cause) { @@ -144,31 +125,6 @@ public void getTrade(GetTradeRequest req, } } - @Override - public void takeOffer(TakeOfferRequest req, - StreamObserver responseObserver) { - GrpcErrorMessageHandler errorMessageHandler = - new GrpcErrorMessageHandler(getTakeOfferMethod().getFullMethodName(), - responseObserver, - exceptionHandler, - log); - coreApi.takeOffer(req.getOfferId(), - req.getPaymentAccountId(), - req.getTakerFeeCurrencyCode(), - trade -> { - TradeInfo tradeInfo = toNewTradeInfo(trade); - var reply = TakeOfferReply.newBuilder() - .setTrade(tradeInfo.toProtoMessage()) - .build(); - responseObserver.onNext(reply); - responseObserver.onCompleted(); - }, - errorMessage -> { - if (!errorMessageHandler.isErrorHandled()) - errorMessageHandler.handleErrorMessage(errorMessage); - }); - } - @Override public void confirmPaymentStarted(ConfirmPaymentStartedRequest req, StreamObserver responseObserver) { @@ -232,9 +188,8 @@ final Optional rateMeteringInterceptor() { .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( new HashMap<>() {{ put(getGetTradeMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS)); - put(getGetBsqSwapTradeMethod().getFullMethodName(), new GrpcCallRateMeter(1, SECONDS)); put(getTakeOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES)); - put(getTakeBsqSwapOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES)); + // put(getTakeBsqSwapOfferMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES)); put(getConfirmPaymentStartedMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES)); put(getConfirmPaymentReceivedMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES)); put(getKeepFundsMethod().getFullMethodName(), new GrpcCallRateMeter(1, MINUTES)); @@ -242,4 +197,49 @@ final Optional rateMeteringInterceptor() { }} ))); } + + private TakeOfferReply buildTakeOfferReply(TradeModel tradeModel) { + TradeInfo tradeInfo; + if (tradeModel.getOffer().isBsqSwapOffer()) { + BsqSwapTrade bsqSwapTrade = (BsqSwapTrade) tradeModel; + String role = getMyRole(bsqSwapTrade); + tradeInfo = toNewTradeInfo(bsqSwapTrade, role); + } else { + tradeInfo = toNewTradeInfo((Trade) tradeModel); + } + return TakeOfferReply.newBuilder() + .setTrade(tradeInfo.toProtoMessage()) + .build(); + } + + private GetTradeReply buildGetTradeReply(BsqSwapTrade bsqSwapTrade) { + boolean wasMyOffer = wasMyOffer(bsqSwapTrade); + String role = getMyRole(bsqSwapTrade); + var numConfirmations = coreApi.getTransactionConfirmations(bsqSwapTrade.getTxId()); + var tradeInfo = toTradeInfo(bsqSwapTrade, + role, + wasMyOffer, + numConfirmations); + return GetTradeReply.newBuilder() + .setTrade(tradeInfo.toProtoMessage()) + .build(); + } + + private GetTradeReply buildGetTradeReply(Trade trade) { + boolean wasMyOffer = wasMyOffer(trade); + String role = getMyRole(trade); + return GetTradeReply.newBuilder() + .setTrade(toTradeInfo(trade, role, wasMyOffer).toProtoMessage()) + .build(); + } + + private boolean wasMyOffer(TradeModel tradeModel) { + return coreApi.isMyOffer(tradeModel.getOffer().getId()); + } + + private String getMyRole(TradeModel tradeModel) { + return tradeModel.getOffer().isBsqSwapOffer() + ? coreApi.getBsqSwapTradeRole((BsqSwapTrade) tradeModel) + : coreApi.getTradeRole(tradeModel.getId()); + } } From 3aae05281306c7f1c4f588e50ac2ec49ef344482 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Wed, 24 Nov 2021 13:05:09 -0300 Subject: [PATCH 15/17] Refactor core.api trade service implemenentations for BSQ swaps A minor refactoring to support serving TradeModel instances to CLI. For example, the CLI 'gettrade' command must return a v1 Trade or BSQ swap trade. --- core/src/main/java/bisq/core/api/CoreApi.java | 17 +++----------- .../java/bisq/core/api/CoreTradesService.java | 23 +++++++++++-------- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/bisq/core/api/CoreApi.java b/core/src/main/java/bisq/core/api/CoreApi.java index 75e082d18c3..261993f08de 100644 --- a/core/src/main/java/bisq/core/api/CoreApi.java +++ b/core/src/main/java/bisq/core/api/CoreApi.java @@ -26,6 +26,7 @@ import bisq.core.payment.PaymentAccount; import bisq.core.payment.payload.PaymentMethod; import bisq.core.trade.bisq_v1.TradeResultHandler; +import bisq.core.trade.model.TradeModel; import bisq.core.trade.model.bisq_v1.Trade; import bisq.core.trade.model.bsq_swap.BsqSwapTrade; import bisq.core.trade.statistics.TradeStatistics3; @@ -276,14 +277,10 @@ public void getMarketPrice(String currencyCode, Consumer resultHandler) /////////////////////////////////////////////////////////////////////////////////////////// public void takeBsqSwapOffer(String offerId, - String paymentAccountId, - String takerFeeCurrencyCode, TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) { Offer bsqSwapOffer = coreOffersService.getBsqSwapOffer(offerId); coreTradesService.takeBsqSwapOffer(bsqSwapOffer, - paymentAccountId, - takerFeeCurrencyCode, tradeResultHandler, errorMessageHandler); } @@ -317,22 +314,14 @@ public void withdrawFunds(String tradeId, String address, String memo) { coreTradesService.withdrawFunds(tradeId, address, memo); } - public BsqSwapTrade getBsqSwapTrade(String tradeId) { - return coreTradesService.getBsqSwapTrade(tradeId); - } - - public Trade getTrade(String tradeId) { - return coreTradesService.getTrade(tradeId); + public TradeModel getTradeModel(String tradeId) { + return coreTradesService.getTradeModel(tradeId); } public String getTradeRole(String tradeId) { return coreTradesService.getTradeRole(tradeId); } - public String getBsqSwapTradeRole(String tradeId) { - return coreTradesService.getBsqSwapTradeRole(tradeId); - } - public String getBsqSwapTradeRole(BsqSwapTrade bsqSwapTrade) { return coreTradesService.getBsqSwapTradeRole(bsqSwapTrade); } diff --git a/core/src/main/java/bisq/core/api/CoreTradesService.java b/core/src/main/java/bisq/core/api/CoreTradesService.java index 6fdb23434db..3184ff31477 100644 --- a/core/src/main/java/bisq/core/api/CoreTradesService.java +++ b/core/src/main/java/bisq/core/api/CoreTradesService.java @@ -28,6 +28,7 @@ import bisq.core.trade.bisq_v1.TradeResultHandler; import bisq.core.trade.bisq_v1.TradeUtil; import bisq.core.trade.model.Tradable; +import bisq.core.trade.model.TradeModel; import bisq.core.trade.model.bisq_v1.Trade; import bisq.core.trade.model.bsq_swap.BsqSwapTrade; import bisq.core.trade.protocol.bisq_v1.BuyerProtocol; @@ -91,18 +92,14 @@ public CoreTradesService(CoreContext coreContext, this.user = user; } - // todo we need to pass the intended trade amount + // TODO We need to pass the intended trade amount, not default to the maximum. void takeBsqSwapOffer(Offer offer, - String paymentAccountId, - String takerFeeCurrencyCode, TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) { coreWalletsService.verifyWalletsAreAvailable(); coreWalletsService.verifyEncryptedWalletIsUnlocked(); bsqSwapTakeOfferModel.initWithData(offer); - - //todo use the intended trade amount bsqSwapTakeOfferModel.applyAmount(offer.getAmount()); log.info("Initiating take {} offer, {}", @@ -114,6 +111,7 @@ void takeBsqSwapOffer(Offer offer, coreContext.isApiUser()); } + // TODO We need to pass the intended trade amount, not default to the maximum. void takeOffer(Offer offer, String paymentAccountId, String takerFeeCurrencyCode, @@ -234,17 +232,22 @@ void withdrawFunds(String tradeId, String toAddress, String memo) { }); } - BsqSwapTrade getBsqSwapTrade(String tradeId) { + TradeModel getTradeModel(String tradeId) { coreWalletsService.verifyWalletsAreAvailable(); coreWalletsService.verifyEncryptedWalletIsUnlocked(); + + Optional openTrade = getOpenTrade(tradeId); + if (openTrade.isPresent()) + return openTrade.get(); + + Optional closedTrade = getClosedTrade(tradeId); + if (closedTrade.isPresent()) + return closedTrade.get(); + return tradeManager.findBsqSwapTradeById(tradeId).orElseThrow(() -> new IllegalArgumentException(format("trade with id '%s' not found", tradeId))); } - String getBsqSwapTradeRole(String tradeId) { - return getBsqSwapTradeRole(getBsqSwapTrade(tradeId)); - } - String getBsqSwapTradeRole(BsqSwapTrade bsqSwapTrade) { coreWalletsService.verifyWalletsAreAvailable(); coreWalletsService.verifyEncryptedWalletIsUnlocked(); From 0c5c343fe09f532c22d7e06f2e689574f47f8bee Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Wed, 24 Nov 2021 13:10:34 -0300 Subject: [PATCH 16/17] Adjust CLI to support getting/taking BSQ swaps Also refactored some of the opt parsers. --- cli/src/main/java/bisq/cli/CliMain.java | 32 +++++++++++++------ cli/src/main/java/bisq/cli/GrpcClient.java | 21 ++---------- .../cli/opts/CancelOfferOptionParser.java | 16 ++-------- .../cli/opts/CreateOfferOptionParser.java | 2 +- .../opts/CreatePaymentAcctOptionParser.java | 2 +- .../bisq/cli/opts/EditOfferOptionParser.java | 27 ++++++---------- .../opts/GetPaymentAcctFormOptionParser.java | 2 +- ...onParser.java => OfferIdOptionParser.java} | 12 ++++--- .../cli/opts/SetTxFeeRateOptionParser.java | 2 +- .../bisq/cli/opts/TakeOfferOptionParser.java | 17 ++-------- .../cli/request/TradesServiceRequest.java | 28 +++++----------- 11 files changed, 57 insertions(+), 104 deletions(-) rename cli/src/main/java/bisq/cli/opts/{GetOfferOptionParser.java => OfferIdOptionParser.java} (80%) diff --git a/cli/src/main/java/bisq/cli/CliMain.java b/cli/src/main/java/bisq/cli/CliMain.java index bc84aed69f4..eef8943723a 100644 --- a/cli/src/main/java/bisq/cli/CliMain.java +++ b/cli/src/main/java/bisq/cli/CliMain.java @@ -18,6 +18,7 @@ package bisq.cli; import bisq.proto.grpc.OfferInfo; +import bisq.proto.grpc.TradeInfo; import io.grpc.StatusRuntimeException; @@ -45,6 +46,7 @@ import static bisq.cli.Method.*; import static bisq.cli.opts.OptLabel.*; import static bisq.cli.table.builder.TableType.*; +import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory.BSQ_SWAP; import static java.lang.String.format; import static java.lang.System.err; import static java.lang.System.exit; @@ -62,11 +64,11 @@ import bisq.cli.opts.GetAddressBalanceOptionParser; import bisq.cli.opts.GetBTCMarketPriceOptionParser; import bisq.cli.opts.GetBalanceOptionParser; -import bisq.cli.opts.GetOfferOptionParser; import bisq.cli.opts.GetOffersOptionParser; import bisq.cli.opts.GetPaymentAcctFormOptionParser; import bisq.cli.opts.GetTradeOptionParser; import bisq.cli.opts.GetTransactionOptionParser; +import bisq.cli.opts.OfferIdOptionParser; import bisq.cli.opts.RegisterDisputeAgentOptionParser; import bisq.cli.opts.RemoveWalletPasswordOptionParser; import bisq.cli.opts.SendBsqOptionParser; @@ -392,7 +394,7 @@ public static void run(String[] args) { return; } case getoffer: { - var opts = new GetOfferOptionParser(args).parse(); + var opts = new OfferIdOptionParser(args).parse(); if (opts.isForHelp()) { out.println(client.getMethodHelp(method)); return; @@ -403,7 +405,7 @@ public static void run(String[] args) { return; } case getmyoffer: { - var opts = new GetOfferOptionParser(args).parse(); + var opts = new OfferIdOptionParser(args).parse(); if (opts.isForHelp()) { out.println(client.getMethodHelp(method)); return; @@ -446,15 +448,25 @@ public static void run(String[] args) { return; } case takeoffer: { - var opts = new TakeOfferOptionParser(args).parse(); - if (opts.isForHelp()) { + var offerIdOpt = new OfferIdOptionParser(args).parse(); + if (offerIdOpt.isForHelp()) { out.println(client.getMethodHelp(method)); return; } - var offerId = opts.getOfferId(); - var paymentAccountId = opts.getPaymentAccountId(); - var takerFeeCurrencyCode = opts.getTakerFeeCurrencyCode(); - var trade = client.takeOffer(offerId, paymentAccountId, takerFeeCurrencyCode); + var offerId = offerIdOpt.getOfferId(); + TradeInfo trade; + // We only send an 'offer-id' param when taking a BsqSwapOffer. + // Find out what kind of offer is being taken before sending a + // 'takeoffer' request. + var offerCategory = client.getAvailableOfferCategory(offerId); + if (offerCategory.equals(BSQ_SWAP)) { + trade = client.takeBsqSwapOffer(offerId); + } else { + var opts = new TakeOfferOptionParser(args).parse(); + var paymentAccountId = opts.getPaymentAccountId(); + var takerFeeCurrencyCode = opts.getTakerFeeCurrencyCode(); + trade = client.takeOffer(offerId, paymentAccountId, takerFeeCurrencyCode); + } out.printf("trade %s successfully taken%n", trade.getTradeId()); return; } @@ -825,7 +837,7 @@ private static void printHelp(OptionParser parser, @SuppressWarnings("SameParame stream.format(rowFormat, "", "--currency-code=", ""); stream.println(); stream.format(rowFormat, takeoffer.name(), "--offer-id= \\", "Take offer with id"); - stream.format(rowFormat, "", "--payment-account=", ""); + stream.format(rowFormat, "", "[--payment-account=]", ""); stream.format(rowFormat, "", "[--fee-currency=]", ""); stream.println(); stream.format(rowFormat, gettrade.name(), "--trade-id= \\", "Get trade summary or full contract"); diff --git a/cli/src/main/java/bisq/cli/GrpcClient.java b/cli/src/main/java/bisq/cli/GrpcClient.java index 87a8aa01229..a1e88898f5e 100644 --- a/cli/src/main/java/bisq/cli/GrpcClient.java +++ b/cli/src/main/java/bisq/cli/GrpcClient.java @@ -27,7 +27,6 @@ import bisq.proto.grpc.OfferInfo; import bisq.proto.grpc.RegisterDisputeAgentRequest; import bisq.proto.grpc.StopRequest; -import bisq.proto.grpc.TakeBsqSwapOfferReply; import bisq.proto.grpc.TakeOfferReply; import bisq.proto.grpc.TradeInfo; import bisq.proto.grpc.TxFeeRateInfo; @@ -349,34 +348,18 @@ public List sortOffersByDate(List offers) { return offersServiceRequest.sortOffersByDate(offers); } - public TakeBsqSwapOfferReply getTakeBsqSwapOfferReply(String offerId, - String paymentAccountId, - String takerFeeCurrencyCode) { - return tradesServiceRequest.getTakeBsqSwapOfferReply(offerId, - paymentAccountId, - takerFeeCurrencyCode); - } - public TakeOfferReply getTakeOfferReply(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { return tradesServiceRequest.getTakeOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode); } - public TradeInfo takeBsqSwapOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { - var reply = getTakeBsqSwapOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode); - if (reply.hasBsqSwapTrade()) - return reply.getBsqSwapTrade(); - else - throw new IllegalStateException(reply.getFailureReason().getDescription()); + public TradeInfo takeBsqSwapOffer(String offerId) { + return tradesServiceRequest.takeBsqSwapOffer(offerId); } public TradeInfo takeOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { return tradesServiceRequest.takeOffer(offerId, paymentAccountId, takerFeeCurrencyCode); } - public TradeInfo getBsqSwapTrade(String tradeId) { - return tradesServiceRequest.getBsqSwapTrade(tradeId); - } - public TradeInfo getTrade(String tradeId) { return tradesServiceRequest.getTrade(tradeId); } diff --git a/cli/src/main/java/bisq/cli/opts/CancelOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/CancelOfferOptionParser.java index c35ffc7bfb4..a18edb84c60 100644 --- a/cli/src/main/java/bisq/cli/opts/CancelOfferOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/CancelOfferOptionParser.java @@ -18,14 +18,7 @@ package bisq.cli.opts; -import joptsimple.OptionSpec; - -import static bisq.cli.opts.OptLabel.OPT_OFFER_ID; - -public class CancelOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts { - - final OptionSpec offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to cancel") - .withRequiredArg(); +public class CancelOfferOptionParser extends OfferIdOptionParser implements MethodOpts { public CancelOfferOptionParser(String[] args) { super(args); @@ -34,12 +27,7 @@ public CancelOfferOptionParser(String[] args) { public CancelOfferOptionParser parse() { super.parse(); - // Short circuit opt validation if user just wants help. - if (options.has(helpOpt)) - return this; - - if (!options.has(offerIdOpt) || options.valueOf(offerIdOpt).isEmpty()) - throw new IllegalArgumentException("no offer id specified"); + // Super class will short-circuit parsing if help option is present. return this; } diff --git a/cli/src/main/java/bisq/cli/opts/CreateOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/CreateOfferOptionParser.java index 42cf8ad1550..df85c69812a 100644 --- a/cli/src/main/java/bisq/cli/opts/CreateOfferOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/CreateOfferOptionParser.java @@ -28,7 +28,7 @@ public class CreateOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec paymentAccountIdOpt = parser.accepts(OPT_PAYMENT_ACCOUNT, - "id of payment account used for offer") + "id of payment account used for offer") .withRequiredArg() .defaultsTo(EMPTY); diff --git a/cli/src/main/java/bisq/cli/opts/CreatePaymentAcctOptionParser.java b/cli/src/main/java/bisq/cli/opts/CreatePaymentAcctOptionParser.java index fe91924bb41..c4b52229664 100644 --- a/cli/src/main/java/bisq/cli/opts/CreatePaymentAcctOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/CreatePaymentAcctOptionParser.java @@ -29,7 +29,7 @@ public class CreatePaymentAcctOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec paymentAcctFormPathOpt = parser.accepts(OPT_PAYMENT_ACCOUNT_FORM, - "path to json payment account form") + "path to json payment account form") .withRequiredArg(); public CreatePaymentAcctOptionParser(String[] args) { diff --git a/cli/src/main/java/bisq/cli/opts/EditOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/EditOfferOptionParser.java index 288f1a9f40d..35001553006 100644 --- a/cli/src/main/java/bisq/cli/opts/EditOfferOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/EditOfferOptionParser.java @@ -24,7 +24,10 @@ import java.math.BigDecimal; -import static bisq.cli.opts.OptLabel.*; +import static bisq.cli.opts.OptLabel.OPT_ENABLE; +import static bisq.cli.opts.OptLabel.OPT_FIXED_PRICE; +import static bisq.cli.opts.OptLabel.OPT_MKT_PRICE_MARGIN; +import static bisq.cli.opts.OptLabel.OPT_TRIGGER_PRICE; import static bisq.proto.grpc.EditOfferRequest.EditType.*; import static java.lang.String.format; @@ -32,26 +35,23 @@ import org.checkerframework.checker.nullness.qual.Nullable; -public class EditOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts { +public class EditOfferOptionParser extends OfferIdOptionParser implements MethodOpts { static int OPT_ENABLE_ON = 1; static int OPT_ENABLE_OFF = 0; static int OPT_ENABLE_IGNORED = -1; - final OptionSpec offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to cancel") - .withRequiredArg(); - final OptionSpec fixedPriceOpt = parser.accepts(OPT_FIXED_PRICE, "fixed btc price") .withOptionalArg() .defaultsTo("0"); final OptionSpec mktPriceMarginOpt = parser.accepts(OPT_MKT_PRICE_MARGIN, - "market btc price margin (%)") + "market btc price margin (%)") .withOptionalArg() .defaultsTo("0.00"); final OptionSpec triggerPriceOpt = parser.accepts(OPT_TRIGGER_PRICE, - "trigger price (applies to mkt price margin based offers)") + "trigger price (applies to mkt price margin based offers)") .withOptionalArg() .defaultsTo("0"); @@ -59,7 +59,7 @@ public class EditOfferOptionParser extends AbstractMethodOptionParser implements // activation state). For this reason, a boolean type is not used (can only be // true or false). final OptionSpec enableOpt = parser.accepts(OPT_ENABLE, - "enable or disable offer") + "enable or disable offer") .withOptionalArg() .ofType(String.class); @@ -72,12 +72,7 @@ public EditOfferOptionParser(String[] args) { public EditOfferOptionParser parse() { super.parse(); - // Short circuit opt validation if user just wants help. - if (options.has(helpOpt)) - return this; - - if (!options.has(offerIdOpt) || options.valueOf(offerIdOpt).isEmpty()) - throw new IllegalArgumentException("no offer id specified"); + // Super class will short-circuit parsing if help option is present. boolean hasNoEditDetails = !options.has(fixedPriceOpt) && !options.has(mktPriceMarginOpt) @@ -201,10 +196,6 @@ public EditOfferOptionParser parse() { return this; } - public String getOfferId() { - return options.valueOf(offerIdOpt); - } - public String getFixedPrice() { if (offerEditType.equals(FIXED_PRICE_ONLY) || offerEditType.equals(FIXED_PRICE_AND_ACTIVATION_STATE)) { return options.has(fixedPriceOpt) ? options.valueOf(fixedPriceOpt) : "0"; diff --git a/cli/src/main/java/bisq/cli/opts/GetPaymentAcctFormOptionParser.java b/cli/src/main/java/bisq/cli/opts/GetPaymentAcctFormOptionParser.java index 508069c2f30..bec9044f264 100644 --- a/cli/src/main/java/bisq/cli/opts/GetPaymentAcctFormOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/GetPaymentAcctFormOptionParser.java @@ -25,7 +25,7 @@ public class GetPaymentAcctFormOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec paymentMethodIdOpt = parser.accepts(OPT_PAYMENT_METHOD_ID, - "id of payment method type used by a payment account") + "id of payment method type used by a payment account") .withRequiredArg(); public GetPaymentAcctFormOptionParser(String[] args) { diff --git a/cli/src/main/java/bisq/cli/opts/GetOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/OfferIdOptionParser.java similarity index 80% rename from cli/src/main/java/bisq/cli/opts/GetOfferOptionParser.java rename to cli/src/main/java/bisq/cli/opts/OfferIdOptionParser.java index 1a849654cf7..60bee4960e1 100644 --- a/cli/src/main/java/bisq/cli/opts/GetOfferOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/OfferIdOptionParser.java @@ -22,16 +22,20 @@ import static bisq.cli.opts.OptLabel.OPT_OFFER_ID; -public class GetOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts { +/** + * Superclass for option parsers requiring an offer-id. Avoids a small amount of + * duplicated boilerplate. + */ +public class OfferIdOptionParser extends AbstractMethodOptionParser implements MethodOpts { - final OptionSpec offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to get") + final OptionSpec offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer") .withRequiredArg(); - public GetOfferOptionParser(String[] args) { + public OfferIdOptionParser(String[] args) { super(args); } - public GetOfferOptionParser parse() { + public OfferIdOptionParser parse() { super.parse(); // Short circuit opt validation if user just wants help. diff --git a/cli/src/main/java/bisq/cli/opts/SetTxFeeRateOptionParser.java b/cli/src/main/java/bisq/cli/opts/SetTxFeeRateOptionParser.java index f7ed113cb3c..be0132b5fee 100644 --- a/cli/src/main/java/bisq/cli/opts/SetTxFeeRateOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/SetTxFeeRateOptionParser.java @@ -25,7 +25,7 @@ public class SetTxFeeRateOptionParser extends AbstractMethodOptionParser implements MethodOpts { final OptionSpec feeRateOpt = parser.accepts(OPT_TX_FEE_RATE, - "tx fee rate preference (sats/byte)") + "tx fee rate preference (sats/byte)") .withRequiredArg(); public SetTxFeeRateOptionParser(String[] args) { diff --git a/cli/src/main/java/bisq/cli/opts/TakeOfferOptionParser.java b/cli/src/main/java/bisq/cli/opts/TakeOfferOptionParser.java index 67fbdd8c86d..9d424c23cec 100644 --- a/cli/src/main/java/bisq/cli/opts/TakeOfferOptionParser.java +++ b/cli/src/main/java/bisq/cli/opts/TakeOfferOptionParser.java @@ -21,13 +21,9 @@ import joptsimple.OptionSpec; import static bisq.cli.opts.OptLabel.OPT_FEE_CURRENCY; -import static bisq.cli.opts.OptLabel.OPT_OFFER_ID; import static bisq.cli.opts.OptLabel.OPT_PAYMENT_ACCOUNT; -public class TakeOfferOptionParser extends AbstractMethodOptionParser implements MethodOpts { - - final OptionSpec offerIdOpt = parser.accepts(OPT_OFFER_ID, "id of offer to take") - .withRequiredArg(); +public class TakeOfferOptionParser extends OfferIdOptionParser implements MethodOpts { final OptionSpec paymentAccountIdOpt = parser.accepts(OPT_PAYMENT_ACCOUNT, "id of payment account used for trade") .withRequiredArg(); @@ -43,12 +39,7 @@ public TakeOfferOptionParser(String[] args) { public TakeOfferOptionParser parse() { super.parse(); - // Short circuit opt validation if user just wants help. - if (options.has(helpOpt)) - return this; - - if (!options.has(offerIdOpt) || options.valueOf(offerIdOpt).isEmpty()) - throw new IllegalArgumentException("no offer id specified"); + // Super class will short-circuit parsing if help option is present. if (!options.has(paymentAccountIdOpt) || options.valueOf(paymentAccountIdOpt).isEmpty()) throw new IllegalArgumentException("no payment account id specified"); @@ -56,10 +47,6 @@ public TakeOfferOptionParser parse() { return this; } - public String getOfferId() { - return options.valueOf(offerIdOpt); - } - public String getPaymentAccountId() { return options.valueOf(paymentAccountIdOpt); } diff --git a/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java b/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java index 3395c0e220f..cf95506615e 100644 --- a/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java +++ b/cli/src/main/java/bisq/cli/request/TradesServiceRequest.java @@ -21,8 +21,6 @@ import bisq.proto.grpc.ConfirmPaymentStartedRequest; import bisq.proto.grpc.GetTradeRequest; import bisq.proto.grpc.KeepFundsRequest; -import bisq.proto.grpc.TakeBsqSwapOfferReply; -import bisq.proto.grpc.TakeBsqSwapOfferRequest; import bisq.proto.grpc.TakeOfferReply; import bisq.proto.grpc.TakeOfferRequest; import bisq.proto.grpc.TradeInfo; @@ -40,17 +38,6 @@ public TradesServiceRequest(GrpcStubs grpcStubs) { this.grpcStubs = grpcStubs; } - public TakeBsqSwapOfferReply getTakeBsqSwapOfferReply(String offerId, - String paymentAccountId, - String takerFeeCurrencyCode) { - var request = TakeBsqSwapOfferRequest.newBuilder() - .setOfferId(offerId) - .setPaymentAccountId(paymentAccountId) - .setTakerFeeCurrencyCode(takerFeeCurrencyCode) - .build(); - return grpcStubs.tradesService.takeBsqSwapOffer(request); - } - public TakeOfferReply getTakeOfferReply(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { var request = TakeOfferRequest.newBuilder() .setOfferId(offerId) @@ -60,19 +47,20 @@ public TakeOfferReply getTakeOfferReply(String offerId, String paymentAccountId, return grpcStubs.tradesService.takeOffer(request); } - public TradeInfo takeOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { - var reply = getTakeOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode); + public TradeInfo takeBsqSwapOffer(String offerId) { + var reply = getTakeOfferReply(offerId, "", ""); if (reply.hasTrade()) return reply.getTrade(); else throw new IllegalStateException(reply.getFailureReason().getDescription()); } - public TradeInfo getBsqSwapTrade(String tradeId) { - var request = GetTradeRequest.newBuilder() - .setTradeId(tradeId) - .build(); - return grpcStubs.tradesService.getBsqSwapTrade(request).getBsqSwapTrade(); + public TradeInfo takeOffer(String offerId, String paymentAccountId, String takerFeeCurrencyCode) { + var reply = getTakeOfferReply(offerId, paymentAccountId, takerFeeCurrencyCode); + if (reply.hasTrade()) + return reply.getTrade(); + else + throw new IllegalStateException(reply.getFailureReason().getDescription()); } public TradeInfo getTrade(String tradeId) { From 6403fc1f8133bee655013d19e4ba95085e83f267 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Wed, 24 Nov 2021 13:12:48 -0300 Subject: [PATCH 17/17] Adjust apitest cases to rpc BSQ wwap related changes --- .../method/offer/AbstractOfferTest.java | 9 +++++ .../method/trade/AbstractTradeTest.java | 9 +++++ .../method/trade/BsqSwapTradeTest.java | 36 ++++++++++++------- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java b/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java index fb8c2d76330..218af0e15e1 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/AbstractOfferTest.java @@ -41,10 +41,12 @@ import static bisq.apitest.config.BisqAppConfig.seednode; import static bisq.cli.table.builder.TableType.OFFER_TBL; import static bisq.common.util.MathUtils.exactMultiply; +import static java.lang.System.out; import bisq.apitest.method.MethodTest; +import bisq.cli.CliMain; import bisq.cli.table.builder.TableBuilder; @Slf4j @@ -134,4 +136,11 @@ public static void createLegacyBsqPaymentAccounts() { public static void tearDown() { tearDownScaffold(); } + + protected static void runCliGetOffer(String offerId) { + out.println("Alice's CLI 'getmyoffer' response:"); + CliMain.main(new String[]{"--password=xyz", "--port=9998", "getmyoffer", "--offer-id=" + offerId}); + out.println("Bob's CLI 'getoffer' response:"); + CliMain.main(new String[]{"--password=xyz", "--port=9999", "getoffer", "--offer-id=" + offerId}); + } } diff --git a/apitest/src/test/java/bisq/apitest/method/trade/AbstractTradeTest.java b/apitest/src/test/java/bisq/apitest/method/trade/AbstractTradeTest.java index 53b9f176f84..84f4f9bac21 100644 --- a/apitest/src/test/java/bisq/apitest/method/trade/AbstractTradeTest.java +++ b/apitest/src/test/java/bisq/apitest/method/trade/AbstractTradeTest.java @@ -21,11 +21,13 @@ import static bisq.core.trade.model.bisq_v1.Trade.State.DEPOSIT_CONFIRMED_IN_BLOCK_CHAIN; import static bisq.core.trade.model.bisq_v1.Trade.State.SELLER_RECEIVED_FIAT_PAYMENT_INITIATED_MSG; import static java.lang.String.format; +import static java.lang.System.out; import static org.junit.jupiter.api.Assertions.*; import bisq.apitest.method.offer.AbstractOfferTest; +import bisq.cli.CliMain; import bisq.cli.GrpcClient; import bisq.cli.table.builder.TableBuilder; @@ -243,4 +245,11 @@ protected final void logTrade(Logger log, new TableBuilder(TRADE_DETAIL_TBL, trade).build())); } } + + protected static void runCliGetTrade(String tradeId) { + out.println("Alice's CLI 'gettrade' response:"); + CliMain.main(new String[]{"--password=xyz", "--port=9998", "gettrade", "--trade-id=" + tradeId}); + out.println("Bob's CLI 'gettrade' response:"); + CliMain.main(new String[]{"--password=xyz", "--port=9999", "gettrade", "--trade-id=" + tradeId}); + } } diff --git a/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java b/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java index 674109f569f..fc8cb607ea3 100644 --- a/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java +++ b/apitest/src/test/java/bisq/apitest/method/trade/BsqSwapTradeTest.java @@ -28,7 +28,6 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; @@ -36,9 +35,11 @@ import static bisq.apitest.config.ApiTestConfig.BSQ; import static bisq.apitest.config.ApiTestConfig.BTC; +import static bisq.proto.grpc.GetOfferCategoryReply.OfferCategory.BSQ_SWAP; import static java.lang.String.format; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static protobuf.BsqSwapTrade.State.COMPLETED; import static protobuf.BsqSwapTrade.State.PREPARATION; @@ -49,13 +50,11 @@ import bisq.apitest.method.offer.AbstractOfferTest; import bisq.cli.GrpcClient; -@Disabled +// @Disabled @Slf4j @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class BsqSwapTradeTest extends AbstractTradeTest { - private static final String BISQ_FEE_CURRENCY_CODE = BSQ; - // Long-running swap trade tests might want to check node logs for exceptions. @Setter private boolean checkForLoggedExceptions; @@ -67,7 +66,7 @@ public static void setUp() { @BeforeEach public void generateBtcBlock() { - genBtcBlocksThenWait(1, 2000); + genBtcBlocksThenWait(1, 2_000); } @Test @@ -102,23 +101,36 @@ public void testAliceCreateBsqSwapBuyOffer() { mySwapOffer = aliceClient.getMyOffer(newOfferId); log.debug("My fetched BsqSwap Sell BSQ (Buy BTC) OFFER:\n{}", toOfferTable.apply(mySwapOffer)); assertNotEquals(0, mySwapOffer.getMakerFee()); + + runCliGetOffer(newOfferId); } @Test @Order(3) public void testBobTakesBsqSwapOffer() { var availableSwapOffer = getAvailableBsqSwapOffer(bobClient); - var swapTrade = bobClient.takeBsqSwapOffer(availableSwapOffer.getId(), - bobsBsqSwapAcct.getId(), - BISQ_FEE_CURRENCY_CODE); + + // Before sending a TakeOfferRequest, the CLI needs to know what kind of Offer + // it is taking (v1 or BsqSwap). Only BSQ swap offers can be taken with a + // single offerId parameter. Taking v1 offers requires an additional + // paymentAccountId param. The test case knows what kind of offer is being taken, + // but we test the gRPC GetOfferCategory service here. + var availableOfferCategory = bobClient.getAvailableOfferCategory(availableSwapOffer.getId()); + assertTrue(availableOfferCategory.equals(BSQ_SWAP)); + + sleep(30_000); + + var swapTrade = bobClient.takeBsqSwapOffer(availableSwapOffer.getId()); tradeId = swapTrade.getTradeId(); // Cache the tradeId for following test case(s). log.debug("BsqSwap Trade at PREPARATION:\n{}", toTradeDetailTable.apply(swapTrade)); assertEquals(PREPARATION.name(), swapTrade.getState()); genBtcBlocksThenWait(1, 3_000); - swapTrade = getBsqSwapTrade(bobClient, swapTrade.getTradeId()); + swapTrade = getBsqSwapTrade(bobClient, tradeId); log.debug("BsqSwap Trade at COMPLETION:\n{}", toTradeDetailTable.apply(swapTrade)); assertEquals(COMPLETED.name(), swapTrade.getState()); + + runCliGetTrade(tradeId); } @Test @@ -164,7 +176,7 @@ private OfferInfo getAvailableBsqSwapOffer(GrpcClient client) { } fail(format("Bob gave up on fetching available bsq swap offers after %d attempts.", numFetchAttempts)); } - sleep(1000); + sleep(1_000); } else { assertEquals(1, bsqSwapOffers.size()); log.debug("Bob found new available bsq swap offer on attempt # {}.", numFetchAttempts); @@ -181,7 +193,7 @@ private TradeInfo getBsqSwapTrade(GrpcClient client, String tradeId) { while (true) { try { numFetchAttempts++; - return client.getBsqSwapTrade(tradeId); + return client.getTrade(tradeId); } catch (Exception ex) { log.warn(ex.getMessage()); if (numFetchAttempts > 9) { @@ -190,7 +202,7 @@ private TradeInfo getBsqSwapTrade(GrpcClient client, String tradeId) { } fail(format("Could not find new bsq swap trade after %d attempts.", numFetchAttempts)); } else { - sleep(1000); + sleep(1_000); } } }