diff --git a/apitest/src/test/java/bisq/apitest/method/MethodTest.java b/apitest/src/test/java/bisq/apitest/method/MethodTest.java index 16a3e1da6d9..b03f00da356 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; @@ -82,6 +84,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) { @@ -138,6 +144,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/apitest/src/test/java/bisq/apitest/method/offer/ValidateCreateOfferTest.java b/apitest/src/test/java/bisq/apitest/method/offer/ValidateCreateOfferTest.java index 6a7d1c67770..c51b64a6a0f 100644 --- a/apitest/src/test/java/bisq/apitest/method/offer/ValidateCreateOfferTest.java +++ b/apitest/src/test/java/bisq/apitest/method/offer/ValidateCreateOfferTest.java @@ -53,6 +53,7 @@ public void testAmtTooLargeShouldThrowException() { .setPrice("10000.0000") .setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()) .build(); + @SuppressWarnings("ResultOfMethodCallIgnored") Throwable exception = assertThrows(StatusRuntimeException.class, () -> aliceStubs.offersService.createOffer(req).getOffer()); assertEquals("UNKNOWN: An error occurred at task: ValidateOffer", diff --git a/cli/src/main/java/bisq/cli/CliMain.java b/cli/src/main/java/bisq/cli/CliMain.java index 1f370c3471f..9b73e560283 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,19 @@ 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 +379,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 e944265a4b7..7fe651c68be 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 ded8287ea98..da07677f1b2 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,13 @@ public CoreOffersService(CreateOfferService createOfferService, this.user = user; } + Offer getOffer(String id) { + return offerBookService.getOffers().stream() + .filter(o -> o.getId().equals(id)) + .findAny().orElseThrow(() -> + new IllegalStateException(format("offer with id '%s' not found", id))); + } + 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..2cee16b601d 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,23 @@ public GrpcOffersService(CoreApi coreApi) { this.coreApi = coreApi; } + @Override + public void getOffer(GetOfferRequest req, + StreamObserver responseObserver) { + try { + Offer offer = coreApi.getOffer(req.getId()); + var reply = GetOfferReply.newBuilder() + .setOffer(toOfferInfo(offer).toProtoMessage()) + .build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } catch (IllegalStateException | IllegalArgumentException cause) { + var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage())); + responseObserver.onError(ex); + throw ex; + } + } + @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..ca84e3ff714 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -45,12 +45,21 @@ 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;