mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-23 15:00:30 +01:00
Implement and test new getbalance(s) api methods
- Added three new methods to CLI: getbalances ... returns complete bsq and btc balance info getbsqbalance ... returns complete bsq balance info getbtcbalance ... returns complete btc balance info The old getbalance method is deprecated and will be removed if there is agreement to do that. - Made the needed changes in the CLI's output formatting classes. - Added new tests to existing BsqWalletTest, added new BtcWalletTest and WalletBalancesTest. - Added disabled tests for funding a bsq wallet (todo in next PR).
This commit is contained in:
parent
8dc1a74c8b
commit
208a37b339
13 changed files with 707 additions and 55 deletions
|
@ -17,11 +17,19 @@
|
|||
|
||||
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;
|
||||
|
@ -33,6 +41,7 @@ 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;
|
||||
|
@ -104,12 +113,25 @@ public class MethodTest extends ApiTestCase {
|
|||
|
||||
// Convenience methods for building gRPC request objects
|
||||
|
||||
@Deprecated
|
||||
protected final GetBalanceRequest createBalanceRequest() {
|
||||
return GetBalanceRequest.newBuilder().build();
|
||||
}
|
||||
|
||||
protected final GetUnusedBsqAddressRequest createGetUnusedBsqAddressRequest() {
|
||||
return GetUnusedBsqAddressRequest.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) {
|
||||
|
@ -132,6 +154,14 @@ public class MethodTest extends ApiTestCase {
|
|||
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();
|
||||
}
|
||||
|
@ -148,8 +178,12 @@ public class MethodTest extends ApiTestCase {
|
|||
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) {
|
||||
|
@ -179,10 +213,27 @@ public class MethodTest extends ApiTestCase {
|
|||
|
||||
// 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));
|
||||
|
@ -193,6 +244,14 @@ public class MethodTest extends ApiTestCase {
|
|||
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())
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package bisq.apitest.method.wallet;
|
||||
|
||||
import bisq.proto.grpc.BsqBalanceInfo;
|
||||
|
||||
import org.bitcoinj.core.LegacyAddress;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
|
||||
|
@ -7,16 +9,22 @@ 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;
|
||||
|
@ -24,20 +32,43 @@ import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
|
|||
|
||||
|
||||
|
||||
import bisq.apitest.config.BisqAppConfig;
|
||||
import bisq.apitest.method.MethodTest;
|
||||
|
||||
// @Disabled
|
||||
@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,
|
||||
alicedaemon);
|
||||
arbdaemon,
|
||||
alicedaemon,
|
||||
bobdaemon);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -52,13 +83,164 @@ public class BsqWalletTest extends MethodTest {
|
|||
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.
|
||||
// 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,
|
||||
bisq.proto.grpc.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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
bisq.proto.grpc.BtcBalanceInfo actual) {
|
||||
assertEquals(expected.getAvailableBalance(), actual.getAvailableBalance());
|
||||
assertEquals(expected.getReservedBalance(), actual.getReservedBalance());
|
||||
assertEquals(expected.getTotalAvailableBalance(), actual.getTotalAvailableBalance());
|
||||
assertEquals(expected.getLockedBalance(), actual.getLockedBalance());
|
||||
}
|
||||
}
|
|
@ -40,6 +40,7 @@ import static org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
|
|||
|
||||
import bisq.apitest.method.MethodTest;
|
||||
|
||||
@Deprecated
|
||||
@Disabled
|
||||
@Slf4j
|
||||
@TestMethodOrder(OrderAnnotation.class)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -24,55 +24,69 @@ import org.junit.jupiter.api.BeforeAll;
|
|||
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.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();
|
||||
|
||||
String unusedAddress = getUnusedBtcAddress(alicedaemon);
|
||||
bitcoinCli.sendToAddress(unusedAddress, "2.5");
|
||||
|
||||
bitcoinCli.generateBlocks(1);
|
||||
sleep(1500);
|
||||
|
||||
balance = getBalance(alicedaemon);
|
||||
assertEquals(1250000000L, balance); // new balance is 12.5 btc
|
||||
btcWalletTest.testDeprecatedAvailableBtcBalance();
|
||||
btcWalletTest.testNewGetBalances(testInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void testBtcWalletFunding(final TestInfo testInfo) {
|
||||
BtcWalletTest btcWalletTest = new BtcWalletTest();
|
||||
|
||||
btcWalletTest.testDeprecatedAvailableBtcBalance();
|
||||
btcWalletTest.testFundAlicesBtcWallet(testInfo);
|
||||
}
|
||||
|
||||
@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(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
|
||||
|
|
|
@ -24,6 +24,9 @@ import bisq.proto.grpc.CreateOfferRequest;
|
|||
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;
|
||||
|
@ -58,6 +61,7 @@ import static bisq.cli.CurrencyFormat.formatSatoshis;
|
|||
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;
|
||||
|
@ -88,7 +92,10 @@ public class CliMain {
|
|||
createpaymentacct,
|
||||
getpaymentaccts,
|
||||
getversion,
|
||||
getbalance,
|
||||
@Deprecated getbalance, // Use getbalances, return bsq and btc balance info
|
||||
getbalances,
|
||||
getbsqbalance,
|
||||
getbtcbalance,
|
||||
getaddressbalance,
|
||||
getfundingaddresses,
|
||||
getunusedbsqaddress,
|
||||
|
@ -185,12 +192,31 @@ public class CliMain {
|
|||
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");
|
||||
|
@ -494,7 +520,10 @@ public class CliMain {
|
|||
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");
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.TimeZone;
|
|||
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> 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> 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 @@ class TableFormat {
|
|||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
static String formatOfferTable(List<OfferInfo> 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> 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
|
||||
|
|
|
@ -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 class CoreApi {
|
|||
// 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);
|
||||
}
|
||||
|
|
|
@ -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.btc.Balances;
|
||||
import bisq.core.btc.model.AddressEntry;
|
||||
import bisq.core.btc.wallet.BsqWalletService;
|
||||
|
@ -82,6 +85,7 @@ class CoreWalletsService {
|
|||
return tempAesKey;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
long getAvailableBalance() {
|
||||
verifyWalletsAreAvailable();
|
||||
verifyEncryptedWalletIsUnlocked();
|
||||
|
@ -93,6 +97,56 @@ class CoreWalletsService {
|
|||
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;
|
||||
|
|
|
@ -19,11 +19,19 @@ package bisq.daemon.grpc;
|
|||
|
||||
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;
|
||||
|
@ -56,12 +64,8 @@ class GrpcWalletsService extends WalletsGrpc.WalletsImplBase {
|
|||
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<GetBalanceReply> responseObserver) {
|
||||
try {
|
||||
|
@ -76,6 +80,54 @@ class GrpcWalletsService extends WalletsGrpc.WalletsImplBase {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getBalances(GetBalancesRequest req, StreamObserver<GetBalancesReply> 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<GetBsqBalancesReply> 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<GetBtcBalancesReply> 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<GetAddressBalanceReply> responseObserver) {
|
||||
|
|
Loading…
Add table
Reference in a new issue