From dd67acc153bf53d4210b4f9d2ee6c184d2fdf3a1 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Mon, 5 Oct 2020 12:23:54 -0300 Subject: [PATCH 1/4] Simplify GrpcOffersService#createOffer (refactor) Push the placeOffer call down into CoreOffersService#createOffer, and use a countdown latch to wait for async placeOffer to complete. --- core/src/main/java/bisq/core/api/CoreApi.java | 33 +++++------------ .../java/bisq/core/api/CoreOffersService.java | 37 ++++++++++++------- .../bisq/daemon/grpc/GrpcOffersService.java | 21 +++-------- 3 files changed, 40 insertions(+), 51 deletions(-) diff --git a/core/src/main/java/bisq/core/api/CoreApi.java b/core/src/main/java/bisq/core/api/CoreApi.java index 33d62d70385..869b8a64942 100644 --- a/core/src/main/java/bisq/core/api/CoreApi.java +++ b/core/src/main/java/bisq/core/api/CoreApi.java @@ -22,7 +22,6 @@ import bisq.core.offer.Offer; import bisq.core.offer.OfferPayload; import bisq.core.payment.PaymentAccount; -import bisq.core.trade.handlers.TransactionResultHandler; import bisq.core.trade.statistics.TradeStatistics2; import bisq.core.trade.statistics.TradeStatisticsManager; @@ -110,17 +109,16 @@ public Offer createOffer(String currencyCode, paymentAccountId); } - // Not used yet, should be renamed for a new placeoffer api method. - public Offer createOffer(String offerId, - String currencyCode, - OfferPayload.Direction direction, - Price price, - boolean useMarketBasedPrice, - double marketPriceMargin, - Coin amount, - Coin minAmount, - double buyerSecurityDeposit, - PaymentAccount paymentAccount) { + public Offer editOffer(String offerId, + String currencyCode, + OfferPayload.Direction direction, + Price price, + boolean useMarketBasedPrice, + double marketPriceMargin, + Coin amount, + Coin minAmount, + double buyerSecurityDeposit, + PaymentAccount paymentAccount) { return coreOffersService.createOffer(offerId, currencyCode, direction, @@ -133,17 +131,6 @@ public Offer createOffer(String offerId, paymentAccount); } - public Offer placeOffer(Offer offer, - double buyerSecurityDeposit, - boolean useSavingsWallet, - TransactionResultHandler resultHandler) { - coreOffersService.placeOffer(offer, - buyerSecurityDeposit, - useSavingsWallet, - resultHandler); - return offer; - } - /////////////////////////////////////////////////////////////////////////////////////////// // PaymentAccounts /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/src/main/java/bisq/core/api/CoreOffersService.java b/core/src/main/java/bisq/core/api/CoreOffersService.java index aa1bba337bd..067dd80edd1 100644 --- a/core/src/main/java/bisq/core/api/CoreOffersService.java +++ b/core/src/main/java/bisq/core/api/CoreOffersService.java @@ -24,7 +24,6 @@ import bisq.core.offer.OfferBookService; import bisq.core.offer.OpenOfferManager; import bisq.core.payment.PaymentAccount; -import bisq.core.trade.handlers.TransactionResultHandler; import bisq.core.user.User; import org.bitcoinj.core.Coin; @@ -36,6 +35,7 @@ import java.util.Comparator; import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; @@ -86,7 +86,7 @@ List getOffers(String direction, String currencyCode) { return offers; } - // Create offer with a random offer id. + // Create and place new offer. Offer createOffer(String currencyCode, String directionAsString, String priceAsString, @@ -104,7 +104,7 @@ Offer createOffer(String currencyCode, Coin minAmount = Coin.valueOf(minAmountAsLong); PaymentAccount paymentAccount = user.getPaymentAccount(paymentAccountId); Coin useDefaultTxFee = Coin.ZERO; - return createOfferService.createAndGetOffer(offerId, + Offer offer = createOfferService.createAndGetOffer(offerId, direction, upperCaseCurrencyCode, amount, @@ -115,10 +115,16 @@ Offer createOffer(String currencyCode, exactMultiply(marketPriceMargin, 0.01), buyerSecurityDeposit, paymentAccount); + + // We don't support atm funding from external wallet to keep it simple. + boolean useSavingsWallet = true; + //noinspection ConstantConditions + placeOffer(offer, buyerSecurityDeposit, useSavingsWallet); + + return offer; } - // Create offer for given offer id. - // Not used yet, should be renamed for a new placeoffer api method. + // Edit a placed offer. Offer createOffer(String offerId, String currencyCode, Direction direction, @@ -130,7 +136,7 @@ Offer createOffer(String offerId, double buyerSecurityDeposit, PaymentAccount paymentAccount) { Coin useDefaultTxFee = Coin.ZERO; - Offer offer = createOfferService.createAndGetOffer(offerId, + return createOfferService.createAndGetOffer(offerId, direction, currencyCode.toUpperCase(), amount, @@ -141,22 +147,27 @@ Offer createOffer(String offerId, exactMultiply(marketPriceMargin, 0.01), buyerSecurityDeposit, paymentAccount); - return offer; } - Offer placeOffer(Offer offer, - double buyerSecurityDeposit, - boolean useSavingsWallet, - TransactionResultHandler resultHandler) { + private void placeOffer(Offer offer, + double buyerSecurityDeposit, + boolean useSavingsWallet) { + // Place offer is async; we need to wait for completion. + CountDownLatch latch = new CountDownLatch(1); openOfferManager.placeOffer(offer, buyerSecurityDeposit, useSavingsWallet, - resultHandler, + transaction -> latch.countDown(), log::error); + if (offer.getErrorMessage() != null) throw new IllegalStateException(offer.getErrorMessage()); - return offer; + try { + latch.await(); + } catch (InterruptedException ignored) { + // empty + } } private long priceStringToLong(String priceAsString, String currencyCode) { diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java index a7c63cb7877..39489c6c208 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java @@ -78,21 +78,12 @@ public void createOffer(CreateOfferRequest req, req.getMinAmount(), req.getBuyerSecurityDeposit(), req.getPaymentAccountId()); - - // We don't support atm funding from external wallet to keep it simple. - boolean useSavingsWallet = true; - //noinspection ConstantConditions - coreApi.placeOffer(offer, - req.getBuyerSecurityDeposit(), - useSavingsWallet, - transaction -> { - OfferInfo offerInfo = toOfferInfo(offer); - CreateOfferReply reply = CreateOfferReply.newBuilder() - .setOffer(offerInfo.toProtoMessage()) - .build(); - responseObserver.onNext(reply); - responseObserver.onCompleted(); - }); + OfferInfo offerInfo = toOfferInfo(offer); + CreateOfferReply reply = CreateOfferReply.newBuilder() + .setOffer(offerInfo.toProtoMessage()) + .build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); } catch (IllegalStateException | IllegalArgumentException cause) { var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage())); responseObserver.onError(ex); From 2d34730bd8530a141ef1255cf690c7584937889b Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Mon, 5 Oct 2020 13:51:48 -0300 Subject: [PATCH 2/4] Fix method name --- core/src/main/java/bisq/core/api/CoreApi.java | 2 +- core/src/main/java/bisq/core/api/CoreOffersService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/bisq/core/api/CoreApi.java b/core/src/main/java/bisq/core/api/CoreApi.java index 869b8a64942..9e9a57c4fb4 100644 --- a/core/src/main/java/bisq/core/api/CoreApi.java +++ b/core/src/main/java/bisq/core/api/CoreApi.java @@ -119,7 +119,7 @@ public Offer editOffer(String offerId, Coin minAmount, double buyerSecurityDeposit, PaymentAccount paymentAccount) { - return coreOffersService.createOffer(offerId, + return coreOffersService.editOffer(offerId, currencyCode, direction, price, diff --git a/core/src/main/java/bisq/core/api/CoreOffersService.java b/core/src/main/java/bisq/core/api/CoreOffersService.java index 067dd80edd1..eb9550f71bb 100644 --- a/core/src/main/java/bisq/core/api/CoreOffersService.java +++ b/core/src/main/java/bisq/core/api/CoreOffersService.java @@ -125,7 +125,7 @@ Offer createOffer(String currencyCode, } // Edit a placed offer. - Offer createOffer(String offerId, + Offer editOffer(String offerId, String currencyCode, Direction direction, Price price, From 3f3f4f06f52d5fb60e90248d154ac72d6b076cf2 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Mon, 5 Oct 2020 14:32:05 -0300 Subject: [PATCH 3/4] Use consumer::accept instead of a countdown latch This is more readable and stylistically consistent. --- core/src/main/java/bisq/core/api/CoreApi.java | 25 ++++---- .../java/bisq/core/api/CoreOffersService.java | 59 +++++++++---------- .../bisq/daemon/grpc/GrpcOffersService.java | 20 ++++--- 3 files changed, 54 insertions(+), 50 deletions(-) diff --git a/core/src/main/java/bisq/core/api/CoreApi.java b/core/src/main/java/bisq/core/api/CoreApi.java index 9e9a57c4fb4..8d298d222c6 100644 --- a/core/src/main/java/bisq/core/api/CoreApi.java +++ b/core/src/main/java/bisq/core/api/CoreApi.java @@ -35,6 +35,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.function.Consumer; import lombok.extern.slf4j.Slf4j; @@ -89,16 +90,17 @@ public List getOffers(String direction, String currencyCode) { return coreOffersService.getOffers(direction, currencyCode); } - public Offer createOffer(String currencyCode, - String directionAsString, - String priceAsString, - boolean useMarketBasedPrice, - double marketPriceMargin, - long amountAsLong, - long minAmountAsLong, - double buyerSecurityDeposit, - String paymentAccountId) { - return coreOffersService.createOffer(currencyCode, + public Offer createAnPlaceOffer(String currencyCode, + String directionAsString, + String priceAsString, + boolean useMarketBasedPrice, + double marketPriceMargin, + long amountAsLong, + long minAmountAsLong, + double buyerSecurityDeposit, + String paymentAccountId, + Consumer resultHandler) { + return coreOffersService.createAndPlaceOffer(currencyCode, directionAsString, priceAsString, useMarketBasedPrice, @@ -106,7 +108,8 @@ public Offer createOffer(String currencyCode, amountAsLong, minAmountAsLong, buyerSecurityDeposit, - paymentAccountId); + paymentAccountId, + resultHandler); } public Offer editOffer(String offerId, diff --git a/core/src/main/java/bisq/core/api/CoreOffersService.java b/core/src/main/java/bisq/core/api/CoreOffersService.java index eb9550f71bb..f94db1b95a9 100644 --- a/core/src/main/java/bisq/core/api/CoreOffersService.java +++ b/core/src/main/java/bisq/core/api/CoreOffersService.java @@ -27,6 +27,7 @@ import bisq.core.user.User; import org.bitcoinj.core.Coin; +import org.bitcoinj.core.Transaction; import org.bitcoinj.utils.Fiat; import javax.inject.Inject; @@ -35,7 +36,7 @@ import java.util.Comparator; import java.util.List; -import java.util.concurrent.CountDownLatch; +import java.util.function.Consumer; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; @@ -87,15 +88,16 @@ List getOffers(String direction, String currencyCode) { } // Create and place new offer. - Offer createOffer(String currencyCode, - String directionAsString, - String priceAsString, - boolean useMarketBasedPrice, - double marketPriceMargin, - long amountAsLong, - long minAmountAsLong, - double buyerSecurityDeposit, - String paymentAccountId) { + Offer createAndPlaceOffer(String currencyCode, + String directionAsString, + String priceAsString, + boolean useMarketBasedPrice, + double marketPriceMargin, + long amountAsLong, + long minAmountAsLong, + double buyerSecurityDeposit, + String paymentAccountId, + Consumer resultHandler) { String upperCaseCurrencyCode = currencyCode.toUpperCase(); String offerId = createOfferService.getRandomOfferId(); Direction direction = Direction.valueOf(directionAsString.toUpperCase()); @@ -119,22 +121,24 @@ Offer createOffer(String currencyCode, // We don't support atm funding from external wallet to keep it simple. boolean useSavingsWallet = true; //noinspection ConstantConditions - placeOffer(offer, buyerSecurityDeposit, useSavingsWallet); - + placeOffer(offer, + buyerSecurityDeposit, + useSavingsWallet, + transaction -> resultHandler.accept(offer)); return offer; } // Edit a placed offer. Offer editOffer(String offerId, - String currencyCode, - Direction direction, - Price price, - boolean useMarketBasedPrice, - double marketPriceMargin, - Coin amount, - Coin minAmount, - double buyerSecurityDeposit, - PaymentAccount paymentAccount) { + String currencyCode, + Direction direction, + Price price, + boolean useMarketBasedPrice, + double marketPriceMargin, + Coin amount, + Coin minAmount, + double buyerSecurityDeposit, + PaymentAccount paymentAccount) { Coin useDefaultTxFee = Coin.ZERO; return createOfferService.createAndGetOffer(offerId, direction, @@ -151,23 +155,16 @@ Offer editOffer(String offerId, private void placeOffer(Offer offer, double buyerSecurityDeposit, - boolean useSavingsWallet) { - // Place offer is async; we need to wait for completion. - CountDownLatch latch = new CountDownLatch(1); + boolean useSavingsWallet, + Consumer resultHandler) { openOfferManager.placeOffer(offer, buyerSecurityDeposit, useSavingsWallet, - transaction -> latch.countDown(), + resultHandler::accept, log::error); if (offer.getErrorMessage() != null) throw new IllegalStateException(offer.getErrorMessage()); - - try { - latch.await(); - } catch (InterruptedException ignored) { - // empty - } } private long priceStringToLong(String priceAsString, String currencyCode) { diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java index 39489c6c208..8b95ed2c9c8 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java @@ -68,7 +68,7 @@ public void getOffers(GetOffersRequest req, public void createOffer(CreateOfferRequest req, StreamObserver responseObserver) { try { - Offer offer = coreApi.createOffer( + coreApi.createAnPlaceOffer( req.getCurrencyCode(), req.getDirection(), req.getPrice(), @@ -77,13 +77,17 @@ public void createOffer(CreateOfferRequest req, req.getAmount(), req.getMinAmount(), req.getBuyerSecurityDeposit(), - req.getPaymentAccountId()); - OfferInfo offerInfo = toOfferInfo(offer); - CreateOfferReply reply = CreateOfferReply.newBuilder() - .setOffer(offerInfo.toProtoMessage()) - .build(); - responseObserver.onNext(reply); - responseObserver.onCompleted(); + req.getPaymentAccountId(), + 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); + CreateOfferReply reply = CreateOfferReply.newBuilder() + .setOffer(offerInfo.toProtoMessage()) + .build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + }); } catch (IllegalStateException | IllegalArgumentException cause) { var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage())); responseObserver.onError(ex); From bfcec3201f1aa54400c0c11c0f15794bcc98b755 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Mon, 5 Oct 2020 16:59:12 -0300 Subject: [PATCH 4/4] Add new getoffer(id) api method There are a number of use cases where a user may want to see a single offer instead of every offer for a currency pair on the buy or sell side. The changes are: - Add getoffer to grpc.proto - Add new method to GrpcOffersService, CoreApi, CoreOffersService - Add new method to CLI - Adjust create offer tests to use this new convenience --- .../java/bisq/apitest/method/MethodTest.java | 11 +++ .../method/offer/AbstractCreateOfferTest.java | 4 + .../offer/CreateOfferUsingFixedPriceTest.java | 67 +++++++------- ...CreateOfferUsingMarketPriceMarginTest.java | 88 +++++++++---------- cli/src/main/java/bisq/cli/CliMain.java | 17 ++++ core/src/main/java/bisq/core/api/CoreApi.java | 4 + .../java/bisq/core/api/CoreOffersService.java | 11 +++ .../bisq/daemon/grpc/GrpcOffersService.java | 13 +++ proto/src/main/proto/grpc.proto | 10 +++ 9 files changed, 147 insertions(+), 78 deletions(-) diff --git a/apitest/src/test/java/bisq/apitest/method/MethodTest.java b/apitest/src/test/java/bisq/apitest/method/MethodTest.java index b7524580999..6b1f5923db2 100644 --- a/apitest/src/test/java/bisq/apitest/method/MethodTest.java +++ b/apitest/src/test/java/bisq/apitest/method/MethodTest.java @@ -20,9 +20,11 @@ import bisq.proto.grpc.CreatePaymentAccountRequest; import bisq.proto.grpc.GetBalanceRequest; import bisq.proto.grpc.GetFundingAddressesRequest; +import bisq.proto.grpc.GetOfferRequest; import bisq.proto.grpc.GetPaymentAccountsRequest; import bisq.proto.grpc.LockWalletRequest; import bisq.proto.grpc.MarketPriceRequest; +import bisq.proto.grpc.OfferInfo; import bisq.proto.grpc.RegisterDisputeAgentRequest; import bisq.proto.grpc.RemoveWalletPasswordRequest; import bisq.proto.grpc.SetWalletPasswordRequest; @@ -80,6 +82,10 @@ protected final MarketPriceRequest createMarketPriceRequest(String currencyCode) return MarketPriceRequest.newBuilder().setCurrencyCode(currencyCode).build(); } + protected final GetOfferRequest createGetOfferRequest(String offerId) { + return GetOfferRequest.newBuilder().setId(offerId).build(); + } + // Convenience methods for calling frequently used & thoroughly tested gRPC services. protected final long getBalance(BisqAppConfig bisqAppConfig) { @@ -136,6 +142,11 @@ protected final double getMarketPrice(BisqAppConfig bisqAppConfig, String curren return grpcStubs(bisqAppConfig).priceService.getMarketPrice(req).getPrice(); } + protected final OfferInfo getOffer(BisqAppConfig bisqAppConfig, String offerId) { + var req = createGetOfferRequest(offerId); + return grpcStubs(bisqAppConfig).offersService.getOffer(req).getOffer(); + } + // Static conveniences for test methods and test case fixture setups. protected static RegisterDisputeAgentRequest createRegisterDisputeAgentRequest(String disputeAgentType) { diff --git a/apitest/src/test/java/bisq/apitest/method/offer/AbstractCreateOfferTest.java b/apitest/src/test/java/bisq/apitest/method/offer/AbstractCreateOfferTest.java index e368261e65e..9c494a7a74d 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/AbstractCreateOfferTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/AbstractCreateOfferTest.java @@ -77,6 +77,10 @@ static void startSupportingApps() { } } + protected final OfferInfo getOffer(String offerId) { + return aliceStubs.offersService.getOffer(createGetOfferRequest(offerId)).getOffer(); + } + protected final OfferInfo getMostRecentOffer(String direction, String currencyCode) { List offerInfoList = getOffersSortedByDate(direction, currencyCode); if (offerInfoList.isEmpty()) 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 0a9c16980aa..39606536558 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingFixedPriceTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingFixedPriceTest.java @@ -20,7 +20,6 @@ import bisq.core.btc.wallet.Restrictions; import bisq.proto.grpc.CreateOfferRequest; -import bisq.proto.grpc.OfferInfo; import lombok.extern.slf4j.Slf4j; @@ -66,17 +65,17 @@ public void testCreateAUDBTCBuyOfferUsingFixedPrice16000() { assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("AUD", newOffer.getCounterCurrencyCode()); - OfferInfo offer = getMostRecentOffer("buy", "aud"); - assertEquals(newOfferId, offer.getId()); - assertEquals("BUY", offer.getDirection()); - assertFalse(offer.getUseMarketBasedPrice()); - assertEquals(160000000, offer.getPrice()); - assertEquals(10000000, offer.getAmount()); - assertEquals(10000000, offer.getMinAmount()); - assertEquals(1500000, offer.getBuyerSecurityDeposit()); - assertEquals(paymentAccount.getId(), offer.getPaymentAccountId()); - assertEquals("BTC", offer.getBaseCurrencyCode()); - assertEquals("AUD", offer.getCounterCurrencyCode()); + newOffer = getOffer(newOfferId); + assertEquals(newOfferId, newOffer.getId()); + assertEquals("BUY", newOffer.getDirection()); + assertFalse(newOffer.getUseMarketBasedPrice()); + assertEquals(160000000, newOffer.getPrice()); + assertEquals(10000000, newOffer.getAmount()); + assertEquals(10000000, newOffer.getMinAmount()); + assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); + assertEquals(paymentAccount.getId(), newOffer.getPaymentAccountId()); + assertEquals("BTC", newOffer.getBaseCurrencyCode()); + assertEquals("AUD", newOffer.getCounterCurrencyCode()); } @Test @@ -107,17 +106,17 @@ public void testCreateUSDBTCBuyOfferUsingFixedPrice100001234() { assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("USD", newOffer.getCounterCurrencyCode()); - OfferInfo offer = getMostRecentOffer("buy", "usd"); - assertEquals(newOfferId, offer.getId()); - assertEquals("BUY", offer.getDirection()); - assertFalse(offer.getUseMarketBasedPrice()); - assertEquals(100001234, offer.getPrice()); - assertEquals(10000000, offer.getAmount()); - assertEquals(10000000, offer.getMinAmount()); - assertEquals(1500000, offer.getBuyerSecurityDeposit()); - assertEquals(paymentAccount.getId(), offer.getPaymentAccountId()); - assertEquals("BTC", offer.getBaseCurrencyCode()); - assertEquals("USD", offer.getCounterCurrencyCode()); + newOffer = getOffer(newOfferId); + assertEquals(newOfferId, newOffer.getId()); + assertEquals("BUY", newOffer.getDirection()); + assertFalse(newOffer.getUseMarketBasedPrice()); + assertEquals(100001234, newOffer.getPrice()); + assertEquals(10000000, newOffer.getAmount()); + assertEquals(10000000, newOffer.getMinAmount()); + assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); + assertEquals(paymentAccount.getId(), newOffer.getPaymentAccountId()); + assertEquals("BTC", newOffer.getBaseCurrencyCode()); + assertEquals("USD", newOffer.getCounterCurrencyCode()); } @Test @@ -148,16 +147,16 @@ public void testCreateEURBTCSellOfferUsingFixedPrice95001234() { assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("EUR", newOffer.getCounterCurrencyCode()); - OfferInfo offer = getMostRecentOffer("sell", "eur"); - assertEquals(newOfferId, offer.getId()); - assertEquals("SELL", offer.getDirection()); - assertFalse(offer.getUseMarketBasedPrice()); - assertEquals(95001234, offer.getPrice()); - assertEquals(10000000, offer.getAmount()); - assertEquals(10000000, offer.getMinAmount()); - assertEquals(1500000, offer.getBuyerSecurityDeposit()); - assertEquals(paymentAccount.getId(), offer.getPaymentAccountId()); - assertEquals("BTC", offer.getBaseCurrencyCode()); - assertEquals("EUR", offer.getCounterCurrencyCode()); + newOffer = getOffer(newOfferId); + assertEquals(newOfferId, newOffer.getId()); + assertEquals("SELL", newOffer.getDirection()); + assertFalse(newOffer.getUseMarketBasedPrice()); + assertEquals(95001234, newOffer.getPrice()); + assertEquals(10000000, newOffer.getAmount()); + assertEquals(10000000, newOffer.getMinAmount()); + assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); + assertEquals(paymentAccount.getId(), newOffer.getPaymentAccountId()); + assertEquals("BTC", newOffer.getBaseCurrencyCode()); + assertEquals("EUR", newOffer.getCounterCurrencyCode()); } } 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 01cdfa4d1b1..331ddbab736 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java @@ -77,18 +77,18 @@ public void testCreateUSDBTCBuyOffer5PctPriceMargin() { assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("USD", newOffer.getCounterCurrencyCode()); - OfferInfo offer = getMostRecentOffer("buy", "usd"); - assertEquals(newOfferId, offer.getId()); - assertEquals("BUY", offer.getDirection()); - assertTrue(offer.getUseMarketBasedPrice()); - assertEquals(10000000, offer.getAmount()); - assertEquals(10000000, offer.getMinAmount()); - assertEquals(1500000, offer.getBuyerSecurityDeposit()); - assertEquals(paymentAccount.getId(), offer.getPaymentAccountId()); - assertEquals("BTC", offer.getBaseCurrencyCode()); - assertEquals("USD", offer.getCounterCurrencyCode()); + newOffer = getOffer(newOfferId); + assertEquals(newOfferId, newOffer.getId()); + assertEquals("BUY", newOffer.getDirection()); + assertTrue(newOffer.getUseMarketBasedPrice()); + assertEquals(10000000, newOffer.getAmount()); + assertEquals(10000000, newOffer.getMinAmount()); + assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); + assertEquals(paymentAccount.getId(), newOffer.getPaymentAccountId()); + assertEquals("BTC", newOffer.getBaseCurrencyCode()); + assertEquals("USD", newOffer.getCounterCurrencyCode()); - assertCalculatedPriceIsCorrect(offer, priceMarginPctInput); + assertCalculatedPriceIsCorrect(newOffer, priceMarginPctInput); } @Test @@ -119,18 +119,18 @@ public void testCreateNZDBTCBuyOfferMinus2PctPriceMargin() { assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("NZD", newOffer.getCounterCurrencyCode()); - OfferInfo offer = getMostRecentOffer("buy", "nzd"); - assertEquals(newOfferId, offer.getId()); - assertEquals("BUY", offer.getDirection()); - assertTrue(offer.getUseMarketBasedPrice()); - assertEquals(10000000, offer.getAmount()); - assertEquals(10000000, offer.getMinAmount()); - assertEquals(1500000, offer.getBuyerSecurityDeposit()); - assertEquals(paymentAccount.getId(), offer.getPaymentAccountId()); - assertEquals("BTC", offer.getBaseCurrencyCode()); - assertEquals("NZD", offer.getCounterCurrencyCode()); + newOffer = getOffer(newOfferId); + assertEquals(newOfferId, newOffer.getId()); + assertEquals("BUY", newOffer.getDirection()); + assertTrue(newOffer.getUseMarketBasedPrice()); + assertEquals(10000000, newOffer.getAmount()); + assertEquals(10000000, newOffer.getMinAmount()); + assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); + assertEquals(paymentAccount.getId(), newOffer.getPaymentAccountId()); + assertEquals("BTC", newOffer.getBaseCurrencyCode()); + assertEquals("NZD", newOffer.getCounterCurrencyCode()); - assertCalculatedPriceIsCorrect(offer, priceMarginPctInput); + assertCalculatedPriceIsCorrect(newOffer, priceMarginPctInput); } @Test @@ -162,18 +162,18 @@ public void testCreateGBPBTCSellOfferMinus1Point5PctPriceMargin() { assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("GBP", newOffer.getCounterCurrencyCode()); - OfferInfo offer = getMostRecentOffer("sell", "gbp"); - assertEquals(newOfferId, offer.getId()); - assertEquals("SELL", offer.getDirection()); - assertTrue(offer.getUseMarketBasedPrice()); - assertEquals(10000000, offer.getAmount()); - assertEquals(10000000, offer.getMinAmount()); - assertEquals(1500000, offer.getBuyerSecurityDeposit()); - assertEquals(paymentAccount.getId(), offer.getPaymentAccountId()); - assertEquals("BTC", offer.getBaseCurrencyCode()); - assertEquals("GBP", offer.getCounterCurrencyCode()); + newOffer = getOffer(newOfferId); + assertEquals(newOfferId, newOffer.getId()); + assertEquals("SELL", newOffer.getDirection()); + assertTrue(newOffer.getUseMarketBasedPrice()); + assertEquals(10000000, newOffer.getAmount()); + assertEquals(10000000, newOffer.getMinAmount()); + assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); + assertEquals(paymentAccount.getId(), newOffer.getPaymentAccountId()); + assertEquals("BTC", newOffer.getBaseCurrencyCode()); + assertEquals("GBP", newOffer.getCounterCurrencyCode()); - assertCalculatedPriceIsCorrect(offer, priceMarginPctInput); + assertCalculatedPriceIsCorrect(newOffer, priceMarginPctInput); } @Test @@ -205,18 +205,18 @@ public void testCreateBRLBTCSellOffer6Point55PctPriceMargin() { assertEquals("BTC", newOffer.getBaseCurrencyCode()); assertEquals("BRL", newOffer.getCounterCurrencyCode()); - OfferInfo offer = getMostRecentOffer("sell", "brl"); - assertEquals(newOfferId, offer.getId()); - assertEquals("SELL", offer.getDirection()); - assertTrue(offer.getUseMarketBasedPrice()); - assertEquals(10000000, offer.getAmount()); - assertEquals(10000000, offer.getMinAmount()); - assertEquals(1500000, offer.getBuyerSecurityDeposit()); - assertEquals(paymentAccount.getId(), offer.getPaymentAccountId()); - assertEquals("BTC", offer.getBaseCurrencyCode()); - assertEquals("BRL", offer.getCounterCurrencyCode()); + newOffer = getOffer(newOfferId); + assertEquals(newOfferId, newOffer.getId()); + assertEquals("SELL", newOffer.getDirection()); + assertTrue(newOffer.getUseMarketBasedPrice()); + assertEquals(10000000, newOffer.getAmount()); + assertEquals(10000000, newOffer.getMinAmount()); + assertEquals(1500000, newOffer.getBuyerSecurityDeposit()); + assertEquals(paymentAccount.getId(), newOffer.getPaymentAccountId()); + assertEquals("BTC", newOffer.getBaseCurrencyCode()); + assertEquals("BRL", newOffer.getCounterCurrencyCode()); - assertCalculatedPriceIsCorrect(offer, priceMarginPctInput); + assertCalculatedPriceIsCorrect(newOffer, priceMarginPctInput); } private void assertCalculatedPriceIsCorrect(OfferInfo offer, double priceMarginPctInput) { diff --git a/cli/src/main/java/bisq/cli/CliMain.java b/cli/src/main/java/bisq/cli/CliMain.java index 1f370c3471f..edee8f54eb3 100644 --- a/cli/src/main/java/bisq/cli/CliMain.java +++ b/cli/src/main/java/bisq/cli/CliMain.java @@ -22,6 +22,7 @@ import bisq.proto.grpc.GetAddressBalanceRequest; import bisq.proto.grpc.GetBalanceRequest; import bisq.proto.grpc.GetFundingAddressesRequest; +import bisq.proto.grpc.GetOfferRequest; import bisq.proto.grpc.GetOffersRequest; import bisq.proto.grpc.GetPaymentAccountsRequest; import bisq.proto.grpc.GetVersionRequest; @@ -67,6 +68,7 @@ public class CliMain { private enum Method { createoffer, + getoffer, getoffers, createpaymentacct, getpaymentaccts, @@ -223,6 +225,20 @@ public static void run(String[] args) { out.println(formatOfferTable(singletonList(reply.getOffer()), currencyCode)); return; } + case getoffer: { + if (nonOptionArgs.size() < 2) + throw new IllegalArgumentException("incorrect parameter count," + + " expecting offer id"); + + var offerId = nonOptionArgs.get(1); + var request = GetOfferRequest.newBuilder() + .setId(offerId) + .build(); + var reply = offersService.getOffer(request); + out.println(formatOfferTable(singletonList(reply.getOffer()), + reply.getOffer().getCounterCurrencyCode())); + return; + } case getoffers: { if (nonOptionArgs.size() < 3) throw new IllegalArgumentException("incorrect parameter count," @@ -364,6 +380,7 @@ private static void printHelp(OptionParser parser, PrintStream stream) { stream.format(rowFormat, "", "amount (btc), min amount, use mkt based price, \\", ""); stream.format(rowFormat, "", "fixed price (btc) | mkt price margin (%), \\", ""); stream.format(rowFormat, "", "security deposit (%)", ""); + stream.format(rowFormat, "getoffer", "offer id", "Get current offer with id"); stream.format(rowFormat, "getoffers", "buy | sell, currency code", "Get current offers"); stream.format(rowFormat, "createpaymentacct", "account name, account number, currency code", "Create PerfectMoney dummy account"); stream.format(rowFormat, "getpaymentaccts", "", "Get user payment accounts"); diff --git a/core/src/main/java/bisq/core/api/CoreApi.java b/core/src/main/java/bisq/core/api/CoreApi.java index 8d298d222c6..1ead8458b09 100644 --- a/core/src/main/java/bisq/core/api/CoreApi.java +++ b/core/src/main/java/bisq/core/api/CoreApi.java @@ -86,6 +86,10 @@ public void registerDisputeAgent(String disputeAgentType, String registrationKey // Offers /////////////////////////////////////////////////////////////////////////////////////////// + public Offer getOffer(String id) { + return coreOffersService.getOffer(id); + } + public List getOffers(String direction, String currencyCode) { return coreOffersService.getOffers(direction, currencyCode); } diff --git a/core/src/main/java/bisq/core/api/CoreOffersService.java b/core/src/main/java/bisq/core/api/CoreOffersService.java index f94db1b95a9..3ba7c34b17f 100644 --- a/core/src/main/java/bisq/core/api/CoreOffersService.java +++ b/core/src/main/java/bisq/core/api/CoreOffersService.java @@ -47,6 +47,7 @@ import static bisq.core.locale.CurrencyUtil.isCryptoCurrency; import static bisq.core.offer.OfferPayload.Direction; import static bisq.core.offer.OfferPayload.Direction.BUY; +import static java.lang.String.format; @Slf4j class CoreOffersService { @@ -67,6 +68,16 @@ public CoreOffersService(CreateOfferService createOfferService, this.user = user; } + Offer getOffer(String id) { + List offers = offerBookService.getOffers().stream() + .filter(o -> o.getId().equals(id)) + .collect(Collectors.toList()); + if (offers.isEmpty()) + throw new IllegalArgumentException(format("offer with id '%s' not found", id)); + else + return offers.get(0); + } + List getOffers(String direction, String currencyCode) { List offers = offerBookService.getOffers().stream() .filter(o -> { diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java index 8b95ed2c9c8..5ac4bff3b58 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java @@ -23,6 +23,8 @@ import bisq.proto.grpc.CreateOfferReply; import bisq.proto.grpc.CreateOfferRequest; +import bisq.proto.grpc.GetOfferReply; +import bisq.proto.grpc.GetOfferRequest; import bisq.proto.grpc.GetOffersReply; import bisq.proto.grpc.GetOffersRequest; import bisq.proto.grpc.OffersGrpc; @@ -49,6 +51,17 @@ public GrpcOffersService(CoreApi coreApi) { this.coreApi = coreApi; } + @Override + public void getOffer(GetOfferRequest req, + StreamObserver responseObserver) { + Offer offer = coreApi.getOffer(req.getId()); + var reply = GetOfferReply.newBuilder() + .setOffer(toOfferInfo(offer).toProtoMessage()) + .build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + @Override public void getOffers(GetOffersRequest req, StreamObserver responseObserver) { diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index 49f47e156ec..a5227bd1b1b 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -45,12 +45,22 @@ message RegisterDisputeAgentReply { /////////////////////////////////////////////////////////////////////////////////////////// service Offers { + rpc GetOffer (GetOfferRequest) returns (GetOfferReply) { + } rpc GetOffers (GetOffersRequest) returns (GetOffersReply) { } rpc CreateOffer (CreateOfferRequest) returns (CreateOfferReply) { } } +message GetOfferRequest { + string id = 1; +} + +message GetOfferReply { + OfferInfo offer = 1; +} + message GetOffersRequest { string direction = 1; string currencyCode = 2;