diff --git a/cli/src/main/java/bisq/cli/CliMain.java b/cli/src/main/java/bisq/cli/CliMain.java index 36bb55add62..ab6f39fa41c 100644 --- a/cli/src/main/java/bisq/cli/CliMain.java +++ b/cli/src/main/java/bisq/cli/CliMain.java @@ -17,6 +17,7 @@ package bisq.cli; +import bisq.proto.grpc.GetAddressBalanceRequest; import bisq.proto.grpc.GetBalanceRequest; import bisq.proto.grpc.GetFundingAddressesRequest; import bisq.proto.grpc.GetVersionGrpc; @@ -59,6 +60,7 @@ public class CliMain { private enum Method { getversion, getbalance, + getaddressbalance, getfundingaddresses, lockwallet, unlockwallet, @@ -154,6 +156,16 @@ public static void run(String[] args) { out.println(btcBalance); return; } + case getaddressbalance: { + if (nonOptionArgs.size() < 2) + throw new IllegalArgumentException("no address specified"); + + var request = GetAddressBalanceRequest.newBuilder() + .setAddress(nonOptionArgs.get(1)).build(); + var reply = walletService.getAddressBalance(request); + out.println(reply.getAddressBalanceInfo()); + return; + } case getfundingaddresses: { var request = GetFundingAddressesRequest.newBuilder().build(); var reply = walletService.getFundingAddresses(request); @@ -230,6 +242,7 @@ private static void printHelp(OptionParser parser, PrintStream stream) { 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", diff --git a/cli/test.sh b/cli/test.sh index be2e67bc46f..875cb0a8a27 100755 --- a/cli/test.sh +++ b/cli/test.sh @@ -152,6 +152,20 @@ [ "$status" -eq 0 ] } +@test "test getaddressbalance missing address argument" { + run ./bisq-cli --password=xyz getaddressbalance + [ "$status" -eq 1 ] + echo "actual output: $output" >&2 + [ "$output" = "Error: no address specified" ] +} + +@test "test getaddressbalance bogus address argument" { + run ./bisq-cli --password=xyz getaddressbalance bogus + [ "$status" -eq 1 ] + echo "actual output: $output" >&2 + [ "$output" = "Error: address bogus not found in wallet" ] +} + @test "test help displayed on stderr if no options or arguments" { run ./bisq-cli [ "$status" -eq 1 ] diff --git a/core/src/main/java/bisq/core/grpc/CoreWalletsService.java b/core/src/main/java/bisq/core/grpc/CoreWalletsService.java index 64d70e15c73..f9e3b7d1c60 100644 --- a/core/src/main/java/bisq/core/grpc/CoreWalletsService.java +++ b/core/src/main/java/bisq/core/grpc/CoreWalletsService.java @@ -80,6 +80,15 @@ public long getAddressBalance(String addressString) { return btcWalletService.getBalanceForAddress(address).value; } + public String getAddressBalanceInfo(String addressString) { + var satoshiBalance = getAddressBalance(addressString); + var btcBalance = formatSatoshis.apply(satoshiBalance); + var numConfirmations = getNumConfirmationsForMostRecentTransaction(addressString); + return addressString + + " balance: " + format("%13s", btcBalance) + + ((numConfirmations > 0) ? (" confirmations: " + format("%6d", numConfirmations)) : ""); + } + public String getFundingAddresses() { if (!walletsManager.areWalletsAvailable()) throw new IllegalStateException("wallet is not yet available"); diff --git a/core/src/main/java/bisq/core/grpc/GrpcWalletService.java b/core/src/main/java/bisq/core/grpc/GrpcWalletService.java index 62373fd1be9..0343960f394 100644 --- a/core/src/main/java/bisq/core/grpc/GrpcWalletService.java +++ b/core/src/main/java/bisq/core/grpc/GrpcWalletService.java @@ -1,5 +1,7 @@ package bisq.core.grpc; +import bisq.proto.grpc.GetAddressBalanceReply; +import bisq.proto.grpc.GetAddressBalanceRequest; import bisq.proto.grpc.GetBalanceReply; import bisq.proto.grpc.GetBalanceRequest; import bisq.proto.grpc.GetFundingAddressesReply; @@ -42,7 +44,22 @@ public void getBalance(GetBalanceRequest req, StreamObserver re throw ex; } } - + + @Override + public void getAddressBalance(GetAddressBalanceRequest req, + StreamObserver responseObserver) { + try { + String result = walletsService.getAddressBalanceInfo(req.getAddress()); + var reply = GetAddressBalanceReply.newBuilder().setAddressBalanceInfo(result).build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } catch (IllegalStateException cause) { + var ex = new StatusRuntimeException(Status.UNKNOWN.withDescription(cause.getMessage())); + responseObserver.onError(ex); + throw ex; + } + } + @Override public void getFundingAddresses(GetFundingAddressesRequest req, StreamObserver responseObserver) { diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index 9e85dbe371e..41b490b9b53 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -119,6 +119,8 @@ message PlaceOfferReply { service Wallet { rpc GetBalance (GetBalanceRequest) returns (GetBalanceReply) { } + rpc GetAddressBalance (GetAddressBalanceRequest) returns (GetAddressBalanceReply) { + } rpc GetFundingAddresses (GetFundingAddressesRequest) returns (GetFundingAddressesReply) { } rpc SetWalletPassword (SetWalletPasswordRequest) returns (SetWalletPasswordReply) { @@ -138,6 +140,14 @@ message GetBalanceReply { uint64 balance = 1; } +message GetAddressBalanceRequest { + string address = 1; +} + +message GetAddressBalanceReply { + string addressBalanceInfo = 1; +} + message GetFundingAddressesRequest { }