From 71a61c63dacb2aec7bddaabb93d1643d837981c6 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Sat, 14 Aug 2021 16:58:47 -0300 Subject: [PATCH] Display Enabled=PENDING in CLI 'createoffer' output A newly created offer has no OpenOffer+State (AVAILABLE || DEACTIVATED) when displayed in the CLI's console. This change adds a 'bool isMyPendingOffer' to the OfferInfo proto + wrapper, and the CLI's console offer output formatter uses it to determine if it should display a new offer's Enabled column value as PENDING, instead of an ambiguous NO value. --- .../method/offer/CreateBSQOffersTest.java | 21 ++++++++++++++ .../offer/CreateOfferUsingFixedPriceTest.java | 16 +++++++++++ ...CreateOfferUsingMarketPriceMarginTest.java | 26 +++++++++++++++++ cli/src/main/java/bisq/cli/CliMain.java | 2 +- cli/src/main/java/bisq/cli/TableFormat.java | 12 ++++++-- .../java/bisq/core/api/model/OfferInfo.java | 28 ++++++++++++++++--- .../bisq/daemon/grpc/GrpcOffersService.java | 4 +-- proto/src/main/proto/grpc.proto | 1 + 8 files changed, 101 insertions(+), 9 deletions(-) diff --git a/apitest/src/test/java/bisq/apitest/method/offer/CreateBSQOffersTest.java b/apitest/src/test/java/bisq/apitest/method/offer/CreateBSQOffersTest.java index ba4f8ce47b6..652d7f50dcf 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/CreateBSQOffersTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/CreateBSQOffersTest.java @@ -39,6 +39,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static protobuf.OfferPayload.Direction.BUY; import static protobuf.OfferPayload.Direction.SELL; @@ -70,6 +71,9 @@ public void testCreateBuy1BTCFor20KBSQOffer() { alicesBsqAcct.getId(), MAKER_FEE_CURRENCY_CODE); log.info("Sell BSQ (Buy BTC) OFFER:\n{}", formatOfferTable(singletonList(newOffer), BSQ)); + assertTrue(newOffer.getIsMyOffer()); + assertTrue(newOffer.getIsMyPendingOffer()); + String newOfferId = newOffer.getId(); assertNotEquals("", newOfferId); assertEquals(BUY.name(), newOffer.getDirection()); @@ -86,6 +90,8 @@ public void testCreateBuy1BTCFor20KBSQOffer() { genBtcBlockAndWaitForOfferPreparation(); newOffer = aliceClient.getMyOffer(newOfferId); + assertTrue(newOffer.getIsMyOffer()); + assertFalse(newOffer.getIsMyPendingOffer()); assertEquals(newOfferId, newOffer.getId()); assertEquals(BUY.name(), newOffer.getDirection()); assertFalse(newOffer.getUseMarketBasedPrice()); @@ -112,6 +118,9 @@ public void testCreateSell1BTCFor20KBSQOffer() { alicesBsqAcct.getId(), MAKER_FEE_CURRENCY_CODE); log.info("SELL 20K BSQ OFFER:\n{}", formatOfferTable(singletonList(newOffer), BSQ)); + assertTrue(newOffer.getIsMyOffer()); + assertTrue(newOffer.getIsMyPendingOffer()); + String newOfferId = newOffer.getId(); assertNotEquals("", newOfferId); assertEquals(SELL.name(), newOffer.getDirection()); @@ -128,6 +137,8 @@ public void testCreateSell1BTCFor20KBSQOffer() { genBtcBlockAndWaitForOfferPreparation(); newOffer = aliceClient.getMyOffer(newOfferId); + assertTrue(newOffer.getIsMyOffer()); + assertFalse(newOffer.getIsMyPendingOffer()); assertEquals(newOfferId, newOffer.getId()); assertEquals(SELL.name(), newOffer.getDirection()); assertFalse(newOffer.getUseMarketBasedPrice()); @@ -154,6 +165,9 @@ public void testCreateBuyBTCWith1To2KBSQOffer() { alicesBsqAcct.getId(), MAKER_FEE_CURRENCY_CODE); log.info("BUY 1-2K BSQ OFFER:\n{}", formatOfferTable(singletonList(newOffer), BSQ)); + assertTrue(newOffer.getIsMyOffer()); + assertTrue(newOffer.getIsMyPendingOffer()); + String newOfferId = newOffer.getId(); assertNotEquals("", newOfferId); assertEquals(BUY.name(), newOffer.getDirection()); @@ -170,6 +184,8 @@ public void testCreateBuyBTCWith1To2KBSQOffer() { genBtcBlockAndWaitForOfferPreparation(); newOffer = aliceClient.getMyOffer(newOfferId); + assertTrue(newOffer.getIsMyOffer()); + assertFalse(newOffer.getIsMyPendingOffer()); assertEquals(newOfferId, newOffer.getId()); assertEquals(BUY.name(), newOffer.getDirection()); assertFalse(newOffer.getUseMarketBasedPrice()); @@ -196,6 +212,9 @@ public void testCreateSellBTCFor5To10KBSQOffer() { alicesBsqAcct.getId(), MAKER_FEE_CURRENCY_CODE); log.info("SELL 5-10K BSQ OFFER:\n{}", formatOfferTable(singletonList(newOffer), BSQ)); + assertTrue(newOffer.getIsMyOffer()); + assertTrue(newOffer.getIsMyPendingOffer()); + String newOfferId = newOffer.getId(); assertNotEquals("", newOfferId); assertEquals(SELL.name(), newOffer.getDirection()); @@ -212,6 +231,8 @@ public void testCreateSellBTCFor5To10KBSQOffer() { genBtcBlockAndWaitForOfferPreparation(); newOffer = aliceClient.getMyOffer(newOfferId); + assertTrue(newOffer.getIsMyOffer()); + assertFalse(newOffer.getIsMyPendingOffer()); assertEquals(newOfferId, newOffer.getId()); assertEquals(SELL.name(), newOffer.getDirection()); assertFalse(newOffer.getUseMarketBasedPrice()); diff --git a/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingFixedPriceTest.java b/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingFixedPriceTest.java index 081c6feadc7..715e05a92e7 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingFixedPriceTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingFixedPriceTest.java @@ -35,6 +35,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static protobuf.OfferPayload.Direction.BUY; import static protobuf.OfferPayload.Direction.SELL; @@ -58,6 +59,9 @@ public void testCreateAUDBTCBuyOfferUsingFixedPrice16000() { audAccount.getId(), MAKER_FEE_CURRENCY_CODE); log.info("OFFER #1:\n{}", formatOfferTable(singletonList(newOffer), "AUD")); + assertTrue(newOffer.getIsMyOffer()); + assertTrue(newOffer.getIsMyPendingOffer()); + String newOfferId = newOffer.getId(); assertNotEquals("", newOfferId); assertEquals(BUY.name(), newOffer.getDirection()); @@ -72,6 +76,8 @@ public void testCreateAUDBTCBuyOfferUsingFixedPrice16000() { assertFalse(newOffer.getIsCurrencyForMakerFeeBtc()); newOffer = aliceClient.getMyOffer(newOfferId); + assertTrue(newOffer.getIsMyOffer()); + assertFalse(newOffer.getIsMyPendingOffer()); assertEquals(newOfferId, newOffer.getId()); assertEquals(BUY.name(), newOffer.getDirection()); assertFalse(newOffer.getUseMarketBasedPrice()); @@ -98,6 +104,9 @@ public void testCreateUSDBTCBuyOfferUsingFixedPrice100001234() { usdAccount.getId(), MAKER_FEE_CURRENCY_CODE); log.info("OFFER #2:\n{}", formatOfferTable(singletonList(newOffer), "USD")); + assertTrue(newOffer.getIsMyOffer()); + assertTrue(newOffer.getIsMyPendingOffer()); + String newOfferId = newOffer.getId(); assertNotEquals("", newOfferId); assertEquals(BUY.name(), newOffer.getDirection()); @@ -112,6 +121,8 @@ public void testCreateUSDBTCBuyOfferUsingFixedPrice100001234() { assertFalse(newOffer.getIsCurrencyForMakerFeeBtc()); newOffer = aliceClient.getMyOffer(newOfferId); + assertTrue(newOffer.getIsMyOffer()); + assertFalse(newOffer.getIsMyPendingOffer()); assertEquals(newOfferId, newOffer.getId()); assertEquals(BUY.name(), newOffer.getDirection()); assertFalse(newOffer.getUseMarketBasedPrice()); @@ -138,6 +149,9 @@ public void testCreateEURBTCSellOfferUsingFixedPrice95001234() { eurAccount.getId(), MAKER_FEE_CURRENCY_CODE); log.info("OFFER #3:\n{}", formatOfferTable(singletonList(newOffer), "EUR")); + assertTrue(newOffer.getIsMyOffer()); + assertTrue(newOffer.getIsMyPendingOffer()); + String newOfferId = newOffer.getId(); assertNotEquals("", newOfferId); assertEquals(SELL.name(), newOffer.getDirection()); @@ -152,6 +166,8 @@ public void testCreateEURBTCSellOfferUsingFixedPrice95001234() { assertFalse(newOffer.getIsCurrencyForMakerFeeBtc()); newOffer = aliceClient.getMyOffer(newOfferId); + assertTrue(newOffer.getIsMyOffer()); + assertFalse(newOffer.getIsMyPendingOffer()); assertEquals(newOfferId, newOffer.getId()); assertEquals(SELL.name(), newOffer.getDirection()); assertFalse(newOffer.getUseMarketBasedPrice()); diff --git a/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java b/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java index 451bd1f2c18..391bb4c5a37 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java @@ -49,6 +49,7 @@ import static java.math.RoundingMode.HALF_UP; import static java.util.Collections.singletonList; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static protobuf.OfferPayload.Direction.BUY; @@ -81,6 +82,9 @@ public void testCreateUSDBTCBuyOffer5PctPriceMargin() { MAKER_FEE_CURRENCY_CODE, NO_TRIGGER_PRICE); log.info("OFFER #1:\n{}", formatOfferTable(singletonList(newOffer), "usd")); + assertTrue(newOffer.getIsMyOffer()); + assertTrue(newOffer.getIsMyPendingOffer()); + String newOfferId = newOffer.getId(); assertNotEquals("", newOfferId); assertEquals(BUY.name(), newOffer.getDirection()); @@ -94,6 +98,8 @@ public void testCreateUSDBTCBuyOffer5PctPriceMargin() { assertTrue(newOffer.getIsCurrencyForMakerFeeBtc()); newOffer = aliceClient.getMyOffer(newOfferId); + assertTrue(newOffer.getIsMyOffer()); + assertFalse(newOffer.getIsMyPendingOffer()); assertEquals(newOfferId, newOffer.getId()); assertEquals(BUY.name(), newOffer.getDirection()); assertTrue(newOffer.getUseMarketBasedPrice()); @@ -123,6 +129,9 @@ public void testCreateNZDBTCBuyOfferMinus2PctPriceMargin() { MAKER_FEE_CURRENCY_CODE, NO_TRIGGER_PRICE); log.info("OFFER #2:\n{}", formatOfferTable(singletonList(newOffer), "nzd")); + assertTrue(newOffer.getIsMyOffer()); + assertTrue(newOffer.getIsMyPendingOffer()); + String newOfferId = newOffer.getId(); assertNotEquals("", newOfferId); assertEquals(BUY.name(), newOffer.getDirection()); @@ -136,6 +145,8 @@ public void testCreateNZDBTCBuyOfferMinus2PctPriceMargin() { assertTrue(newOffer.getIsCurrencyForMakerFeeBtc()); newOffer = aliceClient.getMyOffer(newOfferId); + assertTrue(newOffer.getIsMyOffer()); + assertFalse(newOffer.getIsMyPendingOffer()); assertEquals(newOfferId, newOffer.getId()); assertEquals(BUY.name(), newOffer.getDirection()); assertTrue(newOffer.getUseMarketBasedPrice()); @@ -165,6 +176,9 @@ public void testCreateGBPBTCSellOfferMinus1Point5PctPriceMargin() { MAKER_FEE_CURRENCY_CODE, NO_TRIGGER_PRICE); log.info("OFFER #3:\n{}", formatOfferTable(singletonList(newOffer), "gbp")); + assertTrue(newOffer.getIsMyOffer()); + assertTrue(newOffer.getIsMyPendingOffer()); + String newOfferId = newOffer.getId(); assertNotEquals("", newOfferId); assertEquals(SELL.name(), newOffer.getDirection()); @@ -178,6 +192,8 @@ public void testCreateGBPBTCSellOfferMinus1Point5PctPriceMargin() { assertTrue(newOffer.getIsCurrencyForMakerFeeBtc()); newOffer = aliceClient.getMyOffer(newOfferId); + assertTrue(newOffer.getIsMyOffer()); + assertFalse(newOffer.getIsMyPendingOffer()); assertEquals(newOfferId, newOffer.getId()); assertEquals(SELL.name(), newOffer.getDirection()); assertTrue(newOffer.getUseMarketBasedPrice()); @@ -207,6 +223,9 @@ public void testCreateBRLBTCSellOffer6Point55PctPriceMargin() { MAKER_FEE_CURRENCY_CODE, NO_TRIGGER_PRICE); log.info("OFFER #4:\n{}", formatOfferTable(singletonList(newOffer), "brl")); + assertTrue(newOffer.getIsMyOffer()); + assertTrue(newOffer.getIsMyPendingOffer()); + String newOfferId = newOffer.getId(); assertNotEquals("", newOfferId); assertEquals(SELL.name(), newOffer.getDirection()); @@ -220,6 +239,8 @@ public void testCreateBRLBTCSellOffer6Point55PctPriceMargin() { assertTrue(newOffer.getIsCurrencyForMakerFeeBtc()); newOffer = aliceClient.getMyOffer(newOfferId); + assertTrue(newOffer.getIsMyOffer()); + assertFalse(newOffer.getIsMyPendingOffer()); assertEquals(newOfferId, newOffer.getId()); assertEquals(SELL.name(), newOffer.getDirection()); assertTrue(newOffer.getUseMarketBasedPrice()); @@ -252,9 +273,14 @@ public void testCreateUSDBTCBuyOfferWithTriggerPrice() { usdAccount.getId(), MAKER_FEE_CURRENCY_CODE, triggerPriceAsLong); + assertTrue(newOffer.getIsMyOffer()); + assertTrue(newOffer.getIsMyPendingOffer()); + genBtcBlocksThenWait(1, 4000); // give time to add to offer book newOffer = aliceClient.getMyOffer(newOffer.getId()); log.info("OFFER #5:\n{}", formatOfferTable(singletonList(newOffer), "usd")); + assertTrue(newOffer.getIsMyOffer()); + assertFalse(newOffer.getIsMyPendingOffer()); assertEquals(triggerPriceAsLong, newOffer.getTriggerPrice()); } diff --git a/cli/src/main/java/bisq/cli/CliMain.java b/cli/src/main/java/bisq/cli/CliMain.java index bf3978675c6..bd57db2e9c9 100644 --- a/cli/src/main/java/bisq/cli/CliMain.java +++ b/cli/src/main/java/bisq/cli/CliMain.java @@ -509,7 +509,7 @@ public static void run(String[] args) { } var tradeId = opts.getTradeId(); var address = opts.getAddress(); - // Multi-word memos must be double quoted. + // Multi-word memos must be double-quoted. var memo = opts.getMemo(); client.withdrawFunds(tradeId, address, memo); out.printf("trade %s funds sent to btc address %s%n", tradeId, address); diff --git a/cli/src/main/java/bisq/cli/TableFormat.java b/cli/src/main/java/bisq/cli/TableFormat.java index 3d14b5991d4..1340ac3a760 100644 --- a/cli/src/main/java/bisq/cli/TableFormat.java +++ b/cli/src/main/java/bisq/cli/TableFormat.java @@ -202,7 +202,7 @@ private static String formattedFiatOfferTable(List offers, return headerLine + offers.stream() .map(o -> format(colDataFormat, - o.getIsActivated() ? "YES" : "NO", + formatEnabled(o), o.getDirection(), formatPrice(o.getPrice()), formatAmountRange(o.getMinAmount(), o.getAmount()), @@ -300,7 +300,7 @@ private static String formatCryptoCurrencyOfferTable(List offers, return headerLine + offers.stream() .map(o -> format(colDataFormat, - o.getIsActivated() ? "YES" : "NO", + formatEnabled(o), directionFormat.apply(o), formatCryptoCurrencyPrice(o.getPrice()), formatAmountRange(o.getMinAmount(), o.getAmount()), @@ -324,6 +324,14 @@ private static String formatCryptoCurrencyOfferTable(List offers, } } + + private static String formatEnabled(OfferInfo offerInfo) { + if (offerInfo.getIsMyOffer() && offerInfo.getIsMyPendingOffer()) + return "PENDING"; + else + return offerInfo.getIsActivated() ? "YES" : "NO"; + } + private static int getLongestPaymentMethodColWidth(List offers) { return getLongestColumnSize( COL_HEADER_PAYMENT_METHOD.length(), 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 f99df264569..15ad2acc108 100644 --- a/core/src/main/java/bisq/core/api/model/OfferInfo.java +++ b/core/src/main/java/bisq/core/api/model/OfferInfo.java @@ -63,7 +63,8 @@ public class OfferInfo implements Payload { private final long date; private final String state; private final boolean isActivated; - private boolean isMyOffer; + private boolean isMyOffer; // Not final -- may be re-set after instantiation. + private final boolean isMyPendingOffer; public OfferInfo(OfferInfoBuilder builder) { this.id = builder.id; @@ -91,11 +92,12 @@ public OfferInfo(OfferInfoBuilder builder) { this.state = builder.state; this.isActivated = builder.isActivated; this.isMyOffer = builder.isMyOffer; + this.isMyPendingOffer = builder.isMyPendingOffer; } - // Allow isMyOffer to be set on new offers' OfferInfo instances. - public void setIsMyOffer(boolean myOffer) { - isMyOffer = myOffer; + // Allow isMyOffer to be set on a new offer's OfferInfo instance. + public void setIsMyOffer(boolean isMyOffer) { + this.isMyOffer = isMyOffer; } public static OfferInfo toOfferInfo(Offer offer) { @@ -104,6 +106,16 @@ public static OfferInfo toOfferInfo(Offer offer) { return getOfferInfoBuilder(offer, false).build(); } + public static OfferInfo toPendingOfferInfo(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) + .withIsMyPendingOffer(true) + .build(); + } + public static OfferInfo toOfferInfo(OpenOffer openOffer) { // An OpenOffer is always my offer. return getOfferInfoBuilder(openOffer.getOffer(), true) @@ -171,6 +183,7 @@ public bisq.proto.grpc.OfferInfo toProtoMessage() { .setState(state) .setIsActivated(isActivated) .setIsMyOffer(isMyOffer) + .setIsMyPendingOffer(isMyPendingOffer) .build(); } @@ -202,6 +215,7 @@ public static OfferInfo fromProto(bisq.proto.grpc.OfferInfo proto) { .withState(proto.getState()) .withIsActivated(proto.getIsActivated()) .withIsMyOffer(proto.getIsMyOffer()) + .withIsMyPendingOffer(proto.getIsMyPendingOffer()) .build(); } @@ -237,6 +251,7 @@ public static class OfferInfoBuilder { private String state; private boolean isActivated; private boolean isMyOffer; + private boolean isMyPendingOffer; public OfferInfoBuilder withId(String id) { this.id = id; @@ -363,6 +378,11 @@ public OfferInfoBuilder withIsMyOffer(boolean isMyOffer) { return this; } + public OfferInfoBuilder withIsMyPendingOffer(boolean isMyPendingOffer) { + this.isMyPendingOffer = isMyPendingOffer; + return this; + } + public OfferInfo build() { return new OfferInfo(this); } diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java index b1f9212d46b..e31828bbfb8 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java @@ -50,6 +50,7 @@ import lombok.extern.slf4j.Slf4j; 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.OffersGrpc.*; import static java.util.concurrent.TimeUnit.MINUTES; @@ -160,8 +161,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 = toOfferInfo(offer); - offerInfo.setIsMyOffer(true); + OfferInfo offerInfo = toPendingOfferInfo(offer); CreateOfferReply reply = CreateOfferReply.newBuilder() .setOffer(offerInfo.toProtoMessage()) .build(); diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index ff2467f713f..21221eda452 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -192,6 +192,7 @@ message OfferInfo { uint64 makerFee = 23; bool isActivated = 24; bool isMyOffer = 25; + bool isMyPendingOffer = 26; } message AvailabilityResultWithDescription {