Add getbalances cli command (#3022)

* Add getbalances cli command

* Add docs

* Locked -> reserved
This commit is contained in:
benthecarman 2021-05-04 12:19:15 -05:00 committed by GitHub
parent 507f5c772e
commit f86f90dc32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 86 additions and 12 deletions

View File

@ -438,6 +438,20 @@ object ConsoleCli {
case other => other
}))
),
cmd("getbalances")
.action((_, conf) => conf.copy(command = GetBalances(false)))
.text("Get the wallet balance by utxo state")
.children(
opt[Unit]("sats")
.optional()
.text("Display balance in satoshis")
.action((_, conf) =>
conf.copy(command = conf.command match {
case getBalances: GetBalances =>
getBalances.copy(isSats = true)
case other => other
}))
),
cmd("getutxos")
.action((_, conf) => conf.copy(command = GetUtxos))
.text("Returns list of all wallet utxos"),
@ -1437,6 +1451,8 @@ object ConsoleCli {
// Wallet
case GetBalance(isSats) =>
RequestParam("getbalance", Seq(up.writeJs(isSats)))
case GetBalances(isSats) =>
RequestParam("getbalances", Seq(up.writeJs(isSats)))
case GetConfirmedBalance(isSats) =>
RequestParam("getconfirmedbalance", Seq(up.writeJs(isSats)))
case GetUnconfirmedBalance(isSats) =>
@ -1873,6 +1889,7 @@ object CliCommand {
case class GetBalance(isSats: Boolean) extends AppServerCliCommand
case class GetConfirmedBalance(isSats: Boolean) extends AppServerCliCommand
case class GetUnconfirmedBalance(isSats: Boolean) extends AppServerCliCommand
case class GetBalances(isSats: Boolean) extends AppServerCliCommand
case class GetAddressInfo(address: BitcoinAddress) extends AppServerCliCommand
case class GetTransaction(txId: DoubleSha256DigestBE)

View File

@ -337,6 +337,42 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
}
}
val spendingInfoDb = SegwitV0SpendingInfo(
outPoint = TransactionOutPoint(DoubleSha256DigestBE.empty, UInt32.zero),
output = EmptyTransactionOutput,
privKeyPath =
SegWitHDPath(HDCoinType.Testnet, 0, HDChainType.External, 0),
scriptWitness = EmptyScriptWitness,
txid = DoubleSha256DigestBE.empty,
state = TxoState.PendingConfirmationsSpent,
spendingTxIdOpt = Some(DoubleSha256DigestBE.empty)
)
"return the wallet's balances in sats" in {
(mockWalletApi.getConfirmedBalance: () => Future[CurrencyUnit])
.expects()
.returning(Future.successful(Bitcoins(50)))
(mockWalletApi.getUnconfirmedBalance: () => Future[CurrencyUnit])
.expects()
.returning(Future.successful(Bitcoins(50)))
(mockWalletApi
.listUtxos(_: TxoState))
.expects(TxoState.Reserved)
.returning(Future.successful(Vector(spendingInfoDb)))
val route =
walletRoutes.handleCommand(
ServerCommand("getbalances", Arr(Bool(true))))
Get() ~> route ~> check {
assert(contentType == `application/json`)
assert(
responseAs[String] == """{"result":{"confirmed":"5000000000 sats","unconfirmed":"5000000000 sats","reserved":"-1 sat","total":"9999999999 sats"},"error":null}""")
}
}
"return the wallet's unconfirmed balance in sats" in {
(mockWalletApi.getUnconfirmedBalance: () => Future[CurrencyUnit])
.expects()
@ -367,17 +403,6 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
}
}
val spendingInfoDb = SegwitV0SpendingInfo(
outPoint = TransactionOutPoint(DoubleSha256DigestBE.empty, UInt32.zero),
output = EmptyTransactionOutput,
privKeyPath =
SegWitHDPath(HDCoinType.Testnet, 0, HDChainType.External, 0),
scriptWitness = EmptyScriptWitness,
txid = DoubleSha256DigestBE.empty,
state = TxoState.PendingConfirmationsSpent,
spendingTxIdOpt = Some(DoubleSha256DigestBE.empty)
)
"return the wallet utxos" in {
(mockWalletApi.listUtxos: () => Future[Vector[SpendingInfoDb]])

View File

@ -99,6 +99,36 @@ case class WalletRoutes(wallet: AnyHDWalletApi)(implicit
}
}
case ServerCommand("getbalances", arr) =>
GetBalance.fromJsArr(arr) match {
case Failure(exception) =>
reject(ValidationRejection("failure", Some(exception)))
case Success(GetBalance(isSats)) =>
complete {
for {
confirmed <- wallet.getConfirmedBalance()
unconfirmed <- wallet.getUnconfirmedBalance()
reservedUtxos <- wallet.listUtxos(TxoState.Reserved)
} yield {
def balToStr(bal: CurrencyUnit): String = {
if (isSats) bal.satoshis.toString
else Bitcoins(bal.satoshis).toString
}
val reserved = reservedUtxos.map(_.output.value).sum
val total = confirmed + unconfirmed + reserved
val json = Obj(
"confirmed" -> Str(balToStr(confirmed)),
"unconfirmed" -> Str(balToStr(unconfirmed)),
"reserved" -> Str(balToStr(reserved)),
"total" -> Str(balToStr(total))
)
Server.httpSuccess(json)
}
}
}
case ServerCommand("getnewaddress", arr) =>
withValidServerCommand(GetNewAddress.fromJsArr(arr)) {
case GetNewAddress(labelOpt) =>

View File

@ -100,7 +100,7 @@ sealed abstract class Satoshis extends CurrencyUnit {
override def toString: String = {
val num = toLong
val postFix = if (num == 1) "sat" else "sats"
val postFix = if (num == 1 || num == -1) "sat" else "sats"
s"$num $postFix"
}

View File

@ -164,6 +164,8 @@ the `-p 9999:9999` port mapping on the docker container to adjust for this.
- `--sats ` - Display balance in satoshis
- `getunconfirmedbalance` `[options]` - Get the wallet balance of unconfirmed utxos
- `--sats ` - Display balance in satoshis
- `getbalances` `[options]` - Get the wallet balance by utxo state
- `--sats ` - Display balance in satoshis
- `getutxos` - Returns list of all wallet utxos
- `getaddresses` - Returns list of all wallet addresses currently being watched
- `getspentaddresses` - Returns list of all wallet addresses that have received funds and been spent