diff --git a/apitest/scripts/mainnet-test.sh b/apitest/scripts/mainnet-test.sh index bfab9fc3b5f..5ade2b55f41 100755 --- a/apitest/scripts/mainnet-test.sh +++ b/apitest/scripts/mainnet-test.sh @@ -45,17 +45,19 @@ } @test "test getversion call with quoted password" { + load 'version-parser' run ./bisq-cli --password="xyz" getversion [ "$status" -eq 0 ] echo "actual output: $output" >&2 - [ "$output" = "1.3.9" ] + [ "$output" = "$CURRENT_VERSION" ] } @test "test getversion" { + load 'version-parser' run ./bisq-cli --password=xyz getversion [ "$status" -eq 0 ] echo "actual output: $output" >&2 - [ "$output" = "1.3.9" ] + [ "$output" = "$CURRENT_VERSION" ] } @test "test setwalletpassword \"a b c\"" { diff --git a/apitest/scripts/version-parser.bash b/apitest/scripts/version-parser.bash new file mode 100755 index 00000000000..ba7f2c2d0f7 --- /dev/null +++ b/apitest/scripts/version-parser.bash @@ -0,0 +1,5 @@ +#!/bin/bash + +# Bats helper script for parsing current version from Version.java. + +export CURRENT_VERSION=$(grep "String VERSION =" common/src/main/java/bisq/common/app/Version.java | sed 's/[^0-9.]*//g') diff --git a/apitest/src/test/java/bisq/apitest/method/CreateOfferTest.java b/apitest/src/test/java/bisq/apitest/method/CreateOfferTest.java new file mode 100644 index 00000000000..233daa5a780 --- /dev/null +++ b/apitest/src/test/java/bisq/apitest/method/CreateOfferTest.java @@ -0,0 +1,112 @@ +/* + * 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.apitest.method; + +import bisq.core.btc.wallet.Restrictions; + +import bisq.proto.grpc.CreateOfferRequest; +import bisq.proto.grpc.GetOffersRequest; +import bisq.proto.grpc.OfferInfo; + +import lombok.extern.slf4j.Slf4j; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +import static bisq.apitest.Scaffold.BitcoinCoreApp.bitcoind; +import static bisq.apitest.config.BisqAppConfig.alicedaemon; +import static bisq.apitest.config.BisqAppConfig.arbdaemon; +import static bisq.apitest.config.BisqAppConfig.seednode; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation; + + +@Slf4j +@TestMethodOrder(OrderAnnotation.class) +public class CreateOfferTest extends MethodTest { + + @BeforeAll + public static void setUp() { + try { + // setUpScaffold(new String[]{"--supportingApps", "bitcoind,seednode,arbdaemon,alicedaemon", "--enableBisqDebugging", "true"}); + setUpScaffold(bitcoind, seednode, arbdaemon, alicedaemon); + + // Generate 1 regtest block for alice's wallet to show 10 BTC balance, + // and give alicedaemon time to parse the new block. + bitcoinCli.generateBlocks(1); + MILLISECONDS.sleep(1500); + } catch (Exception ex) { + fail(ex); + } + } + + @Test + @Order(1) + public void testCreateBuyOffer() { + var paymentAccount = getDefaultPerfectDummyPaymentAccount(alicedaemon); + var req = CreateOfferRequest.newBuilder() + .setCurrencyCode("USD") + .setDirection("BUY") + .setPrice(0) + .setUseMarketBasedPrice(true) + .setMarketPriceMargin(0.00) + .setAmount(10000000) + .setMinAmount(10000000) + .setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()) + .setPaymentAccountId(paymentAccount.getId()) + .build(); + var newOffer = grpcStubs(alicedaemon).offersService.createOffer(req).getOffer(); + 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()); + } + + @Test + @Order(2) + public void testGetNewBuyOffer() { + var req = GetOffersRequest.newBuilder().setDirection("BUY").setCurrencyCode("USD").build(); + var reply = grpcStubs(alicedaemon).offersService.getOffers(req); + + assertEquals(1, reply.getOffersCount()); + OfferInfo offer = reply.getOffersList().get(0); + assertEquals("BUY", offer.getDirection()); + assertTrue(offer.getUseMarketBasedPrice()); + assertEquals(10000000, offer.getAmount()); + assertEquals(10000000, offer.getMinAmount()); + assertEquals(1500000, offer.getBuyerSecurityDeposit()); + assertEquals("", offer.getPaymentAccountId()); + assertEquals("BTC", offer.getBaseCurrencyCode()); + assertEquals("USD", offer.getCounterCurrencyCode()); + } + + @AfterAll + public static void tearDown() { + tearDownScaffold(); + } +} diff --git a/apitest/src/test/java/bisq/apitest/method/CreatePaymentAccountTest.java b/apitest/src/test/java/bisq/apitest/method/CreatePaymentAccountTest.java new file mode 100644 index 00000000000..661205c74d3 --- /dev/null +++ b/apitest/src/test/java/bisq/apitest/method/CreatePaymentAccountTest.java @@ -0,0 +1,98 @@ +/* + * 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.apitest.method; + +import bisq.proto.grpc.GetPaymentAccountsRequest; + +import protobuf.PaymentAccount; +import protobuf.PerfectMoneyAccountPayload; + +import java.util.List; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +import static bisq.apitest.Scaffold.BitcoinCoreApp.bitcoind; +import static bisq.apitest.config.BisqAppConfig.alicedaemon; +import static java.util.Comparator.comparing; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation; + + +@Slf4j +@TestMethodOrder(OrderAnnotation.class) +public class CreatePaymentAccountTest extends MethodTest { + + static final String PERFECT_MONEY_ACCT_NAME = "Perfect Money USD"; + static final String PERFECT_MONEY_ACCT_NUMBER = "0123456789"; + + @BeforeAll + public static void setUp() { + try { + setUpScaffold(bitcoind, alicedaemon); + } catch (Exception ex) { + fail(ex); + } + } + + @Test + @Order(1) + public void testCreatePerfectMoneyUSDPaymentAccount() { + var perfectMoneyPaymentAccountRequest = createCreatePerfectMoneyPaymentAccountRequest( + PERFECT_MONEY_ACCT_NAME, + PERFECT_MONEY_ACCT_NUMBER, + "USD"); + //noinspection ResultOfMethodCallIgnored + grpcStubs(alicedaemon).paymentAccountsService.createPaymentAccount(perfectMoneyPaymentAccountRequest); + + var getPaymentAccountsRequest = GetPaymentAccountsRequest.newBuilder().build(); + var reply = grpcStubs(alicedaemon).paymentAccountsService.getPaymentAccounts(getPaymentAccountsRequest); + + // The daemon is running against the regtest/dao setup files, and was set up with + // two dummy accounts ("PerfectMoney dummy", "ETH dummy") before any tests ran. + // We just added 1 test account, making 3 total. + assertEquals(3, reply.getPaymentAccountsCount()); + + // Sort the returned list by creation date; the last item in the sorted + // list will be the payment acct we just created. + List paymentAccountList = reply.getPaymentAccountsList().stream() + .sorted(comparing(PaymentAccount::getCreationDate)) + .collect(Collectors.toList()); + PaymentAccount paymentAccount = paymentAccountList.get(2); + PerfectMoneyAccountPayload perfectMoneyAccount = paymentAccount + .getPaymentAccountPayload() + .getPerfectMoneyAccountPayload(); + + assertEquals(PERFECT_MONEY_ACCT_NAME, paymentAccount.getAccountName()); + assertEquals("USD", + paymentAccount.getSelectedTradeCurrency().getFiatCurrency().getCurrency().getCurrencyCode()); + assertEquals(PERFECT_MONEY_ACCT_NUMBER, perfectMoneyAccount.getAccountNr()); + } + + @AfterAll + public static void tearDown() { + tearDownScaffold(); + } +} diff --git a/apitest/src/test/java/bisq/apitest/method/MethodTest.java b/apitest/src/test/java/bisq/apitest/method/MethodTest.java index 3437ac59c94..3f9f2cec1c7 100644 --- a/apitest/src/test/java/bisq/apitest/method/MethodTest.java +++ b/apitest/src/test/java/bisq/apitest/method/MethodTest.java @@ -17,15 +17,26 @@ package bisq.apitest.method; +import bisq.proto.grpc.CreatePaymentAccountRequest; import bisq.proto.grpc.GetBalanceRequest; import bisq.proto.grpc.GetFundingAddressesRequest; +import bisq.proto.grpc.GetPaymentAccountsRequest; import bisq.proto.grpc.LockWalletRequest; import bisq.proto.grpc.RegisterDisputeAgentRequest; import bisq.proto.grpc.RemoveWalletPasswordRequest; import bisq.proto.grpc.SetWalletPasswordRequest; import bisq.proto.grpc.UnlockWalletRequest; +import protobuf.PaymentAccount; + +import java.util.stream.Collectors; + import static bisq.common.app.DevEnv.DEV_PRIVILEGE_PRIV_KEY; +import static bisq.core.payment.payload.PaymentMethod.PERFECT_MONEY; +import static bisq.core.support.dispute.agent.DisputeAgent.DisputeAgentType.MEDIATOR; +import static bisq.core.support.dispute.agent.DisputeAgent.DisputeAgentType.REFUNDAGENT; +import static java.util.Comparator.comparing; +import static org.junit.jupiter.api.Assertions.assertEquals; @@ -64,12 +75,6 @@ protected final GetFundingAddressesRequest createGetFundingAddressesRequest() { return GetFundingAddressesRequest.newBuilder().build(); } - protected final RegisterDisputeAgentRequest createRegisterDisputeAgentRequest(String disputeAgentType) { - return RegisterDisputeAgentRequest.newBuilder() - .setDisputeAgentType(disputeAgentType) - .setRegistrationKey(DEV_PRIVILEGE_PRIV_KEY).build(); - } - // Convenience methods for calling frequently used & thoroughly tested gRPC services. protected final long getBalance(BisqAppConfig bisqAppConfig) { @@ -96,4 +101,43 @@ protected final String getUnusedBtcAddress(BisqAppConfig bisqAppConfig) { .get() .getAddress(); } + + protected final CreatePaymentAccountRequest createCreatePerfectMoneyPaymentAccountRequest( + String accountName, + String accountNumber, + String currencyCode) { + return CreatePaymentAccountRequest.newBuilder() + .setPaymentMethodId(PERFECT_MONEY.getId()) + .setAccountName(accountName) + .setAccountNumber(accountNumber) + .setCurrencyCode(currencyCode) + .build(); + } + + protected final PaymentAccount getDefaultPerfectDummyPaymentAccount(BisqAppConfig bisqAppConfig) { + var getPaymentAccountsRequest = GetPaymentAccountsRequest.newBuilder().build(); + var paymentAccountsService = grpcStubs(bisqAppConfig).paymentAccountsService; + PaymentAccount paymentAccount = paymentAccountsService.getPaymentAccounts(getPaymentAccountsRequest) + .getPaymentAccountsList() + .stream() + .sorted(comparing(PaymentAccount::getCreationDate)) + .collect(Collectors.toList()).get(0); + assertEquals("PerfectMoney dummy", paymentAccount.getAccountName()); + return paymentAccount; + } + + // Static conveniences for test methods and test case fixture setups. + + protected static RegisterDisputeAgentRequest createRegisterDisputeAgentRequest(String disputeAgentType) { + return RegisterDisputeAgentRequest.newBuilder() + .setDisputeAgentType(disputeAgentType.toLowerCase()) + .setRegistrationKey(DEV_PRIVILEGE_PRIV_KEY).build(); + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + protected static void registerDisputeAgents(BisqAppConfig bisqAppConfig) { + var disputeAgentsService = grpcStubs(bisqAppConfig).disputeAgentsService; + disputeAgentsService.registerDisputeAgent(createRegisterDisputeAgentRequest(MEDIATOR.name())); + disputeAgentsService.registerDisputeAgent(createRegisterDisputeAgentRequest(REFUNDAGENT.name())); + } } diff --git a/apitest/src/test/java/bisq/apitest/method/RegisterDisputeAgentsTest.java b/apitest/src/test/java/bisq/apitest/method/RegisterDisputeAgentsTest.java index e09de2b061e..de6c195f961 100644 --- a/apitest/src/test/java/bisq/apitest/method/RegisterDisputeAgentsTest.java +++ b/apitest/src/test/java/bisq/apitest/method/RegisterDisputeAgentsTest.java @@ -33,6 +33,9 @@ import static bisq.apitest.config.BisqAppConfig.arbdaemon; import static bisq.apitest.config.BisqAppConfig.seednode; import static bisq.common.app.DevEnv.DEV_PRIVILEGE_PRIV_KEY; +import static bisq.core.support.dispute.agent.DisputeAgent.DisputeAgentType.ARBITRATOR; +import static bisq.core.support.dispute.agent.DisputeAgent.DisputeAgentType.MEDIATOR; +import static bisq.core.support.dispute.agent.DisputeAgent.DisputeAgentType.REFUNDAGENT; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; @@ -44,10 +47,6 @@ @TestMethodOrder(OrderAnnotation.class) public class RegisterDisputeAgentsTest extends MethodTest { - private static final String ARBITRATOR = "arbitrator"; - private static final String MEDIATOR = "mediator"; - private static final String REFUNDAGENT = "refundagent"; - @BeforeAll public static void setUp() { try { @@ -61,7 +60,7 @@ public static void setUp() { @Order(1) public void testRegisterArbitratorShouldThrowException() { var req = - createRegisterDisputeAgentRequest(ARBITRATOR); + createRegisterDisputeAgentRequest(ARBITRATOR.name()); Throwable exception = assertThrows(StatusRuntimeException.class, () -> grpcStubs(arbdaemon).disputeAgentsService.registerDisputeAgent(req)); assertEquals("INVALID_ARGUMENT: arbitrators must be registered in a Bisq UI", @@ -83,7 +82,7 @@ public void testInvalidDisputeAgentTypeArgShouldThrowException() { @Order(3) public void testInvalidRegistrationKeyArgShouldThrowException() { var req = RegisterDisputeAgentRequest.newBuilder() - .setDisputeAgentType(REFUNDAGENT) + .setDisputeAgentType(REFUNDAGENT.name().toLowerCase()) .setRegistrationKey("invalid" + DEV_PRIVILEGE_PRIV_KEY).build(); Throwable exception = assertThrows(StatusRuntimeException.class, () -> grpcStubs(arbdaemon).disputeAgentsService.registerDisputeAgent(req)); @@ -95,7 +94,7 @@ public void testInvalidRegistrationKeyArgShouldThrowException() { @Order(4) public void testRegisterMediator() { var req = - createRegisterDisputeAgentRequest(MEDIATOR); + createRegisterDisputeAgentRequest(MEDIATOR.name()); grpcStubs(arbdaemon).disputeAgentsService.registerDisputeAgent(req); } @@ -103,7 +102,7 @@ public void testRegisterMediator() { @Order(5) public void testRegisterRefundAgent() { var req = - createRegisterDisputeAgentRequest(REFUNDAGENT); + createRegisterDisputeAgentRequest(REFUNDAGENT.name()); grpcStubs(arbdaemon).disputeAgentsService.registerDisputeAgent(req); } diff --git a/cli/src/main/java/bisq/cli/CliMain.java b/cli/src/main/java/bisq/cli/CliMain.java index 341420666d2..1de508a15fc 100644 --- a/cli/src/main/java/bisq/cli/CliMain.java +++ b/cli/src/main/java/bisq/cli/CliMain.java @@ -60,6 +60,7 @@ public class CliMain { private enum Method { + createoffer, getoffers, createpaymentacct, getpaymentaccts, @@ -167,6 +168,11 @@ public static void run(String[] args) { out.println(formatAddressBalanceTbl(reply.getAddressBalanceInfoList())); return; } + case createoffer: { + // TODO + out.println("offer created"); + return; + } case getoffers: { if (nonOptionArgs.size() < 3) throw new IllegalArgumentException("incorrect parameter count," @@ -303,6 +309,7 @@ private static void printHelp(OptionParser parser, PrintStream stream) { stream.format("%-22s%-50s%s%n", "getbalance", "", "Get server wallet balance"); stream.format("%-22s%-50s%s%n", "getaddressbalance", "address", "Get server wallet address balance"); stream.format("%-22s%-50s%s%n", "getfundingaddresses", "", "Get BTC funding addresses"); + stream.format("%-22s%-50s%s%n", "createoffer", "", "Create and place an offer"); stream.format("%-22s%-50s%s%n", "getoffers", "buy | sell, fiat currency code", "Get current offers"); stream.format("%-22s%-50s%s%n", "createpaymentacct", "account name, account number, currency code", "Create PerfectMoney dummy account"); stream.format("%-22s%-50s%s%n", "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 81af1fae0f3..27f234a225c 100644 --- a/core/src/main/java/bisq/core/api/CoreApi.java +++ b/core/src/main/java/bisq/core/api/CoreApi.java @@ -87,17 +87,17 @@ public List getOffers(String direction, String fiatCurrencyCode) { return coreOffersService.getOffers(direction, fiatCurrencyCode); } - public void createOffer(String currencyCode, - String directionAsString, - long priceAsLong, - boolean useMarketBasedPrice, - double marketPriceMargin, - long amountAsLong, - long minAmountAsLong, - double buyerSecurityDeposit, - String paymentAccountId, - TransactionResultHandler resultHandler) { - coreOffersService.createOffer(currencyCode, + public Offer createOffer(String currencyCode, + String directionAsString, + long priceAsLong, + boolean useMarketBasedPrice, + double marketPriceMargin, + long amountAsLong, + long minAmountAsLong, + double buyerSecurityDeposit, + String paymentAccountId, + TransactionResultHandler resultHandler) { + return coreOffersService.createOffer(currencyCode, directionAsString, priceAsLong, useMarketBasedPrice, @@ -109,19 +109,19 @@ public void createOffer(String currencyCode, resultHandler); } - public void createOffer(String offerId, - String currencyCode, - OfferPayload.Direction direction, - Price price, - boolean useMarketBasedPrice, - double marketPriceMargin, - Coin amount, - Coin minAmount, - double buyerSecurityDeposit, - PaymentAccount paymentAccount, - boolean useSavingsWallet, - TransactionResultHandler resultHandler) { - coreOffersService.createOffer(offerId, + public Offer createOffer(String offerId, + String currencyCode, + OfferPayload.Direction direction, + Price price, + boolean useMarketBasedPrice, + double marketPriceMargin, + Coin amount, + Coin minAmount, + double buyerSecurityDeposit, + PaymentAccount paymentAccount, + boolean useSavingsWallet, + TransactionResultHandler resultHandler) { + return coreOffersService.createOffer(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 61ee0e006db..a1f60e4c760 100644 --- a/core/src/main/java/bisq/core/api/CoreOffersService.java +++ b/core/src/main/java/bisq/core/api/CoreOffersService.java @@ -77,16 +77,16 @@ List getOffers(String direction, String fiatCurrencyCode) { return offers; } - void createOffer(String currencyCode, - String directionAsString, - long priceAsLong, - boolean useMarketBasedPrice, - double marketPriceMargin, - long amountAsLong, - long minAmountAsLong, - double buyerSecurityDeposit, - String paymentAccountId, - TransactionResultHandler resultHandler) { + Offer createOffer(String currencyCode, + String directionAsString, + long priceAsLong, + boolean useMarketBasedPrice, + double marketPriceMargin, + long amountAsLong, + long minAmountAsLong, + double buyerSecurityDeposit, + String paymentAccountId, + TransactionResultHandler resultHandler) { String offerId = createOfferService.getRandomOfferId(); OfferPayload.Direction direction = OfferPayload.Direction.valueOf(directionAsString); Price price = Price.valueOf(currencyCode, priceAsLong); @@ -97,7 +97,7 @@ void createOffer(String currencyCode, boolean useSavingsWallet = true; //noinspection ConstantConditions - createOffer(offerId, + return createAndPlaceOffer(offerId, currencyCode, direction, price, @@ -111,19 +111,56 @@ void createOffer(String currencyCode, resultHandler); } - void createOffer(String offerId, - String currencyCode, - OfferPayload.Direction direction, - Price price, - boolean useMarketBasedPrice, - double marketPriceMargin, - Coin amount, - Coin minAmount, - double buyerSecurityDeposit, - PaymentAccount paymentAccount, - boolean useSavingsWallet, - TransactionResultHandler resultHandler) { + Offer createAndPlaceOffer(String offerId, + String currencyCode, + OfferPayload.Direction direction, + Price price, + boolean useMarketBasedPrice, + double marketPriceMargin, + Coin amount, + Coin minAmount, + double buyerSecurityDeposit, + PaymentAccount paymentAccount, + boolean useSavingsWallet, + TransactionResultHandler resultHandler) { Coin useDefaultTxFee = Coin.ZERO; + + Offer offer = createOfferService.createAndGetOffer(offerId, + direction, + currencyCode, + amount, + minAmount, + price, + useDefaultTxFee, + useMarketBasedPrice, + marketPriceMargin, + buyerSecurityDeposit, + paymentAccount); + + // TODO give user chance to examine offer before placing it (placeoffer) + openOfferManager.placeOffer(offer, + buyerSecurityDeposit, + useSavingsWallet, + resultHandler, + log::error); + + return offer; + } + + Offer createOffer(String offerId, + String currencyCode, + OfferPayload.Direction direction, + Price price, + boolean useMarketBasedPrice, + double marketPriceMargin, + Coin amount, + Coin minAmount, + double buyerSecurityDeposit, + PaymentAccount paymentAccount, + boolean useSavingsWallet, + TransactionResultHandler resultHandler) { + Coin useDefaultTxFee = Coin.ZERO; + Offer offer = createOfferService.createAndGetOffer(offerId, direction, currencyCode, @@ -141,5 +178,7 @@ void createOffer(String offerId, useSavingsWallet, resultHandler, log::error); + + return offer; } } diff --git a/core/src/main/java/bisq/core/api/CorePaymentAccountsService.java b/core/src/main/java/bisq/core/api/CorePaymentAccountsService.java index b49c57a23f9..a202b0dbdb4 100644 --- a/core/src/main/java/bisq/core/api/CorePaymentAccountsService.java +++ b/core/src/main/java/bisq/core/api/CorePaymentAccountsService.java @@ -62,8 +62,6 @@ void createPaymentAccount(String paymentMethodId, accountNumber, currencyCode); - // TODO not sure if there is more to do at account creation. - // Need to check all the flow when its created from UI. user.addPaymentAccountIfNotExists(paymentAccount); // Don't do this on mainnet until thoroughly tested. diff --git a/core/src/main/java/bisq/core/support/dispute/agent/DisputeAgent.java b/core/src/main/java/bisq/core/support/dispute/agent/DisputeAgent.java index aa583d04de8..acd7d5367ee 100644 --- a/core/src/main/java/bisq/core/support/dispute/agent/DisputeAgent.java +++ b/core/src/main/java/bisq/core/support/dispute/agent/DisputeAgent.java @@ -43,6 +43,12 @@ public abstract class DisputeAgent implements ProtectedStoragePayload, ExpirablePayload { public static final long TTL = TimeUnit.DAYS.toMillis(10); + public enum DisputeAgentType { + ARBITRATOR, + MEDIATOR, + REFUNDAGENT + } + protected final NodeAddress nodeAddress; protected final PubKeyRing pubKeyRing; protected final List languageCodes; diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java index b8b00f6d123..fd9e41a772b 100644 --- a/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java +++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcOffersService.java @@ -19,6 +19,7 @@ import bisq.core.api.CoreApi; import bisq.core.api.model.OfferInfo; +import bisq.core.offer.Offer; import bisq.core.trade.handlers.TransactionResultHandler; import bisq.proto.grpc.CreateOfferReply; @@ -27,11 +28,14 @@ import bisq.proto.grpc.GetOffersRequest; import bisq.proto.grpc.OffersGrpc; +import io.grpc.Status; +import io.grpc.StatusRuntimeException; import io.grpc.stub.StreamObserver; import javax.inject.Inject; import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; @@ -86,21 +90,53 @@ public void getOffers(GetOffersRequest req, @Override public void createOffer(CreateOfferRequest req, StreamObserver responseObserver) { - TransactionResultHandler resultHandler = transaction -> { - CreateOfferReply reply = CreateOfferReply.newBuilder().setResult(true).build(); + CountDownLatch latch = new CountDownLatch(1); + try { + TransactionResultHandler resultHandler = transaction -> { + latch.countDown(); + }; + Offer offer = coreApi.createOffer( + req.getCurrencyCode(), + req.getDirection(), + req.getPrice(), + req.getUseMarketBasedPrice(), + req.getMarketPriceMargin(), + req.getAmount(), + req.getMinAmount(), + req.getBuyerSecurityDeposit(), + req.getPaymentAccountId(), + resultHandler); + try { + latch.await(); + } catch (InterruptedException ignored) { + // empty + } + + OfferInfo offerInfo = new OfferInfo.OfferInfoBuilder() + .withId(offer.getId()) + .withDirection(offer.getDirection().name()) + .withPrice(offer.getPrice().getValue()) + .withUseMarketBasedPrice(offer.isUseMarketBasedPrice()) + .withMarketPriceMargin(offer.getMarketPriceMargin()) + .withAmount(offer.getAmount().value) + .withMinAmount(offer.getMinAmount().value) + .withVolume(offer.getVolume().getValue()) + .withMinVolume(offer.getMinVolume().getValue()) + .withBuyerSecurityDeposit(offer.getBuyerSecurityDeposit().value) + .withPaymentAccountId(offer.getMakerPaymentAccountId()) + .withPaymentMethodId(offer.getPaymentMethod().getId()) + .withPaymentMethodShortName(offer.getPaymentMethod().getShortName()) + .withBaseCurrencyCode(offer.getOfferPayload().getBaseCurrencyCode()) + .withCounterCurrencyCode(offer.getOfferPayload().getCounterCurrencyCode()) + .withDate(offer.getDate().getTime()) + .build(); + CreateOfferReply reply = CreateOfferReply.newBuilder().setOffer(offerInfo.toProtoMessage()).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); - }; - coreApi.createOffer( - req.getCurrencyCode(), - req.getDirection(), - req.getPrice(), - req.getUseMarketBasedPrice(), - req.getMarketPriceMargin(), - req.getAmount(), - req.getMinAmount(), - req.getBuyerSecurityDeposit(), - req.getPaymentAccountId(), - resultHandler); + } catch (IllegalStateException | IllegalArgumentException cause) { + var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage())); + responseObserver.onError(ex); + throw ex; + } } } diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index 21c59b8643d..c0477fb5fbc 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -73,7 +73,7 @@ message CreateOfferRequest { } message CreateOfferReply { - bool result = 1; + OfferInfo offer = 1; } message OfferInfo { @@ -107,7 +107,7 @@ service PaymentAccounts { } message CreatePaymentAccountRequest { -string paymentMethodId = 1; + string paymentMethodId = 1; string accountName = 2; string accountNumber = 3; // TODO Support all currencies. Maybe add a repeated and if only one is used its a singletonList.