diff --git a/apitest/docs/build-run.md b/apitest/docs/build-run.md
index 308fe02cf66..9d1165ca88e 100644
--- a/apitest/docs/build-run.md
+++ b/apitest/docs/build-run.md
@@ -48,7 +48,7 @@ To run all test cases in a package:
To run a single test case:
- $ ./gradlew :apitest:test --tests "bisq.apitest.method.GetBalanceTest" -DrunApiTests=true
+ $ ./gradlew :apitest:test --tests "bisq.apitest.method.wallet.GetBalanceTest" -DrunApiTests=true
To run test cases from Intellij, add two JVM arguments to your JUnit launchers:
diff --git a/apitest/src/test/java/bisq/apitest/method/MethodTest.java b/apitest/src/test/java/bisq/apitest/method/MethodTest.java
index 43073ba995b..f9275ffbee5 100644
--- a/apitest/src/test/java/bisq/apitest/method/MethodTest.java
+++ b/apitest/src/test/java/bisq/apitest/method/MethodTest.java
@@ -17,21 +17,31 @@
package bisq.apitest.method;
+import bisq.proto.grpc.AddressBalanceInfo;
+import bisq.proto.grpc.BalancesInfo;
+import bisq.proto.grpc.BsqBalanceInfo;
+import bisq.proto.grpc.BtcBalanceInfo;
import bisq.proto.grpc.CancelOfferRequest;
import bisq.proto.grpc.ConfirmPaymentReceivedRequest;
import bisq.proto.grpc.ConfirmPaymentStartedRequest;
import bisq.proto.grpc.CreatePaymentAccountRequest;
+import bisq.proto.grpc.GetAddressBalanceRequest;
import bisq.proto.grpc.GetBalanceRequest;
+import bisq.proto.grpc.GetBalancesRequest;
+import bisq.proto.grpc.GetBsqBalancesRequest;
+import bisq.proto.grpc.GetBtcBalancesRequest;
import bisq.proto.grpc.GetFundingAddressesRequest;
import bisq.proto.grpc.GetOfferRequest;
import bisq.proto.grpc.GetPaymentAccountsRequest;
import bisq.proto.grpc.GetTradeRequest;
+import bisq.proto.grpc.GetUnusedBsqAddressRequest;
import bisq.proto.grpc.KeepFundsRequest;
import bisq.proto.grpc.LockWalletRequest;
import bisq.proto.grpc.MarketPriceRequest;
import bisq.proto.grpc.OfferInfo;
import bisq.proto.grpc.RegisterDisputeAgentRequest;
import bisq.proto.grpc.RemoveWalletPasswordRequest;
+import bisq.proto.grpc.SendBsqRequest;
import bisq.proto.grpc.SetWalletPasswordRequest;
import bisq.proto.grpc.TakeOfferRequest;
import bisq.proto.grpc.TradeInfo;
@@ -103,10 +113,27 @@ public static void startSupportingApps(boolean registerDisputeAgents,
// Convenience methods for building gRPC request objects
+ @Deprecated
protected final GetBalanceRequest createBalanceRequest() {
return GetBalanceRequest.newBuilder().build();
}
+ protected final GetBalancesRequest createGetBalancesRequest() {
+ return GetBalancesRequest.newBuilder().build();
+ }
+
+ protected final GetAddressBalanceRequest createGetAddressBalanceRequest(String address) {
+ return GetAddressBalanceRequest.newBuilder().setAddress(address).build();
+ }
+
+ protected final GetBsqBalancesRequest createGetBsqBalancesRequest() {
+ return GetBsqBalancesRequest.newBuilder().build();
+ }
+
+ protected final GetBtcBalancesRequest createBtcBalancesRequest() {
+ return GetBtcBalancesRequest.newBuilder().build();
+ }
+
protected final SetWalletPasswordRequest createSetWalletPasswordRequest(String password) {
return SetWalletPasswordRequest.newBuilder().setPassword(password).build();
}
@@ -127,6 +154,14 @@ protected final LockWalletRequest createLockWalletRequest() {
return LockWalletRequest.newBuilder().build();
}
+ protected final GetUnusedBsqAddressRequest createGetUnusedBsqAddressRequest() {
+ return GetUnusedBsqAddressRequest.newBuilder().build();
+ }
+
+ protected final SendBsqRequest createSendBsqRequest(String address, double amount) {
+ return SendBsqRequest.newBuilder().setAddress(address).setAmount(amount).build();
+ }
+
protected final GetFundingAddressesRequest createGetFundingAddressesRequest() {
return GetFundingAddressesRequest.newBuilder().build();
}
@@ -143,8 +178,12 @@ protected final CancelOfferRequest createCancelOfferRequest(String offerId) {
return CancelOfferRequest.newBuilder().setId(offerId).build();
}
- protected final TakeOfferRequest createTakeOfferRequest(String offerId, String paymentAccountId) {
- return TakeOfferRequest.newBuilder().setOfferId(offerId).setPaymentAccountId(paymentAccountId).build();
+ protected final TakeOfferRequest createTakeOfferRequest(String offerId,
+ String paymentAccountId) {
+ return TakeOfferRequest.newBuilder()
+ .setOfferId(offerId)
+ .setPaymentAccountId(paymentAccountId)
+ .build();
}
protected final GetTradeRequest createGetTradeRequest(String tradeId) {
@@ -174,10 +213,27 @@ protected final WithdrawFundsRequest createWithdrawFundsRequest(String tradeId,
// Convenience methods for calling frequently used & thoroughly tested gRPC services.
+ @Deprecated
protected final long getBalance(BisqAppConfig bisqAppConfig) {
return grpcStubs(bisqAppConfig).walletsService.getBalance(createBalanceRequest()).getBalance();
}
+ protected final BalancesInfo getBalances(BisqAppConfig bisqAppConfig) {
+ return grpcStubs(bisqAppConfig).walletsService.getBalances(createGetBalancesRequest()).getBalances();
+ }
+
+ protected final BsqBalanceInfo getBsqBalances(BisqAppConfig bisqAppConfig) {
+ return grpcStubs(bisqAppConfig).walletsService.getBsqBalances(createGetBsqBalancesRequest()).getBsqBalanceInfo();
+ }
+
+ protected final BtcBalanceInfo getBtcBalances(BisqAppConfig bisqAppConfig) {
+ return grpcStubs(bisqAppConfig).walletsService.getBtcBalances(createBtcBalancesRequest()).getBtcBalanceInfo();
+ }
+
+ protected final AddressBalanceInfo getAddressBalance(BisqAppConfig bisqAppConfig, String address) {
+ return grpcStubs(bisqAppConfig).walletsService.getAddressBalance(createGetAddressBalanceRequest(address)).getAddressBalanceInfo();
+ }
+
protected final void unlockWallet(BisqAppConfig bisqAppConfig, String password, long timeout) {
//noinspection ResultOfMethodCallIgnored
grpcStubs(bisqAppConfig).walletsService.unlockWallet(createUnlockWalletRequest(password, timeout));
@@ -188,6 +244,14 @@ protected final void lockWallet(BisqAppConfig bisqAppConfig) {
grpcStubs(bisqAppConfig).walletsService.lockWallet(createLockWalletRequest());
}
+ protected final String getUnusedBsqAddress(BisqAppConfig bisqAppConfig) {
+ return grpcStubs(bisqAppConfig).walletsService.getUnusedBsqAddress(createGetUnusedBsqAddressRequest()).getAddress();
+ }
+
+ protected final void sendBsq(BisqAppConfig bisqAppConfig, String address, double amount) {
+ grpcStubs(bisqAppConfig).walletsService.sendBsq(createSendBsqRequest(address, amount));
+ }
+
protected final String getUnusedBtcAddress(BisqAppConfig bisqAppConfig) {
//noinspection OptionalGetWithoutIsPresent
return grpcStubs(bisqAppConfig).walletsService.getFundingAddresses(createGetFundingAddressesRequest())
diff --git a/apitest/src/test/java/bisq/apitest/method/wallet/BsqWalletTest.java b/apitest/src/test/java/bisq/apitest/method/wallet/BsqWalletTest.java
new file mode 100644
index 00000000000..861c1839c5b
--- /dev/null
+++ b/apitest/src/test/java/bisq/apitest/method/wallet/BsqWalletTest.java
@@ -0,0 +1,246 @@
+package bisq.apitest.method.wallet;
+
+import bisq.proto.grpc.BsqBalanceInfo;
+
+import org.bitcoinj.core.LegacyAddress;
+import org.bitcoinj.core.NetworkParameters;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+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.bobdaemon;
+import static bisq.apitest.config.BisqAppConfig.seednode;
+import static bisq.cli.TableFormat.formatBsqBalanceInfoTbl;
+import static org.bitcoinj.core.NetworkParameters.PAYMENT_PROTOCOL_ID_MAINNET;
+import static org.bitcoinj.core.NetworkParameters.PAYMENT_PROTOCOL_ID_REGTEST;
+import static org.bitcoinj.core.NetworkParameters.PAYMENT_PROTOCOL_ID_TESTNET;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+
+
+
+import bisq.apitest.config.BisqAppConfig;
+import bisq.apitest.method.MethodTest;
+
+@Disabled
+@Slf4j
+@TestMethodOrder(OrderAnnotation.class)
+public class BsqWalletTest extends MethodTest {
+
+ // Alice's regtest BSQ wallet is initialized with 1,000,000 BSQ.
+ private static final bisq.core.api.model.BsqBalanceInfo ALICES_INITIAL_BSQ_BALANCES =
+ expectedBsqBalanceModel(100000000,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0);
+
+ // Bob's regtest BSQ wallet is initialized with 1,500,000 BSQ.
+ private static final bisq.core.api.model.BsqBalanceInfo BOBS_INITIAL_BSQ_BALANCES =
+ expectedBsqBalanceModel(150000000,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0);
+
+ private static final double SEND_BSQ_AMOUNT = 25000.50;
+
+ @BeforeAll
+ public static void setUp() {
+ startSupportingApps(false,
+ true,
+ bitcoind,
+ seednode,
+ arbdaemon,
+ alicedaemon,
+ bobdaemon);
+ }
+
+ @Test
+ @Order(1)
+ public void testGetUnusedBsqAddress() {
+ var request = createGetUnusedBsqAddressRequest();
+
+ String address = grpcStubs(alicedaemon).walletsService.getUnusedBsqAddress(request).getAddress();
+ assertFalse(address.isEmpty());
+ assertTrue(address.startsWith("B"));
+
+ NetworkParameters networkParameters = LegacyAddress.getParametersFromAddress(address.substring(1));
+ String addressNetwork = networkParameters.getPaymentProtocolId();
+ assertNotEquals(PAYMENT_PROTOCOL_ID_MAINNET, addressNetwork);
+ // TODO Fix bug causing the regtest bsq address network to be evaluated as 'testnet' here.
+ assertTrue(addressNetwork.equals(PAYMENT_PROTOCOL_ID_TESTNET)
+ || addressNetwork.equals(PAYMENT_PROTOCOL_ID_REGTEST));
+ }
+
+ @Test
+ @Order(2)
+ public void testInitialBsqBalances(final TestInfo testInfo) {
+ BsqBalanceInfo alicesBsqBalances = getBsqBalances(alicedaemon);
+ log.info("{} -> Alice's BSQ Initial Balances -> \n{}",
+ testName(testInfo),
+ formatBsqBalanceInfoTbl(alicesBsqBalances));
+ verifyBsqBalances(ALICES_INITIAL_BSQ_BALANCES, alicesBsqBalances);
+
+ BsqBalanceInfo bobsBsqBalances = getBsqBalances(bobdaemon);
+ log.info("{} -> Bob's BSQ Initial Balances -> \n{}",
+ testName(testInfo),
+ formatBsqBalanceInfoTbl(bobsBsqBalances));
+ verifyBsqBalances(BOBS_INITIAL_BSQ_BALANCES, bobsBsqBalances);
+ }
+
+ @Disabled // TODO
+ @Test
+ @Order(3)
+ public void testSendBsqAndCheckBalancesBeforeGeneratingBtcBlock(final TestInfo testInfo) {
+ String bobsBsqAddress = getUnusedBsqAddress(bobdaemon);
+ sendBsq(alicedaemon, bobsBsqAddress, SEND_BSQ_AMOUNT);
+ sleep(2000);
+
+ BsqBalanceInfo alicesBsqBalances = getBsqBalances(alicedaemon);
+ BsqBalanceInfo bobsBsqBalances = waitForNonZeroUnverifiedBalance(bobdaemon);
+
+ log.info("BSQ Balances Before BTC Block Gen...");
+ printBobAndAliceBsqBalances(testInfo,
+ bobsBsqBalances,
+ alicesBsqBalances,
+ alicedaemon);
+
+ verifyBsqBalances(expectedBsqBalanceModel(150000000,
+ 2500050,
+ 0,
+ 0,
+ 0,
+ 0),
+ bobsBsqBalances);
+
+ verifyBsqBalances(expectedBsqBalanceModel(97499950,
+ 97499950,
+ 97499950,
+ 0,
+ 0,
+ 0),
+ alicesBsqBalances);
+ }
+
+ @Disabled // TODO
+ @Test
+ @Order(4)
+ public void testBalancesAfterSendingBsqAndGeneratingBtcBlock(final TestInfo testInfo) {
+ // There is a wallet persist delay; we have to
+ // wait for both wallets to be saved to disk.
+ genBtcBlocksThenWait(1, 4000);
+
+ BsqBalanceInfo alicesBsqBalances = getBsqBalances(alicedaemon);
+ BsqBalanceInfo bobsBsqBalances = waitForNewAvailableConfirmedBalance(bobdaemon, 150000000);
+
+ log.info("See Available Confirmed BSQ Balances...");
+ printBobAndAliceBsqBalances(testInfo,
+ bobsBsqBalances,
+ alicesBsqBalances,
+ alicedaemon);
+
+ verifyBsqBalances(expectedBsqBalanceModel(152500050,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0),
+ bobsBsqBalances);
+
+ verifyBsqBalances(expectedBsqBalanceModel(97499950,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0),
+ alicesBsqBalances);
+ }
+
+ @AfterAll
+ public static void tearDown() {
+ tearDownScaffold();
+ }
+
+ private void verifyBsqBalances(bisq.core.api.model.BsqBalanceInfo expected,
+ BsqBalanceInfo actual) {
+ assertEquals(expected.getAvailableConfirmedBalance(), actual.getAvailableConfirmedBalance());
+ assertEquals(expected.getUnverifiedBalance(), actual.getUnverifiedBalance());
+ assertEquals(expected.getUnconfirmedChangeBalance(), actual.getUnconfirmedChangeBalance());
+ assertEquals(expected.getLockedForVotingBalance(), actual.getLockedForVotingBalance());
+ assertEquals(expected.getLockupBondsBalance(), actual.getLockupBondsBalance());
+ assertEquals(expected.getUnlockingBondsBalance(), actual.getUnlockingBondsBalance());
+ }
+
+ private BsqBalanceInfo waitForNonZeroUnverifiedBalance(BisqAppConfig daemon) {
+ // A BSQ recipient needs to wait for her daemon to detect a new tx.
+ // Loop here until her unverifiedBalance != 0, or give up after 15 seconds.
+ // A slow test is preferred over a flaky test.
+ BsqBalanceInfo bsqBalance = getBsqBalances(daemon);
+ for (int numRequests = 1; numRequests <= 15 && bsqBalance.getUnverifiedBalance() == 0; numRequests++) {
+ sleep(1000);
+ bsqBalance = getBsqBalances(daemon);
+ }
+ return bsqBalance;
+ }
+
+ private BsqBalanceInfo waitForNewAvailableConfirmedBalance(BisqAppConfig daemon,
+ long staleBalance) {
+ BsqBalanceInfo bsqBalance = getBsqBalances(daemon);
+ for (int numRequests = 1;
+ numRequests <= 15 && bsqBalance.getAvailableConfirmedBalance() == staleBalance;
+ numRequests++) {
+ sleep(1000);
+ bsqBalance = getBsqBalances(daemon);
+ }
+ return bsqBalance;
+ }
+
+ @SuppressWarnings("SameParameterValue")
+ private void printBobAndAliceBsqBalances(final TestInfo testInfo,
+ BsqBalanceInfo bobsBsqBalances,
+ BsqBalanceInfo alicesBsqBalances,
+ BisqAppConfig senderApp) {
+ log.info("{} -> Bob's BSQ Balances After {} {} BSQ-> \n{}",
+ testName(testInfo),
+ senderApp.equals(bobdaemon) ? "Sending" : "Receiving",
+ SEND_BSQ_AMOUNT,
+ formatBsqBalanceInfoTbl(bobsBsqBalances));
+
+ log.info("{} -> Alice's Balances After {} {} BSQ-> \n{}",
+ testName(testInfo),
+ senderApp.equals(alicedaemon) ? "Sending" : "Receiving",
+ SEND_BSQ_AMOUNT,
+ formatBsqBalanceInfoTbl(alicesBsqBalances));
+ }
+
+ @SuppressWarnings("SameParameterValue")
+ private static bisq.core.api.model.BsqBalanceInfo expectedBsqBalanceModel(long availableConfirmedBalance,
+ long unverifiedBalance,
+ long unconfirmedChangeBalance,
+ long lockedForVotingBalance,
+ long lockupBondsBalance,
+ long unlockingBondsBalance) {
+ return bisq.core.api.model.BsqBalanceInfo.valueOf(availableConfirmedBalance,
+ unverifiedBalance,
+ unconfirmedChangeBalance,
+ lockedForVotingBalance,
+ lockupBondsBalance,
+ unlockingBondsBalance);
+ }
+}
diff --git a/apitest/src/test/java/bisq/apitest/method/wallet/BtcWalletTest.java b/apitest/src/test/java/bisq/apitest/method/wallet/BtcWalletTest.java
new file mode 100644
index 00000000000..380198d53ee
--- /dev/null
+++ b/apitest/src/test/java/bisq/apitest/method/wallet/BtcWalletTest.java
@@ -0,0 +1,102 @@
+package bisq.apitest.method.wallet;
+
+import bisq.proto.grpc.BtcBalanceInfo;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+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.bobdaemon;
+import static bisq.apitest.config.BisqAppConfig.seednode;
+import static bisq.cli.TableFormat.formatAddressBalanceTbl;
+import static bisq.cli.TableFormat.formatBtcBalanceInfoTbl;
+import static java.util.Collections.singletonList;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+
+
+
+import bisq.apitest.method.MethodTest;
+
+@Disabled
+@Slf4j
+@TestMethodOrder(OrderAnnotation.class)
+public class BtcWalletTest extends MethodTest {
+
+ // All api tests depend on the DAO / regtest environment, and Bob & Alice's wallets
+ // are initialized with 10 BTC during the scaffolding setup.
+ private static final bisq.core.api.model.BtcBalanceInfo INITIAL_BTC_BALANCES =
+ bisq.core.api.model.BtcBalanceInfo.valueOf(1000000000,
+ 0,
+ 1000000000,
+ 0);
+
+ @BeforeAll
+ public static void setUp() {
+ startSupportingApps(false,
+ true,
+ bitcoind,
+ seednode,
+ alicedaemon,
+ bobdaemon);
+ }
+
+ @Test
+ @Order(1)
+ public void testDeprecatedAvailableBtcBalance() {
+ // Alice's regtest Bisq wallet was initialized with 10 BTC.
+ long balance = getBalance(alicedaemon); // @Deprecated method
+ assertEquals(INITIAL_BTC_BALANCES.getAvailableBalance(), balance);
+
+ // Bob's regtest Bisq wallet was initialized with 10 BTC.
+ balance = getBalance(bobdaemon); // @Deprecated method
+ assertEquals(INITIAL_BTC_BALANCES.getAvailableBalance(), balance);
+ }
+
+ @Test
+ @Order(2)
+ public void testFundAlicesBtcWallet(final TestInfo testInfo) {
+ String newAddress = getUnusedBtcAddress(alicedaemon);
+ bitcoinCli.sendToAddress(newAddress, "2.5");
+ genBtcBlocksThenWait(1, 1500);
+
+ long balance = getBalance(alicedaemon); // @Deprecated method
+ assertEquals(1250000000, balance); // new balance is 12.5 btc
+
+ log.info("{} -> Alice's Funded Address Balance -> \n{}",
+ testName(testInfo),
+ formatAddressBalanceTbl(singletonList(getAddressBalance(alicedaemon, newAddress))));
+
+ BtcBalanceInfo btcBalanceInfo = getBtcBalances(alicedaemon); // new balance is 12.5 btc
+ bisq.core.api.model.BtcBalanceInfo alicesExpectedBalances =
+ bisq.core.api.model.BtcBalanceInfo.valueOf(1250000000,
+ 0,
+ 1250000000,
+ 0);
+ verifyBtcBalances(alicesExpectedBalances, btcBalanceInfo);
+ log.info("{} -> Alice's BTC Balances After Sending 2.5 BTC -> \n{}",
+ testName(testInfo),
+ formatBtcBalanceInfoTbl(btcBalanceInfo));
+ }
+
+ @AfterAll
+ public static void tearDown() {
+ tearDownScaffold();
+ }
+
+ private void verifyBtcBalances(bisq.core.api.model.BtcBalanceInfo expected,
+ BtcBalanceInfo actual) {
+ assertEquals(expected.getAvailableBalance(), actual.getAvailableBalance());
+ assertEquals(expected.getReservedBalance(), actual.getReservedBalance());
+ assertEquals(expected.getTotalAvailableBalance(), actual.getTotalAvailableBalance());
+ assertEquals(expected.getLockedBalance(), actual.getLockedBalance());
+ }
+}
diff --git a/apitest/src/test/java/bisq/apitest/method/GetBalanceTest.java b/apitest/src/test/java/bisq/apitest/method/wallet/GetBalanceTest.java
similarity index 96%
rename from apitest/src/test/java/bisq/apitest/method/GetBalanceTest.java
rename to apitest/src/test/java/bisq/apitest/method/wallet/GetBalanceTest.java
index 1d44590837b..2c7c3466dda 100644
--- a/apitest/src/test/java/bisq/apitest/method/GetBalanceTest.java
+++ b/apitest/src/test/java/bisq/apitest/method/wallet/GetBalanceTest.java
@@ -15,7 +15,7 @@
* along with Bisq. If not, see .
*/
-package bisq.apitest.method;
+package bisq.apitest.method.wallet;
import bisq.proto.grpc.GetBalanceRequest;
@@ -36,6 +36,11 @@
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+
+
+import bisq.apitest.method.MethodTest;
+
+@Deprecated
@Disabled
@Slf4j
@TestMethodOrder(OrderAnnotation.class)
diff --git a/apitest/src/test/java/bisq/apitest/method/wallet/WalletBalancesTest.java b/apitest/src/test/java/bisq/apitest/method/wallet/WalletBalancesTest.java
new file mode 100644
index 00000000000..6c168843668
--- /dev/null
+++ b/apitest/src/test/java/bisq/apitest/method/wallet/WalletBalancesTest.java
@@ -0,0 +1,79 @@
+package bisq.apitest.method.wallet;
+
+import bisq.proto.grpc.BalancesInfo;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+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.bobdaemon;
+import static bisq.apitest.config.BisqAppConfig.seednode;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+
+import bisq.apitest.method.MethodTest;
+import bisq.cli.TableFormat;
+
+@Disabled
+@Slf4j
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class WalletBalancesTest extends MethodTest {
+
+ // All api tests depend on the DAO / regtest environment, and Bob & Alice's wallets
+ // are initialized with 10 BTC during the scaffolding setup.
+ private static final bisq.core.api.model.BtcBalanceInfo INITIAL_BTC_BALANCES =
+ bisq.core.api.model.BtcBalanceInfo.valueOf(1000000000,
+ 0,
+ 1000000000,
+ 0);
+
+ @BeforeAll
+ public static void setUp() {
+ startSupportingApps(false,
+ true,
+ bitcoind,
+ seednode,
+ alicedaemon,
+ bobdaemon);
+ }
+
+ @Test
+ @Order(1)
+ public void testDeprecatedAvailableBtcBalance() {
+ // Alice's regtest Bisq wallet was initialized with 10 BTC.
+ long balance = getBalance(alicedaemon); // @Deprecated method
+ assertEquals(INITIAL_BTC_BALANCES.getAvailableBalance(), balance);
+
+ // Bob's regtest Bisq wallet was initialized with 10 BTC.
+ balance = getBalance(bobdaemon); // @Deprecated method
+ assertEquals(INITIAL_BTC_BALANCES.getAvailableBalance(), balance);
+ }
+
+ @Test
+ @Order(2)
+ public void testNewGetBalances(final TestInfo testInfo) {
+ BalancesInfo alicesBalances = getBalances(alicedaemon);
+ BalancesInfo bobsBalances = getBalances(bobdaemon);
+
+ log.info("{} Alice's Balances:\n{}", testName(testInfo), TableFormat.formatBalancesTbls(alicesBalances));
+ log.info("{} Bob's Balances:\n{}", testName(testInfo), TableFormat.formatBalancesTbls(bobsBalances));
+
+ assertEquals(INITIAL_BTC_BALANCES.getAvailableBalance(), alicesBalances.getBtcBalanceInfo().getAvailableBalance());
+ assertEquals(INITIAL_BTC_BALANCES.getAvailableBalance(), bobsBalances.getBtcBalanceInfo().getAvailableBalance());
+ }
+
+ @AfterAll
+ public static void tearDown() {
+ tearDownScaffold();
+ }
+}
diff --git a/apitest/src/test/java/bisq/apitest/method/WalletProtectionTest.java b/apitest/src/test/java/bisq/apitest/method/wallet/WalletProtectionTest.java
similarity index 98%
rename from apitest/src/test/java/bisq/apitest/method/WalletProtectionTest.java
rename to apitest/src/test/java/bisq/apitest/method/wallet/WalletProtectionTest.java
index 08547e9ebb9..82174f5195a 100644
--- a/apitest/src/test/java/bisq/apitest/method/WalletProtectionTest.java
+++ b/apitest/src/test/java/bisq/apitest/method/wallet/WalletProtectionTest.java
@@ -1,4 +1,4 @@
-package bisq.apitest.method;
+package bisq.apitest.method.wallet;
import io.grpc.StatusRuntimeException;
@@ -18,6 +18,10 @@
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+
+
+import bisq.apitest.method.MethodTest;
+
@SuppressWarnings("ResultOfMethodCallIgnored")
@Disabled
@Slf4j
diff --git a/apitest/src/test/java/bisq/apitest/scenario/WalletTest.java b/apitest/src/test/java/bisq/apitest/scenario/WalletTest.java
index ecd38dc2295..f6240512230 100644
--- a/apitest/src/test/java/bisq/apitest/scenario/WalletTest.java
+++ b/apitest/src/test/java/bisq/apitest/scenario/WalletTest.java
@@ -24,55 +24,69 @@
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
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.bobdaemon;
import static bisq.apitest.config.BisqAppConfig.seednode;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.fail;
import bisq.apitest.method.MethodTest;
-import bisq.apitest.method.WalletProtectionTest;
+import bisq.apitest.method.wallet.BsqWalletTest;
+import bisq.apitest.method.wallet.BtcWalletTest;
+import bisq.apitest.method.wallet.WalletBalancesTest;
+import bisq.apitest.method.wallet.WalletProtectionTest;
@Slf4j
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class WalletTest extends MethodTest {
- // All tests depend on the DAO / regtest environment, and Alice's wallet is
- // initialized with 10 BTC during the scaffolding setup.
-
@BeforeAll
public static void setUp() {
- try {
- setUpScaffold(bitcoind, seednode, alicedaemon);
- genBtcBlocksThenWait(1, 1500);
- } catch (Exception ex) {
- fail(ex);
- }
+ startSupportingApps(true,
+ true,
+ bitcoind,
+ seednode,
+ arbdaemon,
+ alicedaemon,
+ bobdaemon);
}
@Test
@Order(1)
- public void testFundWallet() {
- // The regtest Bisq wallet was initialized with 10 BTC.
- long balance = getBalance(alicedaemon);
- assertEquals(1000000000, balance);
+ public void testGetWalletBalances(final TestInfo testInfo) {
+ WalletBalancesTest btcWalletTest = new WalletBalancesTest();
+
+ btcWalletTest.testDeprecatedAvailableBtcBalance();
+ btcWalletTest.testNewGetBalances(testInfo);
+ }
- String unusedAddress = getUnusedBtcAddress(alicedaemon);
- bitcoinCli.sendToAddress(unusedAddress, "2.5");
+ @Test
+ @Order(2)
+ public void testBtcWalletFunding(final TestInfo testInfo) {
+ BtcWalletTest btcWalletTest = new BtcWalletTest();
- bitcoinCli.generateBlocks(1);
- sleep(1500);
+ btcWalletTest.testDeprecatedAvailableBtcBalance();
+ btcWalletTest.testFundAlicesBtcWallet(testInfo);
+ }
- balance = getBalance(alicedaemon);
- assertEquals(1250000000L, balance); // new balance is 12.5 btc
+ @Test
+ @Order(3)
+ public void testBsqWalletFunding(final TestInfo testInfo) {
+ BsqWalletTest bsqWalletTest = new BsqWalletTest();
+
+ bsqWalletTest.testGetUnusedBsqAddress();
+ bsqWalletTest.testInitialBsqBalances(testInfo);
+ //bsqWalletTest.testSendBsqAndCheckBalancesBeforeGeneratingBtcBlock(testInfo); // TODO
+ //bsqWalletTest.testBalancesAfterSendingBsqAndGeneratingBtcBlock(testInfo); // TODO
}
@Test
- @Order(2)
+ @Order(4)
public void testWalletProtection() {
// Batching all wallet tests in this test case reduces scaffold setup
// time. Here, we create a method WalletProtectionTest instance and run each
diff --git a/cli/src/main/java/bisq/cli/CliMain.java b/cli/src/main/java/bisq/cli/CliMain.java
index ec0e5e71bb6..2226d352004 100644
--- a/cli/src/main/java/bisq/cli/CliMain.java
+++ b/cli/src/main/java/bisq/cli/CliMain.java
@@ -24,11 +24,15 @@
import bisq.proto.grpc.CreatePaymentAccountRequest;
import bisq.proto.grpc.GetAddressBalanceRequest;
import bisq.proto.grpc.GetBalanceRequest;
+import bisq.proto.grpc.GetBalancesRequest;
+import bisq.proto.grpc.GetBsqBalancesRequest;
+import bisq.proto.grpc.GetBtcBalancesRequest;
import bisq.proto.grpc.GetFundingAddressesRequest;
import bisq.proto.grpc.GetOfferRequest;
import bisq.proto.grpc.GetOffersRequest;
import bisq.proto.grpc.GetPaymentAccountsRequest;
import bisq.proto.grpc.GetTradeRequest;
+import bisq.proto.grpc.GetUnusedBsqAddressRequest;
import bisq.proto.grpc.GetVersionRequest;
import bisq.proto.grpc.KeepFundsRequest;
import bisq.proto.grpc.LockWalletRequest;
@@ -57,6 +61,7 @@
import static bisq.cli.CurrencyFormat.toSatoshis;
import static bisq.cli.NegativeNumberOptions.hasNegativeNumberOptions;
import static bisq.cli.TableFormat.formatAddressBalanceTbl;
+import static bisq.cli.TableFormat.formatBalancesTbls;
import static bisq.cli.TableFormat.formatOfferTable;
import static bisq.cli.TableFormat.formatPaymentAcctTbl;
import static java.lang.String.format;
@@ -87,9 +92,13 @@ private enum Method {
createpaymentacct,
getpaymentaccts,
getversion,
- getbalance,
+ @Deprecated getbalance, // Use getbalances, return bsq and btc balance info
+ getbalances,
+ getbsqbalance,
+ getbtcbalance,
getaddressbalance,
getfundingaddresses,
+ getunusedbsqaddress,
lockwallet,
unlockwallet,
removewalletpassword,
@@ -183,12 +192,31 @@ public static void run(String[] args) {
return;
}
case getbalance: {
+ // Deprecated, use getbalances.
var request = GetBalanceRequest.newBuilder().build();
var reply = walletsService.getBalance(request);
var btcBalance = formatSatoshis(reply.getBalance());
out.println(btcBalance);
return;
}
+ case getbalances: {
+ var request = GetBalancesRequest.newBuilder().build();
+ var reply = walletsService.getBalances(request);
+ out.println(formatBalancesTbls(reply.getBalances()));
+ return;
+ }
+ case getbsqbalance: {
+ var request = GetBsqBalancesRequest.newBuilder().build();
+ var reply = walletsService.getBsqBalances(request);
+ out.println(reply.getBsqBalanceInfo());
+ return;
+ }
+ case getbtcbalance: {
+ var request = GetBtcBalancesRequest.newBuilder().build();
+ var reply = walletsService.getBtcBalances(request);
+ out.println(reply.getBtcBalanceInfo());
+ return;
+ }
case getaddressbalance: {
if (nonOptionArgs.size() < 2)
throw new IllegalArgumentException("no address specified");
@@ -205,6 +233,12 @@ public static void run(String[] args) {
out.println(formatAddressBalanceTbl(reply.getAddressBalanceInfoList()));
return;
}
+ case getunusedbsqaddress: {
+ var request = GetUnusedBsqAddressRequest.newBuilder().build();
+ var reply = walletsService.getUnusedBsqAddress(request);
+ out.println(reply.getAddress());
+ return;
+ }
case createoffer: {
if (nonOptionArgs.size() < 9)
throw new IllegalArgumentException("incorrect parameter count,"
@@ -223,6 +257,7 @@ public static void run(String[] args) {
marketPriceMargin = new BigDecimal(nonOptionArgs.get(7));
else
fixedPrice = nonOptionArgs.get(7);
+
var securityDeposit = new BigDecimal(nonOptionArgs.get(8));
var request = CreateOfferRequest.newBuilder()
@@ -283,7 +318,8 @@ public static void run(String[] args) {
}
case takeoffer: {
if (nonOptionArgs.size() < 3)
- throw new IllegalArgumentException("incorrect parameter count, expecting offer id, payment acct id");
+ throw new IllegalArgumentException("incorrect parameter count, "
+ + " expecting offer id, payment acct id");
var offerId = nonOptionArgs.get(1);
var paymentAccountId = nonOptionArgs.get(2);
@@ -297,7 +333,8 @@ public static void run(String[] args) {
}
case gettrade: {
if (nonOptionArgs.size() < 2)
- throw new IllegalArgumentException("incorrect parameter count, expecting trade id, [,showcontract = true|false]");
+ throw new IllegalArgumentException("incorrect parameter count, "
+ + " expecting trade id [,showcontract = true|false]");
var tradeId = nonOptionArgs.get(1);
var showContract = false;
@@ -352,7 +389,8 @@ public static void run(String[] args) {
}
case withdrawfunds: {
if (nonOptionArgs.size() < 3)
- throw new IllegalArgumentException("incorrect parameter count, expecting trade id, bitcoin wallet address");
+ throw new IllegalArgumentException("incorrect parameter count, "
+ + " expecting trade id, bitcoin wallet address");
var tradeId = nonOptionArgs.get(1);
var address = nonOptionArgs.get(2);
@@ -482,9 +520,13 @@ private static void printHelp(OptionParser parser, PrintStream stream) {
stream.format(rowFormat, "Method", "Params", "Description");
stream.format(rowFormat, "------", "------", "------------");
stream.format(rowFormat, "getversion", "", "Get server version");
- stream.format(rowFormat, "getbalance", "", "Get server wallet balance");
+ stream.format(rowFormat, "getbalance", "", "Get server wallet balance (deprecated, use getbalances");
+ stream.format(rowFormat, "getbalances", "", "Get server wallet bsq and btc balances");
+ stream.format(rowFormat, "getbsqbalance", "", "Get server wallet bsq balance");
+ stream.format(rowFormat, "getbtcbalance", "", "Get server wallet btc balance");
stream.format(rowFormat, "getaddressbalance", "address", "Get server wallet address balance");
stream.format(rowFormat, "getfundingaddresses", "", "Get BTC funding addresses");
+ stream.format(rowFormat, "getunusedbsqaddress", "", "Get unused BSQ address");
stream.format(rowFormat, "createoffer", "payment acct id, buy | sell, currency code, \\", "Create and place an offer");
stream.format(rowFormat, "", "amount (btc), min amount, use mkt based price, \\", "");
stream.format(rowFormat, "", "fixed price (btc) | mkt price margin (%), \\", "");
@@ -493,7 +535,7 @@ private static void printHelp(OptionParser parser, PrintStream stream) {
stream.format(rowFormat, "getoffer", "offer id", "Get current offer with id");
stream.format(rowFormat, "getoffers", "buy | sell, currency code", "Get current offers");
stream.format(rowFormat, "takeoffer", "offer id", "Take offer with id");
- stream.format(rowFormat, "gettrade", "trade id [,showcontract]", "Get trade summary or full contract");
+ stream.format(rowFormat, "gettrade", "trade id [,showcontract = true|false]", "Get trade summary or full contract");
stream.format(rowFormat, "confirmpaymentstarted", "trade id", "Confirm payment started");
stream.format(rowFormat, "confirmpaymentreceived", "trade id", "Confirm payment received");
stream.format(rowFormat, "keepfunds", "trade id", "Keep received funds in Bisq wallet");
diff --git a/cli/src/main/java/bisq/cli/ColumnHeaderConstants.java b/cli/src/main/java/bisq/cli/ColumnHeaderConstants.java
index 03500e4f47a..59b6230a2eb 100644
--- a/cli/src/main/java/bisq/cli/ColumnHeaderConstants.java
+++ b/cli/src/main/java/bisq/cli/ColumnHeaderConstants.java
@@ -29,9 +29,18 @@ class ColumnHeaderConstants {
// such as COL_HEADER_CREATION_DATE, COL_HEADER_VOLUME and COL_HEADER_UUID, the
// expected max data string length is accounted for. In others, the column header length
// are expected to be greater than any column value length.
- static final String COL_HEADER_ADDRESS = padEnd("Address", 34, ' ');
+ static final String COL_HEADER_ADDRESS = padEnd("%-3s Address", 52, ' ');
static final String COL_HEADER_AMOUNT = padEnd("BTC(min - max)", 24, ' ');
- static final String COL_HEADER_BALANCE = padStart("Balance", 12, ' ');
+ static final String COL_HEADER_AVAILABLE_BALANCE = "Available Balance";
+ static final String COL_HEADER_AVAILABLE_CONFIRMED_BALANCE = "Available Confirmed Balance";
+ static final String COL_HEADER_UNCONFIRMED_CHANGE_BALANCE = "Unconfirmed Change Balance";
+ static final String COL_HEADER_RESERVED_BALANCE = "Reserved Balance";
+ static final String COL_HEADER_TOTAL_AVAILABLE_BALANCE = "Total Available Balance";
+ static final String COL_HEADER_LOCKED_BALANCE = "Locked Balance";
+ static final String COL_HEADER_LOCKED_FOR_VOTING_BALANCE = "Locked For Voting Balance";
+ static final String COL_HEADER_LOCKUP_BONDS_BALANCE = "Lockup Bonds Balance";
+ static final String COL_HEADER_UNLOCKING_BONDS_BALANCE = "Unlocking Bonds Balance";
+ static final String COL_HEADER_UNVERIFIED_BALANCE = "Unverified Balance";
static final String COL_HEADER_CONFIRMATIONS = "Confirmations";
static final String COL_HEADER_CREATION_DATE = padEnd("Creation Date (UTC)", 20, ' ');
static final String COL_HEADER_CURRENCY = "Currency";
diff --git a/cli/src/main/java/bisq/cli/CurrencyFormat.java b/cli/src/main/java/bisq/cli/CurrencyFormat.java
index e4d8f89c6c7..a4766690eff 100644
--- a/cli/src/main/java/bisq/cli/CurrencyFormat.java
+++ b/cli/src/main/java/bisq/cli/CurrencyFormat.java
@@ -37,12 +37,19 @@ public class CurrencyFormat {
static final BigDecimal SATOSHI_DIVISOR = new BigDecimal(100000000);
static final DecimalFormat BTC_FORMAT = new DecimalFormat("###,##0.00000000");
- @VisibleForTesting
+ static final BigDecimal BSQ_SATOSHI_DIVISOR = new BigDecimal(100);
+ static final DecimalFormat BSQ_FORMAT = new DecimalFormat("###,###,###,##0.00");
+
@SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
public static String formatSatoshis(long sats) {
return BTC_FORMAT.format(BigDecimal.valueOf(sats).divide(SATOSHI_DIVISOR));
}
+ @SuppressWarnings("BigDecimalMethodWithoutRoundingCalled")
+ public static String formatBsq(long sats) {
+ return BSQ_FORMAT.format(BigDecimal.valueOf(sats).divide(BSQ_SATOSHI_DIVISOR));
+ }
+
static String formatAmountRange(long minAmount, long amount) {
return minAmount != amount
? formatSatoshis(minAmount) + " - " + formatSatoshis(amount)
diff --git a/cli/src/main/java/bisq/cli/TableFormat.java b/cli/src/main/java/bisq/cli/TableFormat.java
index 8336fff9ba1..ff4e440f18f 100644
--- a/cli/src/main/java/bisq/cli/TableFormat.java
+++ b/cli/src/main/java/bisq/cli/TableFormat.java
@@ -18,10 +18,15 @@
package bisq.cli;
import bisq.proto.grpc.AddressBalanceInfo;
+import bisq.proto.grpc.BalancesInfo;
+import bisq.proto.grpc.BsqBalanceInfo;
+import bisq.proto.grpc.BtcBalanceInfo;
import bisq.proto.grpc.OfferInfo;
import protobuf.PaymentAccount;
+import com.google.common.annotations.VisibleForTesting;
+
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -30,28 +35,28 @@
import java.util.stream.Collectors;
import static bisq.cli.ColumnHeaderConstants.*;
-import static bisq.cli.CurrencyFormat.formatAmountRange;
-import static bisq.cli.CurrencyFormat.formatOfferPrice;
-import static bisq.cli.CurrencyFormat.formatSatoshis;
-import static bisq.cli.CurrencyFormat.formatVolumeRange;
+import static bisq.cli.CurrencyFormat.*;
import static com.google.common.base.Strings.padEnd;
import static java.lang.String.format;
import static java.util.Collections.max;
import static java.util.Comparator.comparing;
import static java.util.TimeZone.getTimeZone;
-class TableFormat {
+@VisibleForTesting
+public class TableFormat {
static final TimeZone TZ_UTC = getTimeZone("UTC");
static final SimpleDateFormat DATE_FORMAT_ISO_8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
- static String formatAddressBalanceTbl(List addressBalanceInfo) {
- String headerLine = (COL_HEADER_ADDRESS + COL_HEADER_DELIMITER
- + COL_HEADER_BALANCE + COL_HEADER_DELIMITER
- + COL_HEADER_CONFIRMATIONS + COL_HEADER_DELIMITER + "\n");
- String colDataFormat = "%-" + COL_HEADER_ADDRESS.length() + "s" // left justify
- + " %" + COL_HEADER_BALANCE.length() + "s" // right justify
- + " %" + COL_HEADER_CONFIRMATIONS.length() + "d"; // right justify
+ public static String formatAddressBalanceTbl(List addressBalanceInfo) {
+ String headerFormatString = COL_HEADER_ADDRESS + COL_HEADER_DELIMITER
+ + COL_HEADER_AVAILABLE_BALANCE + COL_HEADER_DELIMITER
+ + COL_HEADER_CONFIRMATIONS + COL_HEADER_DELIMITER + "\n";
+ String headerLine = format(headerFormatString, "BTC");
+
+ String colDataFormat = "%-" + COL_HEADER_ADDRESS.length() + "s" // lt justify
+ + " %" + (COL_HEADER_AVAILABLE_BALANCE.length() - 1) + "s" // rt justify
+ + " %" + COL_HEADER_CONFIRMATIONS.length() + "d"; // lt justify
return headerLine
+ addressBalanceInfo.stream()
.map(info -> format(colDataFormat,
@@ -61,15 +66,58 @@ static String formatAddressBalanceTbl(List addressBalanceInf
.collect(Collectors.joining("\n"));
}
- static String formatOfferTable(List offerInfo, String fiatCurrency) {
+ public static String formatBalancesTbls(BalancesInfo balancesInfo) {
+ return "BTC" + "\n"
+ + formatBtcBalanceInfoTbl(balancesInfo.getBtcBalanceInfo()) + "\n"
+ + "BSQ" + "\n"
+ + formatBsqBalanceInfoTbl(balancesInfo.getBsqBalanceInfo());
+ }
+
+ public static String formatBsqBalanceInfoTbl(BsqBalanceInfo bsqBalanceInfo) {
+ String headerLine = COL_HEADER_AVAILABLE_CONFIRMED_BALANCE + COL_HEADER_DELIMITER
+ + COL_HEADER_UNVERIFIED_BALANCE + COL_HEADER_DELIMITER
+ + COL_HEADER_UNCONFIRMED_CHANGE_BALANCE + COL_HEADER_DELIMITER
+ + COL_HEADER_LOCKED_FOR_VOTING_BALANCE + COL_HEADER_DELIMITER
+ + COL_HEADER_LOCKUP_BONDS_BALANCE + COL_HEADER_DELIMITER
+ + COL_HEADER_UNLOCKING_BONDS_BALANCE + COL_HEADER_DELIMITER + "\n";
+ String colDataFormat = "%" + COL_HEADER_AVAILABLE_CONFIRMED_BALANCE.length() + "s" // rt justify
+ + " %" + (COL_HEADER_UNVERIFIED_BALANCE.length() + 1) + "s" // rt justify
+ + " %" + (COL_HEADER_UNCONFIRMED_CHANGE_BALANCE.length() + 1) + "s" // rt justify
+ + " %" + (COL_HEADER_LOCKED_FOR_VOTING_BALANCE.length() + 1) + "s" // rt justify
+ + " %" + (COL_HEADER_LOCKUP_BONDS_BALANCE.length() + 1) + "s" // rt justify
+ + " %" + (COL_HEADER_UNLOCKING_BONDS_BALANCE.length() + 1) + "s"; // rt justify
+ return headerLine + format(colDataFormat,
+ formatBsq(bsqBalanceInfo.getAvailableConfirmedBalance()),
+ formatBsq(bsqBalanceInfo.getUnverifiedBalance()),
+ formatBsq(bsqBalanceInfo.getUnconfirmedChangeBalance()),
+ formatBsq(bsqBalanceInfo.getLockedForVotingBalance()),
+ formatBsq(bsqBalanceInfo.getLockupBondsBalance()),
+ formatBsq(bsqBalanceInfo.getUnlockingBondsBalance()));
+ }
+
+ public static String formatBtcBalanceInfoTbl(BtcBalanceInfo btcBalanceInfo) {
+ String headerLine = COL_HEADER_AVAILABLE_BALANCE + COL_HEADER_DELIMITER
+ + COL_HEADER_RESERVED_BALANCE + COL_HEADER_DELIMITER
+ + COL_HEADER_TOTAL_AVAILABLE_BALANCE + COL_HEADER_DELIMITER
+ + COL_HEADER_LOCKED_BALANCE + COL_HEADER_DELIMITER + "\n";
+ String colDataFormat = "%" + COL_HEADER_AVAILABLE_BALANCE.length() + "s" // rt justify
+ + " %" + (COL_HEADER_RESERVED_BALANCE.length() + 1) + "s" // rt justify
+ + " %" + (COL_HEADER_TOTAL_AVAILABLE_BALANCE.length() + 1) + "s" // rt justify
+ + " %" + (COL_HEADER_LOCKED_BALANCE.length() + 1) + "s"; // rt justify
+ return headerLine + format(colDataFormat,
+ formatSatoshis(btcBalanceInfo.getAvailableBalance()),
+ formatSatoshis(btcBalanceInfo.getReservedBalance()),
+ formatSatoshis(btcBalanceInfo.getTotalAvailableBalance()),
+ formatSatoshis(btcBalanceInfo.getLockedBalance()));
+ }
+ static String formatOfferTable(List offerInfo, String fiatCurrency) {
// Some column values might be longer than header, so we need to calculate them.
int paymentMethodColWidth = getLengthOfLongestColumn(
COL_HEADER_PAYMENT_METHOD.length(),
offerInfo.stream()
.map(OfferInfo::getPaymentMethodShortName)
.collect(Collectors.toList()));
-
String headersFormat = COL_HEADER_DIRECTION + COL_HEADER_DELIMITER
+ COL_HEADER_PRICE + COL_HEADER_DELIMITER // includes %s -> fiatCurrency
+ COL_HEADER_AMOUNT + COL_HEADER_DELIMITER
diff --git a/core/src/main/java/bisq/core/api/CoreApi.java b/core/src/main/java/bisq/core/api/CoreApi.java
index 7cfcc5ce152..bd1ac198a26 100644
--- a/core/src/main/java/bisq/core/api/CoreApi.java
+++ b/core/src/main/java/bisq/core/api/CoreApi.java
@@ -18,6 +18,9 @@
package bisq.core.api;
import bisq.core.api.model.AddressBalanceInfo;
+import bisq.core.api.model.BalancesInfo;
+import bisq.core.api.model.BsqBalanceInfo;
+import bisq.core.api.model.BtcBalanceInfo;
import bisq.core.monetary.Price;
import bisq.core.offer.Offer;
import bisq.core.offer.OfferPayload;
@@ -213,10 +216,23 @@ public String getTradeRole(String tradeId) {
// Wallets
///////////////////////////////////////////////////////////////////////////////////////////
+ @Deprecated
public long getAvailableBalance() {
return walletsService.getAvailableBalance();
}
+ public BalancesInfo getBalances() {
+ return walletsService.getBalances();
+ }
+
+ public BsqBalanceInfo getBsqBalances() {
+ return walletsService.getBsqBalances();
+ }
+
+ public BtcBalanceInfo getBtcBalances() {
+ return walletsService.getBtcBalances();
+ }
+
public long getAddressBalance(String addressString) {
return walletsService.getAddressBalance(addressString);
}
@@ -229,6 +245,10 @@ public List getFundingAddresses() {
return walletsService.getFundingAddresses();
}
+ public String getUnusedBsqAddress() {
+ return walletsService.getUnusedBsqAddress();
+ }
+
public void setWalletPassword(String password, String newPassword) {
walletsService.setWalletPassword(password, newPassword);
}
diff --git a/core/src/main/java/bisq/core/api/CoreWalletsService.java b/core/src/main/java/bisq/core/api/CoreWalletsService.java
index fc15ec5062a..3284a457730 100644
--- a/core/src/main/java/bisq/core/api/CoreWalletsService.java
+++ b/core/src/main/java/bisq/core/api/CoreWalletsService.java
@@ -18,8 +18,12 @@
package bisq.core.api;
import bisq.core.api.model.AddressBalanceInfo;
+import bisq.core.api.model.BalancesInfo;
+import bisq.core.api.model.BsqBalanceInfo;
+import bisq.core.api.model.BtcBalanceInfo;
import bisq.core.btc.Balances;
import bisq.core.btc.model.AddressEntry;
+import bisq.core.btc.wallet.BsqWalletService;
import bisq.core.btc.wallet.BtcWalletService;
import bisq.core.btc.wallet.WalletsManager;
@@ -55,6 +59,7 @@ class CoreWalletsService {
private final Balances balances;
private final WalletsManager walletsManager;
+ private final BsqWalletService bsqWalletService;
private final BtcWalletService btcWalletService;
@Nullable
@@ -66,9 +71,11 @@ class CoreWalletsService {
@Inject
public CoreWalletsService(Balances balances,
WalletsManager walletsManager,
+ BsqWalletService bsqWalletService,
BtcWalletService btcWalletService) {
this.balances = balances;
this.walletsManager = walletsManager;
+ this.bsqWalletService = bsqWalletService;
this.btcWalletService = btcWalletService;
}
@@ -78,6 +85,7 @@ KeyParameter getKey() {
return tempAesKey;
}
+ @Deprecated
long getAvailableBalance() {
verifyWalletsAreAvailable();
verifyEncryptedWalletIsUnlocked();
@@ -89,6 +97,56 @@ long getAvailableBalance() {
return balance.getValue();
}
+ BalancesInfo getBalances() {
+ verifyWalletsAreAvailable();
+ verifyEncryptedWalletIsUnlocked();
+ if (balances.getAvailableBalance().get() == null)
+ throw new IllegalStateException("balance is not yet available");
+
+ return new BalancesInfo(getBsqBalances(), getBtcBalances());
+ }
+
+ BsqBalanceInfo getBsqBalances() {
+ verifyWalletsAreAvailable();
+ verifyEncryptedWalletIsUnlocked();
+
+ var availableConfirmedBalance = bsqWalletService.getAvailableConfirmedBalance();
+ var unverifiedBalance = bsqWalletService.getUnverifiedBalance();
+ var unconfirmedChangeBalance = bsqWalletService.getUnconfirmedChangeBalance();
+ var lockedForVotingBalance = bsqWalletService.getLockedForVotingBalance();
+ var lockupBondsBalance = bsqWalletService.getLockupBondsBalance();
+ var unlockingBondsBalance = bsqWalletService.getUnlockingBondsBalance();
+
+ return new BsqBalanceInfo(availableConfirmedBalance.value,
+ unverifiedBalance.value,
+ unconfirmedChangeBalance.value,
+ lockedForVotingBalance.value,
+ lockupBondsBalance.value,
+ unlockingBondsBalance.value);
+ }
+
+ BtcBalanceInfo getBtcBalances() {
+ verifyWalletsAreAvailable();
+ verifyEncryptedWalletIsUnlocked();
+
+ var availableBalance = balances.getAvailableBalance().get();
+ if (availableBalance == null)
+ throw new IllegalStateException("balance is not yet available");
+
+ var reservedBalance = balances.getReservedBalance().get();
+ if (reservedBalance == null)
+ throw new IllegalStateException("reserved balance is not yet available");
+
+ var lockedBalance = balances.getLockedBalance().get();
+ if (lockedBalance == null)
+ throw new IllegalStateException("locked balance is not yet available");
+
+ return new BtcBalanceInfo(availableBalance.value,
+ reservedBalance.value,
+ availableBalance.add(reservedBalance).value,
+ lockedBalance.value);
+ }
+
long getAddressBalance(String addressString) {
Address address = getAddressEntry(addressString).getAddress();
return btcWalletService.getBalanceForAddress(address).value;
@@ -134,6 +192,10 @@ List getFundingAddresses() {
.collect(Collectors.toList());
}
+ String getUnusedBsqAddress() {
+ return bsqWalletService.getUnusedBsqAddressAsString();
+ }
+
int getNumConfirmationsForMostRecentTransaction(String addressString) {
Address address = getAddressEntry(addressString).getAddress();
TransactionConfidence confidence = btcWalletService.getConfidenceForAddress(address);
diff --git a/core/src/main/java/bisq/core/api/model/BalancesInfo.java b/core/src/main/java/bisq/core/api/model/BalancesInfo.java
new file mode 100644
index 00000000000..39179fde2b3
--- /dev/null
+++ b/core/src/main/java/bisq/core/api/model/BalancesInfo.java
@@ -0,0 +1,42 @@
+package bisq.core.api.model;
+
+import bisq.common.Payload;
+
+import lombok.Getter;
+
+@Getter
+public class BalancesInfo implements Payload {
+
+ private final BsqBalanceInfo bsqBalanceInfo;
+ private final BtcBalanceInfo btcBalanceInfo;
+
+ public BalancesInfo(BsqBalanceInfo bsqBalanceInfo, BtcBalanceInfo btcBalanceInfo) {
+ this.bsqBalanceInfo = bsqBalanceInfo;
+ this.btcBalanceInfo = btcBalanceInfo;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // PROTO BUFFER
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public bisq.proto.grpc.BalancesInfo toProtoMessage() {
+ return bisq.proto.grpc.BalancesInfo.newBuilder()
+ .setBsqBalanceInfo(bsqBalanceInfo.toProtoMessage())
+ .setBtcBalanceInfo(btcBalanceInfo.toProtoMessage())
+ .build();
+ }
+
+ public static BalancesInfo fromProto(bisq.proto.grpc.BalancesInfo proto) {
+ return new BalancesInfo(BsqBalanceInfo.fromProto(proto.getBsqBalanceInfo()),
+ BtcBalanceInfo.fromProto(proto.getBtcBalanceInfo()));
+ }
+
+ @Override
+ public String toString() {
+ return "BalancesInfo{" + "\n" +
+ " " + bsqBalanceInfo.toString() + "\n" +
+ ", " + btcBalanceInfo.toString() + "\n" +
+ '}';
+ }
+}
diff --git a/core/src/main/java/bisq/core/api/model/BsqBalanceInfo.java b/core/src/main/java/bisq/core/api/model/BsqBalanceInfo.java
new file mode 100644
index 00000000000..ff314e087ba
--- /dev/null
+++ b/core/src/main/java/bisq/core/api/model/BsqBalanceInfo.java
@@ -0,0 +1,87 @@
+package bisq.core.api.model;
+
+import bisq.common.Payload;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import lombok.Getter;
+
+@Getter
+public class BsqBalanceInfo implements Payload {
+
+ // All balances are in BSQ satoshis.
+ private final long availableConfirmedBalance;
+ private final long unverifiedBalance;
+ private final long unconfirmedChangeBalance;
+ private final long lockedForVotingBalance;
+ private final long lockupBondsBalance;
+ private final long unlockingBondsBalance;
+
+ public BsqBalanceInfo(long availableConfirmedBalance,
+ long unverifiedBalance,
+ long unconfirmedChangeBalance,
+ long lockedForVotingBalance,
+ long lockupBondsBalance,
+ long unlockingBondsBalance) {
+ this.availableConfirmedBalance = availableConfirmedBalance;
+ this.unverifiedBalance = unverifiedBalance;
+ this.unconfirmedChangeBalance = unconfirmedChangeBalance;
+ this.lockedForVotingBalance = lockedForVotingBalance;
+ this.lockupBondsBalance = lockupBondsBalance;
+ this.unlockingBondsBalance = unlockingBondsBalance;
+ }
+
+ @VisibleForTesting
+ public static BsqBalanceInfo valueOf(long availableConfirmedBalance,
+ long unverifiedBalance,
+ long unconfirmedChangeBalance,
+ long lockedForVotingBalance,
+ long lockupBondsBalance,
+ long unlockingBondsBalance) {
+ // Convenience for creating a model instance instead of a proto.
+ return new BsqBalanceInfo(availableConfirmedBalance,
+ unverifiedBalance,
+ unconfirmedChangeBalance,
+ lockedForVotingBalance,
+ lockupBondsBalance,
+ unlockingBondsBalance);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // PROTO BUFFER
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public bisq.proto.grpc.BsqBalanceInfo toProtoMessage() {
+ return bisq.proto.grpc.BsqBalanceInfo.newBuilder()
+ .setAvailableConfirmedBalance(availableConfirmedBalance)
+ .setUnverifiedBalance(unverifiedBalance)
+ .setUnconfirmedChangeBalance(unconfirmedChangeBalance)
+ .setLockedForVotingBalance(lockedForVotingBalance)
+ .setLockupBondsBalance(lockupBondsBalance)
+ .setUnlockingBondsBalance(unlockingBondsBalance)
+ .build();
+
+ }
+
+ public static BsqBalanceInfo fromProto(bisq.proto.grpc.BsqBalanceInfo proto) {
+ return new BsqBalanceInfo(proto.getAvailableConfirmedBalance(),
+ proto.getUnverifiedBalance(),
+ proto.getUnconfirmedChangeBalance(),
+ proto.getLockedForVotingBalance(),
+ proto.getLockupBondsBalance(),
+ proto.getUnlockingBondsBalance());
+ }
+
+ @Override
+ public String toString() {
+ return "BsqBalanceInfo{" +
+ "availableConfirmedBalance=" + availableConfirmedBalance +
+ ", unverifiedBalance=" + unverifiedBalance +
+ ", unconfirmedChangeBalance=" + unconfirmedChangeBalance +
+ ", lockedForVotingBalance=" + lockedForVotingBalance +
+ ", lockupBondsBalance=" + lockupBondsBalance +
+ ", unlockingBondsBalance=" + unlockingBondsBalance +
+ '}';
+ }
+}
diff --git a/core/src/main/java/bisq/core/api/model/BtcBalanceInfo.java b/core/src/main/java/bisq/core/api/model/BtcBalanceInfo.java
new file mode 100644
index 00000000000..6e8708c3e37
--- /dev/null
+++ b/core/src/main/java/bisq/core/api/model/BtcBalanceInfo.java
@@ -0,0 +1,70 @@
+package bisq.core.api.model;
+
+import bisq.common.Payload;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import lombok.Getter;
+
+@Getter
+public class BtcBalanceInfo implements Payload {
+
+ // All balances are in BTC satoshis.
+ private final long availableBalance;
+ private final long reservedBalance;
+ private final long totalAvailableBalance; // available + reserved
+ private final long lockedBalance;
+
+ public BtcBalanceInfo(long availableBalance,
+ long reservedBalance,
+ long totalAvailableBalance,
+ long lockedBalance) {
+ this.availableBalance = availableBalance;
+ this.reservedBalance = reservedBalance;
+ this.totalAvailableBalance = totalAvailableBalance;
+ this.lockedBalance = lockedBalance;
+ }
+
+ @VisibleForTesting
+ public static BtcBalanceInfo valueOf(long availableBalance,
+ long reservedBalance,
+ long totalAvailableBalance,
+ long lockedBalance) {
+ // Convenience for creating a model instance instead of a proto.
+ return new BtcBalanceInfo(availableBalance,
+ reservedBalance,
+ totalAvailableBalance,
+ lockedBalance);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+ // PROTO BUFFER
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public bisq.proto.grpc.BtcBalanceInfo toProtoMessage() {
+ return bisq.proto.grpc.BtcBalanceInfo.newBuilder()
+ .setAvailableBalance(availableBalance)
+ .setReservedBalance(reservedBalance)
+ .setTotalAvailableBalance(totalAvailableBalance)
+ .setLockedBalance(lockedBalance)
+ .build();
+ }
+
+ public static BtcBalanceInfo fromProto(bisq.proto.grpc.BtcBalanceInfo proto) {
+ return new BtcBalanceInfo(proto.getAvailableBalance(),
+ proto.getReservedBalance(),
+ proto.getTotalAvailableBalance(),
+ proto.getLockedBalance());
+ }
+
+ @Override
+ public String toString() {
+ return "BtcBalanceInfo{" +
+ "availableBalance=" + availableBalance +
+ ", reservedBalance=" + reservedBalance +
+ ", totalAvailableBalance=" + totalAvailableBalance +
+ ", lockedBalance=" + lockedBalance +
+ '}';
+ }
+}
diff --git a/daemon/src/main/java/bisq/daemon/grpc/GrpcWalletsService.java b/daemon/src/main/java/bisq/daemon/grpc/GrpcWalletsService.java
index 1b5cb42e4cc..2f35f000779 100644
--- a/daemon/src/main/java/bisq/daemon/grpc/GrpcWalletsService.java
+++ b/daemon/src/main/java/bisq/daemon/grpc/GrpcWalletsService.java
@@ -19,13 +19,23 @@
import bisq.core.api.CoreApi;
import bisq.core.api.model.AddressBalanceInfo;
+import bisq.core.api.model.BsqBalanceInfo;
+import bisq.core.api.model.BtcBalanceInfo;
import bisq.proto.grpc.GetAddressBalanceReply;
import bisq.proto.grpc.GetAddressBalanceRequest;
import bisq.proto.grpc.GetBalanceReply;
import bisq.proto.grpc.GetBalanceRequest;
+import bisq.proto.grpc.GetBalancesReply;
+import bisq.proto.grpc.GetBalancesRequest;
+import bisq.proto.grpc.GetBsqBalancesReply;
+import bisq.proto.grpc.GetBsqBalancesRequest;
+import bisq.proto.grpc.GetBtcBalancesReply;
+import bisq.proto.grpc.GetBtcBalancesRequest;
import bisq.proto.grpc.GetFundingAddressesReply;
import bisq.proto.grpc.GetFundingAddressesRequest;
+import bisq.proto.grpc.GetUnusedBsqAddressReply;
+import bisq.proto.grpc.GetUnusedBsqAddressRequest;
import bisq.proto.grpc.LockWalletReply;
import bisq.proto.grpc.LockWalletRequest;
import bisq.proto.grpc.RemoveWalletPasswordReply;
@@ -54,12 +64,8 @@ public GrpcWalletsService(CoreApi coreApi) {
this.coreApi = coreApi;
}
- // TODO we need to support 3 or 4 balance types: available, reserved, lockedInTrade
- // and maybe total wallet balance (available+reserved). To not duplicate the methods,
- // we should pass an enum type. Enums in proto are a bit cumbersome as they are
- // global so you quickly run into namespace conflicts if not always prefixes which
- // makes it more verbose. In the core code base we move to the strategy to store the
- // enum name and map it. This gives also more flexibility with updates.
+
+ @Deprecated
@Override
public void getBalance(GetBalanceRequest req, StreamObserver responseObserver) {
try {
@@ -74,6 +80,54 @@ public void getBalance(GetBalanceRequest req, StreamObserver re
}
}
+ @Override
+ public void getBalances(GetBalancesRequest req, StreamObserver responseObserver) {
+ try {
+ var balances = coreApi.getBalances();
+ var reply = GetBalancesReply.newBuilder()
+ .setBalances(balances.toProtoMessage())
+ .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 getBsqBalances(GetBsqBalancesRequest req, StreamObserver responseObserver) {
+ try {
+ BsqBalanceInfo bsqBalanceInfo = coreApi.getBsqBalances();
+ var reply = GetBsqBalancesReply.newBuilder()
+ .setBsqBalanceInfo(bsqBalanceInfo.toProtoMessage())
+ .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 getBtcBalances(GetBtcBalancesRequest req, StreamObserver responseObserver) {
+ try {
+ BtcBalanceInfo btcBalanceInfo = coreApi.getBtcBalances();
+ var reply = GetBtcBalancesReply.newBuilder()
+ .setBtcBalanceInfo(btcBalanceInfo.toProtoMessage())
+ .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 getAddressBalance(GetAddressBalanceRequest req,
StreamObserver responseObserver) {
@@ -110,6 +164,23 @@ public void getFundingAddresses(GetFundingAddressesRequest req,
}
}
+ @Override
+ public void getUnusedBsqAddress(GetUnusedBsqAddressRequest req,
+ StreamObserver responseObserver) {
+ try {
+ String address = coreApi.getUnusedBsqAddress();
+ var reply = GetUnusedBsqAddressReply.newBuilder()
+ .setAddress(address)
+ .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 setWalletPassword(SetWalletPasswordRequest req,
StreamObserver responseObserver) {
diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto
index d9e0a3973d8..5005ad1eef8 100644
--- a/proto/src/main/proto/grpc.proto
+++ b/proto/src/main/proto/grpc.proto
@@ -81,6 +81,7 @@ message CreateOfferRequest {
uint64 minAmount = 7;
double buyerSecurityDeposit = 8;
string paymentAccountId = 9;
+ string makerFeeCurrencyCode = 10;
}
message CreateOfferReply {
@@ -105,13 +106,14 @@ message OfferInfo {
uint64 volume = 8;
uint64 minVolume = 9;
uint64 buyerSecurityDeposit = 10;
- string paymentAccountId = 11;
- string paymentMethodId = 12;
- string paymentMethodShortName = 13;
- string baseCurrencyCode = 14;
- string counterCurrencyCode = 15;
- uint64 date = 16;
- string state = 17;
+ bool isCurrencyForMakerFeeBtc = 11;
+ string paymentAccountId = 12;
+ string paymentMethodId = 13;
+ string paymentMethodShortName = 14;
+ string baseCurrencyCode = 15;
+ string counterCurrencyCode = 16;
+ uint64 date = 17;
+ string state = 18;
}
///////////////////////////////////////////////////////////////////////////////////////////
@@ -198,6 +200,7 @@ service Trades {
message TakeOfferRequest {
string offerId = 1;
string paymentAccountId = 2;
+ string takerFeeCurrencyCode = 3;
}
message TakeOfferReply {
@@ -275,8 +278,18 @@ message TradeInfo {
service Wallets {
rpc GetBalance (GetBalanceRequest) returns (GetBalanceReply) {
}
+ rpc GetBalances (GetBalancesRequest) returns (GetBalancesReply) {
+ }
+ rpc GetBsqBalances (GetBsqBalancesRequest) returns (GetBsqBalancesReply) {
+ }
+ rpc GetBtcBalances (GetBtcBalancesRequest) returns (GetBtcBalancesReply) {
+ }
rpc GetAddressBalance (GetAddressBalanceRequest) returns (GetAddressBalanceReply) {
}
+ rpc GetUnusedBsqAddress (GetUnusedBsqAddressRequest) returns (GetUnusedBsqAddressReply) {
+ }
+ rpc SendBsq (SendBsqRequest) returns (SendBsqReply) {
+ }
rpc GetFundingAddresses (GetFundingAddressesRequest) returns (GetFundingAddressesReply) {
}
rpc SetWalletPassword (SetWalletPasswordRequest) returns (SetWalletPasswordReply) {
@@ -296,6 +309,27 @@ message GetBalanceReply {
uint64 balance = 1;
}
+message GetBalancesRequest {
+}
+
+message GetBalancesReply {
+ BalancesInfo balances = 1;
+}
+
+message GetBsqBalancesRequest {
+}
+
+message GetBsqBalancesReply {
+ BsqBalanceInfo bsqBalanceInfo = 1;
+}
+
+message GetBtcBalancesRequest {
+}
+
+message GetBtcBalancesReply {
+ BtcBalanceInfo btcBalanceInfo = 1;
+}
+
message GetAddressBalanceRequest {
string address = 1;
}
@@ -304,6 +338,21 @@ message GetAddressBalanceReply {
AddressBalanceInfo addressBalanceInfo = 1;
}
+message GetUnusedBsqAddressRequest {
+}
+
+message GetUnusedBsqAddressReply {
+ string address = 1;
+}
+
+message SendBsqRequest {
+ string address = 1;
+ double amount = 2;
+}
+
+message SendBsqReply {
+}
+
message GetFundingAddressesRequest {
}
@@ -340,6 +389,27 @@ message UnlockWalletRequest {
message UnlockWalletReply {
}
+message BalancesInfo {
+ BsqBalanceInfo bsqBalanceInfo = 1;
+ BtcBalanceInfo btcBalanceInfo = 2;
+}
+
+message BsqBalanceInfo {
+ uint64 availableConfirmedBalance = 1;
+ uint64 unverifiedBalance = 2;
+ uint64 unconfirmedChangeBalance = 3;
+ uint64 lockedForVotingBalance = 4;
+ uint64 lockupBondsBalance = 5;
+ uint64 unlockingBondsBalance = 6;
+}
+
+message BtcBalanceInfo {
+ uint64 availableBalance = 1;
+ uint64 reservedBalance = 2;
+ uint64 totalAvailableBalance = 3;
+ uint64 lockedBalance = 4;
+}
+
message AddressBalanceInfo {
string address = 1;
int64 balance = 2;