From 9132722bbf38a7df0136b8f8c5087593125fe2f4 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 14:45:21 -0300 Subject: [PATCH 01/14] Replace hardcoded version with Version.java value Bats version check tests now use a bash script for parsing the value from the Bisq class file, and these test cases no longer need to be manually updated. --- apitest/scripts/mainnet-test.sh | 8 ++++++-- apitest/scripts/version-parser.bash | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100755 apitest/scripts/version-parser.bash diff --git a/apitest/scripts/mainnet-test.sh b/apitest/scripts/mainnet-test.sh index bfab9fc3b5f..b7b7a8e6131 100755 --- a/apitest/scripts/mainnet-test.sh +++ b/apitest/scripts/mainnet-test.sh @@ -16,6 +16,8 @@ # # ./cli/test.sh +# load 'mainnet-test-helper' + @test "test unsupported method error" { run ./bisq-cli --password=xyz bogus [ "$status" -eq 1 ] @@ -45,17 +47,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') From 34cfe9532ffa1d77f4310787bccca754b3745420 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 14:51:31 -0300 Subject: [PATCH 02/14] Remove comment --- apitest/scripts/mainnet-test.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/apitest/scripts/mainnet-test.sh b/apitest/scripts/mainnet-test.sh index b7b7a8e6131..5ade2b55f41 100755 --- a/apitest/scripts/mainnet-test.sh +++ b/apitest/scripts/mainnet-test.sh @@ -16,8 +16,6 @@ # # ./cli/test.sh -# load 'mainnet-test-helper' - @test "test unsupported method error" { run ./bisq-cli --password=xyz bogus [ "$status" -eq 1 ] From 8896372a0f34c5c253593aaadfccb904f82ee492 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 15:31:38 -0300 Subject: [PATCH 03/14] Move test dispute agent type constants to core The string constants deleted from the test case are re-defined as enums, but the test harness still passes around strings (enum.name()) because the handling of invalid dispute agent type string args needs to be tested. (Reminder: CLI does not accept any enum arguments.) --- .../test/java/bisq/apitest/method/MethodTest.java | 11 ++++++++++- .../apitest/method/RegisterDisputeAgentsTest.java | 15 +++++++-------- .../core/support/dispute/agent/DisputeAgent.java | 6 ++++++ 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/apitest/src/test/java/bisq/apitest/method/MethodTest.java b/apitest/src/test/java/bisq/apitest/method/MethodTest.java index 3437ac59c94..6b85fb00a61 100644 --- a/apitest/src/test/java/bisq/apitest/method/MethodTest.java +++ b/apitest/src/test/java/bisq/apitest/method/MethodTest.java @@ -26,6 +26,8 @@ import bisq.proto.grpc.UnlockWalletRequest; import static bisq.common.app.DevEnv.DEV_PRIVILEGE_PRIV_KEY; +import static bisq.core.support.dispute.agent.DisputeAgent.DisputeAgentType.MEDIATOR; +import static bisq.core.support.dispute.agent.DisputeAgent.DisputeAgentType.REFUNDAGENT; @@ -66,7 +68,7 @@ protected final GetFundingAddressesRequest createGetFundingAddressesRequest() { protected final RegisterDisputeAgentRequest createRegisterDisputeAgentRequest(String disputeAgentType) { return RegisterDisputeAgentRequest.newBuilder() - .setDisputeAgentType(disputeAgentType) + .setDisputeAgentType(disputeAgentType.toLowerCase()) .setRegistrationKey(DEV_PRIVILEGE_PRIV_KEY).build(); } @@ -96,4 +98,11 @@ protected final String getUnusedBtcAddress(BisqAppConfig bisqAppConfig) { .get() .getAddress(); } + + @SuppressWarnings("ResultOfMethodCallIgnored") + protected final 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/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; From 1f307c8263b424b9b5c5960d21bd17815b5e5f75 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 16:31:31 -0300 Subject: [PATCH 04/14] Fix indentation --- proto/src/main/proto/grpc.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index 21c59b8643d..0b9d69cd8d5 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -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. From 6a5040228efaae72616f37896d15b51485d7b6c2 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 18:05:09 -0300 Subject: [PATCH 05/14] Add simple create payment acct test And make test dispute agent registration work from static fixture setup methods. --- .../method/CreatePaymentAccountTest.java | 98 +++++++++++++++++++ .../java/bisq/apitest/method/MethodTest.java | 30 ++++-- 2 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 apitest/src/test/java/bisq/apitest/method/CreatePaymentAccountTest.java 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 6b85fb00a61..de713ae1863 100644 --- a/apitest/src/test/java/bisq/apitest/method/MethodTest.java +++ b/apitest/src/test/java/bisq/apitest/method/MethodTest.java @@ -17,6 +17,7 @@ package bisq.apitest.method; +import bisq.proto.grpc.CreatePaymentAccountRequest; import bisq.proto.grpc.GetBalanceRequest; import bisq.proto.grpc.GetFundingAddressesRequest; import bisq.proto.grpc.LockWalletRequest; @@ -26,6 +27,7 @@ import bisq.proto.grpc.UnlockWalletRequest; 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; @@ -66,12 +68,6 @@ protected final GetFundingAddressesRequest createGetFundingAddressesRequest() { return GetFundingAddressesRequest.newBuilder().build(); } - protected final RegisterDisputeAgentRequest createRegisterDisputeAgentRequest(String disputeAgentType) { - return RegisterDisputeAgentRequest.newBuilder() - .setDisputeAgentType(disputeAgentType.toLowerCase()) - .setRegistrationKey(DEV_PRIVILEGE_PRIV_KEY).build(); - } - // Convenience methods for calling frequently used & thoroughly tested gRPC services. protected final long getBalance(BisqAppConfig bisqAppConfig) { @@ -99,10 +95,30 @@ protected final String getUnusedBtcAddress(BisqAppConfig bisqAppConfig) { .getAddress(); } + // Static conveniences for test methods and test case fixture setups. + + protected static final RegisterDisputeAgentRequest createRegisterDisputeAgentRequest(String disputeAgentType) { + return RegisterDisputeAgentRequest.newBuilder() + .setDisputeAgentType(disputeAgentType.toLowerCase()) + .setRegistrationKey(DEV_PRIVILEGE_PRIV_KEY).build(); + } + @SuppressWarnings("ResultOfMethodCallIgnored") - protected final void registerDisputeAgents(BisqAppConfig bisqAppConfig) { + protected static final void registerDisputeAgents(BisqAppConfig bisqAppConfig) { var disputeAgentsService = grpcStubs(bisqAppConfig).disputeAgentsService; disputeAgentsService.registerDisputeAgent(createRegisterDisputeAgentRequest(MEDIATOR.name())); disputeAgentsService.registerDisputeAgent(createRegisterDisputeAgentRequest(REFUNDAGENT.name())); } + + protected static final CreatePaymentAccountRequest createCreatePerfectMoneyPaymentAccountRequest( + String accountName, + String accountNumber, + String currencyCode) { + return CreatePaymentAccountRequest.newBuilder() + .setPaymentMethodId(PERFECT_MONEY.getId()) + .setAccountName(accountName) + .setAccountNumber(accountNumber) + .setCurrencyCode(currencyCode) + .build(); + } } From 1d88d2733019da4c6231d5fa4159b69cba2dbf44 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 18:11:55 -0300 Subject: [PATCH 06/14] Remove final modifiers --- apitest/src/test/java/bisq/apitest/method/MethodTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apitest/src/test/java/bisq/apitest/method/MethodTest.java b/apitest/src/test/java/bisq/apitest/method/MethodTest.java index de713ae1863..207ec25c26c 100644 --- a/apitest/src/test/java/bisq/apitest/method/MethodTest.java +++ b/apitest/src/test/java/bisq/apitest/method/MethodTest.java @@ -97,20 +97,20 @@ protected final String getUnusedBtcAddress(BisqAppConfig bisqAppConfig) { // Static conveniences for test methods and test case fixture setups. - protected static final RegisterDisputeAgentRequest createRegisterDisputeAgentRequest(String disputeAgentType) { + protected static RegisterDisputeAgentRequest createRegisterDisputeAgentRequest(String disputeAgentType) { return RegisterDisputeAgentRequest.newBuilder() .setDisputeAgentType(disputeAgentType.toLowerCase()) .setRegistrationKey(DEV_PRIVILEGE_PRIV_KEY).build(); } @SuppressWarnings("ResultOfMethodCallIgnored") - protected static final void registerDisputeAgents(BisqAppConfig bisqAppConfig) { + protected static void registerDisputeAgents(BisqAppConfig bisqAppConfig) { var disputeAgentsService = grpcStubs(bisqAppConfig).disputeAgentsService; disputeAgentsService.registerDisputeAgent(createRegisterDisputeAgentRequest(MEDIATOR.name())); disputeAgentsService.registerDisputeAgent(createRegisterDisputeAgentRequest(REFUNDAGENT.name())); } - protected static final CreatePaymentAccountRequest createCreatePerfectMoneyPaymentAccountRequest( + protected static CreatePaymentAccountRequest createCreatePerfectMoneyPaymentAccountRequest( String accountName, String accountNumber, String currencyCode) { From c4dd041d97fbe5a100d9a56d763cf4b4b8ee7e16 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 18:20:23 -0300 Subject: [PATCH 07/14] Don't use static boilerplate helpers if not necessary --- .../java/bisq/apitest/method/MethodTest.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apitest/src/test/java/bisq/apitest/method/MethodTest.java b/apitest/src/test/java/bisq/apitest/method/MethodTest.java index 207ec25c26c..ad971eea09e 100644 --- a/apitest/src/test/java/bisq/apitest/method/MethodTest.java +++ b/apitest/src/test/java/bisq/apitest/method/MethodTest.java @@ -95,6 +95,18 @@ protected final String getUnusedBtcAddress(BisqAppConfig bisqAppConfig) { .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(); + } + // Static conveniences for test methods and test case fixture setups. protected static RegisterDisputeAgentRequest createRegisterDisputeAgentRequest(String disputeAgentType) { @@ -109,16 +121,4 @@ protected static void registerDisputeAgents(BisqAppConfig bisqAppConfig) { disputeAgentsService.registerDisputeAgent(createRegisterDisputeAgentRequest(MEDIATOR.name())); disputeAgentsService.registerDisputeAgent(createRegisterDisputeAgentRequest(REFUNDAGENT.name())); } - - protected static CreatePaymentAccountRequest createCreatePerfectMoneyPaymentAccountRequest( - String accountName, - String accountNumber, - String currencyCode) { - return CreatePaymentAccountRequest.newBuilder() - .setPaymentMethodId(PERFECT_MONEY.getId()) - .setAccountName(accountName) - .setAccountNumber(accountNumber) - .setCurrencyCode(currencyCode) - .build(); - } } From e63a6c57718ab6c480dd77b024ed9710f32bb72c Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 18:45:50 -0300 Subject: [PATCH 08/14] Remove comment --- .../src/main/java/bisq/core/api/CorePaymentAccountsService.java | 2 -- 1 file changed, 2 deletions(-) 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. From 92f36ed03a4d054b7517f1ac1a8af7bf99b03b17 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 22:08:01 -0300 Subject: [PATCH 09/14] Add get default payment acct helper --- .../java/bisq/apitest/method/MethodTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/apitest/src/test/java/bisq/apitest/method/MethodTest.java b/apitest/src/test/java/bisq/apitest/method/MethodTest.java index ad971eea09e..5c4de14c5c6 100644 --- a/apitest/src/test/java/bisq/apitest/method/MethodTest.java +++ b/apitest/src/test/java/bisq/apitest/method/MethodTest.java @@ -20,16 +20,25 @@ 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 org.junit.jupiter.api.Assertions; + 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.*; @@ -107,6 +116,18 @@ protected final CreatePaymentAccountRequest createCreatePerfectMoneyPaymentAccou .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(protobuf.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) { From 2b68e572738d31afcdf41327d670d3a1dd654b87 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 22:09:58 -0300 Subject: [PATCH 10/14] Stub out createoffer method in CLI --- cli/src/main/java/bisq/cli/CliMain.java | 7 +++++++ 1 file changed, 7 insertions(+) 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"); From 3c0c443680a7eca723eb6efaf0b73a41b1781f9e Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 22:13:42 -0300 Subject: [PATCH 11/14] Change API's createoffer return value from bool to Offer --- core/src/main/java/bisq/core/api/CoreApi.java | 48 +++++------ .../java/bisq/core/api/CoreOffersService.java | 85 ++++++++++++++----- .../bisq/daemon/grpc/GrpcOffersService.java | 64 +++++++++++--- proto/src/main/proto/grpc.proto | 2 +- 4 files changed, 137 insertions(+), 62 deletions(-) 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/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 0b9d69cd8d5..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 { From 70e3be0032218d37e0fc8a22023a1995394d49ad Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 22:16:55 -0300 Subject: [PATCH 12/14] Add API CreateOfferTest case --- .../bisq/apitest/method/CreateOfferTest.java | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 apitest/src/test/java/bisq/apitest/method/CreateOfferTest.java 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(); + } +} From fc1f0bac60635e98bad75becfc7282567eb152d8 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 22:56:08 -0300 Subject: [PATCH 13/14] Fix imports --- apitest/src/test/java/bisq/apitest/method/MethodTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apitest/src/test/java/bisq/apitest/method/MethodTest.java b/apitest/src/test/java/bisq/apitest/method/MethodTest.java index 5c4de14c5c6..764e8cb93d3 100644 --- a/apitest/src/test/java/bisq/apitest/method/MethodTest.java +++ b/apitest/src/test/java/bisq/apitest/method/MethodTest.java @@ -31,14 +31,12 @@ import java.util.stream.Collectors; -import org.junit.jupiter.api.Assertions; - 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.*; +import static org.junit.jupiter.api.Assertions.assertEquals; From d190d09e2bc21ab8aaf686ba3a81a0936a716904 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Tue, 22 Sep 2020 22:58:32 -0300 Subject: [PATCH 14/14] Fix unnecessary use of fully qualified name --- apitest/src/test/java/bisq/apitest/method/MethodTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apitest/src/test/java/bisq/apitest/method/MethodTest.java b/apitest/src/test/java/bisq/apitest/method/MethodTest.java index 764e8cb93d3..3f9f2cec1c7 100644 --- a/apitest/src/test/java/bisq/apitest/method/MethodTest.java +++ b/apitest/src/test/java/bisq/apitest/method/MethodTest.java @@ -120,7 +120,7 @@ protected final PaymentAccount getDefaultPerfectDummyPaymentAccount(BisqAppConfi PaymentAccount paymentAccount = paymentAccountsService.getPaymentAccounts(getPaymentAccountsRequest) .getPaymentAccountsList() .stream() - .sorted(comparing(protobuf.PaymentAccount::getCreationDate)) + .sorted(comparing(PaymentAccount::getCreationDate)) .collect(Collectors.toList()).get(0); assertEquals("PerfectMoney dummy", paymentAccount.getAccountName()); return paymentAccount;