Skip to content

Commit

Permalink
Merge pull request #4324 from ghubstan/5A-print-addressinfo-as-table
Browse files Browse the repository at this point in the history
Return protos from funding address methods
  • Loading branch information
sqrrm authored Jun 25, 2020
2 parents ca98654 + 612bafe commit 79f0dac
Show file tree
Hide file tree
Showing 10 changed files with 407 additions and 127 deletions.
113 changes: 88 additions & 25 deletions cli/src/main/java/bisq/cli/CliMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,20 @@

package bisq.cli;

import bisq.proto.grpc.AddressBalanceInfo;
import bisq.proto.grpc.CreatePaymentAccountRequest;
import bisq.proto.grpc.GetAddressBalanceRequest;
import bisq.proto.grpc.GetBalanceRequest;
import bisq.proto.grpc.GetFundingAddressesRequest;
import bisq.proto.grpc.GetPaymentAccountsRequest;
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;
import bisq.proto.grpc.WalletGrpc;
import bisq.proto.grpc.WalletsGrpc;

import io.grpc.ManagedChannelBuilder;
import io.grpc.StatusRuntimeException;
Expand All @@ -43,21 +47,33 @@

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;

import static java.lang.String.format;
import static java.lang.System.err;
import static java.lang.System.exit;
import static java.lang.System.out;
import static java.util.Collections.singletonList;

/**
* A command-line client for the Bisq gRPC API.
*/
@SuppressWarnings("ResultOfMethodCallIgnored")
@Slf4j
public class CliMain {

private static final BigDecimal SATOSHI_DIVISOR = new BigDecimal(100000000);
private static final DecimalFormat BTC_FORMAT = new DecimalFormat("###,##0.00000000");
@SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
private static final Function<Long, String> formatSatoshis = (sats) ->
BTC_FORMAT.format(BigDecimal.valueOf(sats).divide(SATOSHI_DIVISOR));

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

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

try {
switch (method) {
Expand All @@ -147,12 +164,8 @@ public static void run(String[] args) {
}
case getbalance: {
var request = GetBalanceRequest.newBuilder().build();
var reply = walletService.getBalance(request);
var satoshiBalance = reply.getBalance();
var satoshiDivisor = new BigDecimal(100000000);
var btcFormat = new DecimalFormat("###,##0.00000000");
@SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
var btcBalance = btcFormat.format(BigDecimal.valueOf(satoshiBalance).divide(satoshiDivisor));
var reply = walletsService.getBalance(request);
var btcBalance = formatSatoshis.apply(reply.getBalance());
out.println(btcBalance);
return;
}
Expand All @@ -162,19 +175,57 @@ public static void run(String[] args) {

var request = GetAddressBalanceRequest.newBuilder()
.setAddress(nonOptionArgs.get(1)).build();
var reply = walletService.getAddressBalance(request);
out.println(reply.getAddressBalanceInfo());
var reply = walletsService.getAddressBalance(request);
out.println(formatTable(singletonList(reply.getAddressBalanceInfo())));
return;
}
case getfundingaddresses: {
var request = GetFundingAddressesRequest.newBuilder().build();
var reply = walletService.getFundingAddresses(request);
out.println(reply.getFundingAddressesInfo());
var reply = walletsService.getFundingAddresses(request);
out.println(formatTable(reply.getAddressBalanceInfoList()));
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 getpaymentaccts: {
var request = GetPaymentAccountsRequest.newBuilder().build();
var reply = paymentAccountsService.getPaymentAccounts(request);
var columnFormatSpec = "%-41s %-25s %-14s %s";
out.println(format(columnFormatSpec, "ID", "Name", "Currency", "Payment Method"));
out.println(reply.getPaymentAccountsList().stream()
.map(a -> format(columnFormatSpec,
a.getId(),
a.getAccountName(),
a.getSelectedTradeCurrency().getCode(),
a.getPaymentMethod().getId()))
.collect(Collectors.joining("\n")));
return;
}
case lockwallet: {
var request = LockWalletRequest.newBuilder().build();
walletService.lockWallet(request);
walletsService.lockWallet(request);
out.println("wallet locked");
return;
}
Expand All @@ -194,7 +245,7 @@ public static void run(String[] args) {
var request = UnlockWalletRequest.newBuilder()
.setPassword(nonOptionArgs.get(1))
.setTimeout(timeout).build();
walletService.unlockWallet(request);
walletsService.unlockWallet(request);
out.println("wallet unlocked");
return;
}
Expand All @@ -203,7 +254,7 @@ public static void run(String[] args) {
throw new IllegalArgumentException("no password specified");

var request = RemoveWalletPasswordRequest.newBuilder().setPassword(nonOptionArgs.get(1)).build();
walletService.removeWalletPassword(request);
walletsService.removeWalletPassword(request);
out.println("wallet decrypted");
return;
}
Expand All @@ -215,7 +266,7 @@ public static void run(String[] args) {
var hasNewPassword = nonOptionArgs.size() == 3;
if (hasNewPassword)
requestBuilder.setNewPassword(nonOptionArgs.get(2));
walletService.setWalletPassword(requestBuilder.build());
walletsService.setWalletPassword(requestBuilder.build());
out.println("wallet encrypted" + (hasNewPassword ? " with new password" : ""));
return;
}
Expand All @@ -238,20 +289,32 @@ 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", "getpaymentaccts", "", "Get user payment accounts");
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) {
ex.printStackTrace(stream);
}
}

private static String formatTable(List<AddressBalanceInfo> addressBalanceInfo) {
return format("%-35s %13s %s%n", "Address", "Balance", "Confirmations")
+ addressBalanceInfo.stream()
.map(info -> format("%-35s %13s %14d",
info.getAddress(),
formatSatoshis.apply(info.getBalance()),
info.getNumConfirmations()))
.collect(Collectors.joining("\n"));
}
}
10 changes: 10 additions & 0 deletions cli/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@
[ "$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 getpaymentaccts" {
run ./bisq-cli --password=xyz getpaymentaccts
[ "$status" -eq 0 ]
}

@test "test help displayed on stderr if no options or arguments" {
run ./bisq-cli
[ "$status" -eq 1 ]
Expand Down
64 changes: 59 additions & 5 deletions core/src/main/java/bisq/core/grpc/CoreApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package bisq.core.grpc;

import bisq.core.grpc.model.AddressBalanceInfo;
import bisq.core.monetary.Price;
import bisq.core.offer.CreateOfferService;
import bisq.core.offer.Offer;
Expand Down Expand Up @@ -47,18 +48,24 @@
*/
@Slf4j
public class CoreApi {
private final CorePaymentAccountsService paymentAccountsService;
private final CoreWalletsService walletsService;
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,
CoreWalletsService walletsService,
OfferBookService offerBookService,
TradeStatisticsManager tradeStatisticsManager,
CreateOfferService createOfferService,
OpenOfferManager openOfferManager,
User user) {
this.paymentAccountsService = paymentAccountsService;
this.walletsService = walletsService;
this.offerBookService = offerBookService;
this.tradeStatisticsManager = tradeStatisticsManager;
this.createOfferService = createOfferService;
Expand All @@ -70,16 +77,52 @@ public String getVersion() {
return Version.VERSION;
}

///////////////////////////////////////////////////////////////////////////////////////////
// Wallets
///////////////////////////////////////////////////////////////////////////////////////////

public long getAvailableBalance() {
return walletsService.getAvailableBalance();
}

public long getAddressBalance(String addressString) {
return walletsService.getAddressBalance(addressString);
}

public AddressBalanceInfo getAddressBalanceInfo(String addressString) {
return walletsService.getAddressBalanceInfo(addressString);
}

public List<AddressBalanceInfo> getFundingAddresses() {
return walletsService.getFundingAddresses();
}

public void setWalletPassword(String password, String newPassword) {
walletsService.setWalletPassword(password, newPassword);
}

public void lockWallet() {
walletsService.lockWallet();
}

public void unlockWallet(String password, long timeout) {
walletsService.unlockWallet(password, timeout);
}

public void removeWalletPassword(String password) {
walletsService.removeWalletPassword(password);
}

public List<TradeStatistics2> getTradeStatistics() {
return new ArrayList<>(tradeStatisticsManager.getObservableTradeStatisticsSet());
}

public List<Offer> getOffers() {
return offerBookService.getOffers();
public int getNumConfirmationsForMostRecentTransaction(String addressString) {
return walletsService.getNumConfirmationsForMostRecentTransaction(addressString);
}

public Set<PaymentAccount> getPaymentAccounts() {
return user.getPaymentAccounts();
public List<Offer> getOffers() {
return offerBookService.getOffers();
}

public void placeOffer(String currencyCode,
Expand Down Expand Up @@ -145,4 +188,15 @@ public void placeOffer(String offerId,
log::error);
}

///////////////////////////////////////////////////////////////////////////////////////////
// PaymentAccounts
///////////////////////////////////////////////////////////////////////////////////////////

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

public Set<PaymentAccount> getPaymentAccounts() {
return paymentAccountsService.getPaymentAccounts();
}
}
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();
}
}
Loading

0 comments on commit 79f0dac

Please sign in to comment.