Skip to content

Commit

Permalink
Add rpc method 'createpaymentacct'
Browse files Browse the repository at this point in the history
This addresses task 4 in issue 4257.
    bisq-network#4257

This PR should be reviewed/merged after PR 4304.
    bisq-network#4304

This new gRPC PaymentAccounts service method creates a dummy
PerfectMoney payment account for the given name, number and fiat
currency code, as part of the required "simplest possible trading
API" (for demo).   An implementation supporting all payment
methods is not in the scope.

Changes specific to the new rpc method implementation follow:

* New createpaymentacct method + help text was added to CliMain.
  Help text formatting was also changed to make room for larger
  method names and argument lists.

* The PaymentAccount proto service def was renamed PaymentAccounts
  to avoid a name collision, and the new rpc CreatePaymentAccount
  was made part of the newly named PaymentAccounts service def.

* New GrpcPaymentAccountsService (gRPC boilerplate) and
  CorePaymentAccountsService (method implementations) classes were
  added.

* The gRPC GetPaymentAccountsService stub was moved from GrpcServer
  to the new GrpcPaymentAccountsService class, and
  GrpcPaymentAccountsService is injected into GrpcServer.

* A new createpaymentacct unit test was added to the bats test
  suite (checks for successful return status code).

Maybe bit out of scope, some small changes were made towards making
sure the entire API is defined in CoreApi, which is used as a
pass-through object to the new CorePaymentAccountsService.  In the
next PR, similar refactoring will be done to make CoreApi the
pass-through object for all of the existing CoreWalletsService
methods.  (CoreWalletsService will be injected into CoreApi.)
In the future, all Grpc*Service implementations will call core
services through CoreApi, for the sake of consistency.
  • Loading branch information
ghubstan committed Jun 15, 2020
1 parent b1228e5 commit 4b7bd7c
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 34 deletions.
47 changes: 38 additions & 9 deletions cli/src/main/java/bisq/cli/CliMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@

package bisq.cli;

import bisq.proto.grpc.CreatePaymentAccountRequest;
import bisq.proto.grpc.GetAddressBalanceRequest;
import bisq.proto.grpc.GetBalanceRequest;
import bisq.proto.grpc.GetFundingAddressesRequest;
import bisq.proto.grpc.GetVersionGrpc;
import bisq.proto.grpc.GetVersionRequest;
import bisq.proto.grpc.LockWalletRequest;
import bisq.proto.grpc.PaymentAccountsGrpc;
import bisq.proto.grpc.RemoveWalletPasswordRequest;
import bisq.proto.grpc.SetWalletPasswordRequest;
import bisq.proto.grpc.UnlockWalletRequest;
Expand Down Expand Up @@ -58,6 +60,7 @@
public class CliMain {

private enum Method {
createpaymentacct,
getversion,
getbalance,
getaddressbalance,
Expand Down Expand Up @@ -135,6 +138,7 @@ public static void run(String[] args) {
}));

var versionService = GetVersionGrpc.newBlockingStub(channel).withCallCredentials(credentials);
var paymentAccountsService = PaymentAccountsGrpc.newBlockingStub(channel).withCallCredentials(credentials);
var walletService = WalletGrpc.newBlockingStub(channel).withCallCredentials(credentials);

try {
Expand Down Expand Up @@ -172,6 +176,30 @@ public static void run(String[] args) {
out.println(reply.getFundingAddressesInfo());
return;
}
case createpaymentacct: {
if (nonOptionArgs.size() < 2)
throw new IllegalArgumentException("no account name specified");

var accountName = nonOptionArgs.get(1);

if (nonOptionArgs.size() < 3)
throw new IllegalArgumentException("no account number specified");

var accountNumber = nonOptionArgs.get(2);

if (nonOptionArgs.size() < 4)
throw new IllegalArgumentException("no fiat currency specified");

var fiatCurrencyCode = nonOptionArgs.get(3).toUpperCase();

var request = CreatePaymentAccountRequest.newBuilder()
.setAccountName(accountName)
.setAccountNumber(accountNumber)
.setFiatCurrencyCode(fiatCurrencyCode).build();
paymentAccountsService.createPaymentAccount(request);
out.println(format("payment account %s saved", accountName));
return;
}
case lockwallet: {
var request = LockWalletRequest.newBuilder().build();
walletService.lockWallet(request);
Expand Down Expand Up @@ -238,16 +266,17 @@ private static void printHelp(OptionParser parser, PrintStream stream) {
stream.println();
parser.printHelpOn(stream);
stream.println();
stream.format("%-19s%-30s%s%n", "Method", "Params", "Description");
stream.format("%-19s%-30s%s%n", "------", "------", "------------");
stream.format("%-19s%-30s%s%n", "getversion", "", "Get server version");
stream.format("%-19s%-30s%s%n", "getbalance", "", "Get server wallet balance");
stream.format("%-19s%-30s%s%n", "getaddressbalance", "", "Get server wallet address balance");
stream.format("%-19s%-30s%s%n", "getfundingaddresses", "", "Get BTC funding addresses");
stream.format("%-19s%-30s%s%n", "lockwallet", "", "Remove wallet password from memory, locking the wallet");
stream.format("%-19s%-30s%s%n", "unlockwallet", "password timeout",
stream.format("%-22s%-50s%s%n", "Method", "Params", "Description");
stream.format("%-22s%-50s%s%n", "------", "------", "------------");
stream.format("%-22s%-50s%s%n", "getversion", "", "Get server version");
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", "createpaymentacct", "account name, account number, currency code", "Create PerfectMoney dummy account");
stream.format("%-22s%-50s%s%n", "lockwallet", "", "Remove wallet password from memory, locking the wallet");
stream.format("%-22s%-50s%s%n", "unlockwallet", "password timeout",
"Store wallet password in memory for timeout seconds");
stream.format("%-19s%-30s%s%n", "setwalletpassword", "password [newpassword]",
stream.format("%-22s%-50s%s%n", "setwalletpassword", "password [newpassword]",
"Encrypt wallet with password, or set new password on encrypted wallet");
stream.println();
} catch (IOException ex) {
Expand Down
5 changes: 5 additions & 0 deletions cli/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@
[ "$output" = "Error: address bogus not found in wallet" ]
}

@test "test createpaymentacct PerfectMoneyDummy 0123456789 USD" {
run ./bisq-cli --password=xyz createpaymentacct PerfectMoneyDummy 0123456789 USD
[ "$status" -eq 0 ]
}

@test "test help displayed on stderr if no options or arguments" {
run ./bisq-cli
[ "$status" -eq 1 ]
Expand Down
11 changes: 9 additions & 2 deletions core/src/main/java/bisq/core/grpc/CoreApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,21 @@
*/
@Slf4j
public class CoreApi {
private final CorePaymentAccountsService paymentAccountsService;
private final OfferBookService offerBookService;
private final TradeStatisticsManager tradeStatisticsManager;
private final CreateOfferService createOfferService;
private final OpenOfferManager openOfferManager;
private final User user;

@Inject
public CoreApi(OfferBookService offerBookService,
public CoreApi(CorePaymentAccountsService paymentAccountsService,
OfferBookService offerBookService,
TradeStatisticsManager tradeStatisticsManager,
CreateOfferService createOfferService,
OpenOfferManager openOfferManager,
User user) {
this.paymentAccountsService = paymentAccountsService;
this.offerBookService = offerBookService;
this.tradeStatisticsManager = tradeStatisticsManager;
this.createOfferService = createOfferService;
Expand All @@ -78,8 +81,12 @@ public List<Offer> getOffers() {
return offerBookService.getOffers();
}

public void createPaymentAccount(String accountName, String accountNumber, String fiatCurrencyCode) {
paymentAccountsService.createPaymentAccount(accountName, accountNumber, fiatCurrencyCode);
}

public Set<PaymentAccount> getPaymentAccounts() {
return user.getPaymentAccounts();
return paymentAccountsService.getPaymentAccounts();
}

public void placeOffer(String currencyCode,
Expand Down
57 changes: 57 additions & 0 deletions core/src/main/java/bisq/core/grpc/CorePaymentAccountsService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package bisq.core.grpc;

import bisq.core.account.witness.AccountAgeWitnessService;
import bisq.core.locale.FiatCurrency;
import bisq.core.payment.PaymentAccount;
import bisq.core.payment.PaymentAccountFactory;
import bisq.core.payment.PerfectMoneyAccount;
import bisq.core.payment.payload.PaymentMethod;
import bisq.core.user.User;

import bisq.common.config.Config;

import javax.inject.Inject;

import java.util.Set;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CorePaymentAccountsService {

private final Config config;
private final AccountAgeWitnessService accountAgeWitnessService;
private final User user;

@Inject
public CorePaymentAccountsService(Config config,
AccountAgeWitnessService accountAgeWitnessService,
User user) {
this.config = config;
this.accountAgeWitnessService = accountAgeWitnessService;
this.user = user;
}

public void createPaymentAccount(String accountName, String accountNumber, String fiatCurrencyCode) {
// Create and persist a PerfectMoney dummy payment account. There is no guard
// against creating accounts with duplicate names & numbers, only the uuid and
// creation date are unique.
PaymentMethod dummyPaymentMethod = PaymentMethod.getDummyPaymentMethod(PaymentMethod.PERFECT_MONEY_ID);
PaymentAccount paymentAccount = PaymentAccountFactory.getPaymentAccount(dummyPaymentMethod);
paymentAccount.init();
paymentAccount.setAccountName(accountName);
((PerfectMoneyAccount) paymentAccount).setAccountNr(accountNumber);
paymentAccount.setSingleTradeCurrency(new FiatCurrency(fiatCurrencyCode));
user.addPaymentAccount(paymentAccount);

// Don't do this on mainnet until thoroughly tested.
if (config.baseCurrencyNetwork.isRegtest())
accountAgeWitnessService.publishMyAccountAgeWitness(paymentAccount.getPaymentAccountPayload());

log.info("Payment account {} saved", paymentAccount.getId());
}

public Set<PaymentAccount> getPaymentAccounts() {
return user.getPaymentAccounts();
}
}
46 changes: 46 additions & 0 deletions core/src/main/java/bisq/core/grpc/GrpcPaymentAccountsService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package bisq.core.grpc;

import bisq.core.payment.PaymentAccount;

import bisq.proto.grpc.CreatePaymentAccountReply;
import bisq.proto.grpc.CreatePaymentAccountRequest;
import bisq.proto.grpc.GetPaymentAccountsReply;
import bisq.proto.grpc.GetPaymentAccountsRequest;
import bisq.proto.grpc.PaymentAccountsGrpc;

import io.grpc.stub.StreamObserver;

import javax.inject.Inject;

import java.util.stream.Collectors;


public class GrpcPaymentAccountsService extends PaymentAccountsGrpc.PaymentAccountsImplBase {

private final CoreApi coreApi;

@Inject
public GrpcPaymentAccountsService(CoreApi coreApi) {
this.coreApi = coreApi;
}

@Override
public void createPaymentAccount(CreatePaymentAccountRequest req,
StreamObserver<CreatePaymentAccountReply> responseObserver) {
coreApi.createPaymentAccount(req.getAccountName(), req.getAccountNumber(), req.getFiatCurrencyCode());
var reply = CreatePaymentAccountReply.newBuilder().build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}

@Override
public void getPaymentAccounts(GetPaymentAccountsRequest req,
StreamObserver<GetPaymentAccountsReply> responseObserver) {
var tradeStatistics = coreApi.getPaymentAccounts().stream()
.map(PaymentAccount::toProtoMessage)
.collect(Collectors.toList());
var reply = GetPaymentAccountsReply.newBuilder().addAllPaymentAccounts(tradeStatistics).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
26 changes: 5 additions & 21 deletions core/src/main/java/bisq/core/grpc/GrpcServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
package bisq.core.grpc;

import bisq.core.offer.Offer;
import bisq.core.payment.PaymentAccount;
import bisq.core.trade.handlers.TransactionResultHandler;
import bisq.core.trade.statistics.TradeStatistics2;

Expand All @@ -27,9 +26,6 @@
import bisq.proto.grpc.GetOffersGrpc;
import bisq.proto.grpc.GetOffersReply;
import bisq.proto.grpc.GetOffersRequest;
import bisq.proto.grpc.GetPaymentAccountsGrpc;
import bisq.proto.grpc.GetPaymentAccountsReply;
import bisq.proto.grpc.GetPaymentAccountsRequest;
import bisq.proto.grpc.GetTradeStatisticsGrpc;
import bisq.proto.grpc.GetTradeStatisticsReply;
import bisq.proto.grpc.GetTradeStatisticsRequest;
Expand Down Expand Up @@ -60,14 +56,17 @@ public class GrpcServer {
private final Server server;

@Inject
public GrpcServer(Config config, CoreApi coreApi, GrpcWalletService walletService) {
public GrpcServer(Config config,
CoreApi coreApi,
GrpcPaymentAccountsService paymentAccountsService,
GrpcWalletService walletService) {
this.coreApi = coreApi;
this.server = ServerBuilder.forPort(config.apiPort)
.addService(new GetVersionService())
.addService(new GetTradeStatisticsService())
.addService(new GetOffersService())
.addService(new GetPaymentAccountsService())
.addService(new PlaceOfferService())
.addService(paymentAccountsService)
.addService(walletService)
.intercept(new PasswordAuthInterceptor(config.apiPassword))
.build();
Expand Down Expand Up @@ -125,21 +124,6 @@ public void getOffers(GetOffersRequest req, StreamObserver<GetOffersReply> respo
}
}

class GetPaymentAccountsService extends GetPaymentAccountsGrpc.GetPaymentAccountsImplBase {
@Override
public void getPaymentAccounts(GetPaymentAccountsRequest req,
StreamObserver<GetPaymentAccountsReply> responseObserver) {

var tradeStatistics = coreApi.getPaymentAccounts().stream()
.map(PaymentAccount::toProtoMessage)
.collect(Collectors.toList());

var reply = GetPaymentAccountsReply.newBuilder().addAllPaymentAccounts(tradeStatistics).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}

class PlaceOfferService extends PlaceOfferGrpc.PlaceOfferImplBase {
@Override
public void placeOffer(PlaceOfferRequest req, StreamObserver<PlaceOfferReply> responseObserver) {
Expand Down
15 changes: 13 additions & 2 deletions proto/src/main/proto/grpc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,25 @@ message GetOffersReply {
}

///////////////////////////////////////////////////////////////////////////////////////////
// PaymentAccount
// PaymentAccounts
///////////////////////////////////////////////////////////////////////////////////////////

service GetPaymentAccounts {
service PaymentAccounts {
rpc CreatePaymentAccount (CreatePaymentAccountRequest) returns (CreatePaymentAccountReply) {
}
rpc GetPaymentAccounts (GetPaymentAccountsRequest) returns (GetPaymentAccountsReply) {
}
}

message CreatePaymentAccountRequest {
string accountName = 1;
string accountNumber = 2;
string fiatCurrencyCode = 3;
}

message CreatePaymentAccountReply {
}

message GetPaymentAccountsRequest {
}

Expand Down

0 comments on commit 4b7bd7c

Please sign in to comment.