mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-13 11:35:40 +01:00
Add listFundedAddresses call (#1407)
This commit is contained in:
parent
721b28aefd
commit
711f5cb99c
8 changed files with 95 additions and 2 deletions
|
@ -169,6 +169,9 @@ object ConsoleCli {
|
|||
.action((_, conf) => conf.copy(command = GetSpentAddresses))
|
||||
.text(
|
||||
"Returns list of all wallet addresses that have received funds and been spent"),
|
||||
cmd("getfundedaddresses")
|
||||
.action((_, conf) => conf.copy(command = GetFundedAddresses))
|
||||
.text("Returns list of all wallet addresses that are holding funds"),
|
||||
cmd("getaccounts")
|
||||
.action((_, conf) => conf.copy(command = GetAccounts))
|
||||
.text("Returns list of all wallet accounts"),
|
||||
|
@ -402,6 +405,8 @@ object ConsoleCli {
|
|||
RequestParam("getaddresses")
|
||||
case GetSpentAddresses =>
|
||||
RequestParam("getspentaddresses")
|
||||
case GetFundedAddresses =>
|
||||
RequestParam("getfundedaddresses")
|
||||
case GetAccounts =>
|
||||
RequestParam("getaccounts")
|
||||
case CreateNewAccount =>
|
||||
|
@ -577,6 +582,7 @@ object CliCommand {
|
|||
case object GetUtxos extends CliCommand
|
||||
case object GetAddresses extends CliCommand
|
||||
case object GetSpentAddresses extends CliCommand
|
||||
case object GetFundedAddresses extends CliCommand
|
||||
case object GetAccounts extends CliCommand
|
||||
case object CreateNewAccount extends CliCommand
|
||||
case object IsEmpty extends CliCommand
|
||||
|
|
|
@ -8,7 +8,7 @@ import akka.http.scaladsl.testkit.ScalatestRouteTest
|
|||
import org.bitcoins.chain.api.ChainApi
|
||||
import org.bitcoins.core.Core
|
||||
import org.bitcoins.core.crypto.ExtPublicKey
|
||||
import org.bitcoins.core.currency.{Bitcoins, CurrencyUnit}
|
||||
import org.bitcoins.core.currency.{Bitcoins, CurrencyUnit, Satoshis}
|
||||
import org.bitcoins.core.hd._
|
||||
import org.bitcoins.core.protocol.BlockStamp.{
|
||||
BlockHash,
|
||||
|
@ -373,6 +373,31 @@ class RoutesSpec
|
|||
}
|
||||
}
|
||||
|
||||
"return the wallet's funded addresses" in {
|
||||
val addressDb = LegacyAddressDb(
|
||||
LegacyHDPath(HDCoinType.Testnet, 0, HDChainType.External, 0),
|
||||
ECPublicKey.freshPublicKey,
|
||||
Sha256Hash160Digest.fromBytes(ByteVector.low(20)),
|
||||
testAddress.asInstanceOf[P2PKHAddress],
|
||||
testAddress.scriptPubKey
|
||||
)
|
||||
|
||||
(mockWalletApi.listFundedAddresses: () => Future[Vector[(
|
||||
AddressDb,
|
||||
CurrencyUnit)]])
|
||||
.expects()
|
||||
.returning(Future.successful(Vector((addressDb, Satoshis.zero))))
|
||||
|
||||
val route =
|
||||
walletRoutes.handleCommand(ServerCommand("getfundedaddresses", Arr()))
|
||||
|
||||
Get() ~> route ~> check {
|
||||
contentType shouldEqual `application/json`
|
||||
responseAs[String] shouldEqual
|
||||
s"""{"result":["$testAddressStr ${Satoshis.zero}"],"error":null}""".stripMargin
|
||||
}
|
||||
}
|
||||
|
||||
"return the wallet accounts" in {
|
||||
val xpub = ExtPublicKey
|
||||
.fromString(
|
||||
|
|
|
@ -266,7 +266,7 @@ object SendFromOutpoints extends ServerJsonModels {
|
|||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 3"))
|
||||
s"Bad number of arguments: ${other.length}. Expected: 4"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -189,6 +189,17 @@ case class WalletRoutes(wallet: WalletApi, node: Node)(
|
|||
}
|
||||
}
|
||||
|
||||
case ServerCommand("getfundedaddresses", _) =>
|
||||
complete {
|
||||
wallet.listFundedAddresses().map { addressDbs =>
|
||||
val addressAndValues = addressDbs.map {
|
||||
case (addressDb, value) => s"${addressDb.address} $value"
|
||||
}
|
||||
|
||||
Server.httpSuccess(addressAndValues)
|
||||
}
|
||||
}
|
||||
|
||||
case ServerCommand("getaccounts", _) =>
|
||||
complete {
|
||||
wallet.listAccounts().map { accounts =>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.bitcoins.wallet
|
||||
|
||||
import org.bitcoins.core.currency.{Bitcoins, Satoshis}
|
||||
import org.bitcoins.core.protocol.transaction.TransactionOutput
|
||||
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
|
||||
import org.bitcoins.testkit.wallet.FundWalletUtil.FundedWallet
|
||||
import org.bitcoins.rpc.util.AsyncUtil
|
||||
|
@ -136,4 +137,19 @@ class AddressHandlingTest extends BitcoinSWalletTest {
|
|||
assert(diff.isEmpty, s"Extra spent addresses $diff")
|
||||
}
|
||||
}
|
||||
|
||||
it must "get the correct funded addresses" in { fundedWallet: FundedWallet =>
|
||||
val wallet = fundedWallet.wallet
|
||||
|
||||
for {
|
||||
unspentDbs <- wallet.spendingInfoDAO.findAllUnspent()
|
||||
fundedAddresses <- wallet.listFundedAddresses()
|
||||
} yield {
|
||||
val diff = unspentDbs
|
||||
.map(_.output)
|
||||
.diff(fundedAddresses.map(tuple =>
|
||||
TransactionOutput(tuple._2, tuple._1.scriptPubKey)))
|
||||
assert(diff.isEmpty, s"Extra funded addresses $diff")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -176,6 +176,11 @@ trait WalletApi extends WalletLogger {
|
|||
|
||||
def listSpentAddresses(account: HDAccount): Future[Vector[AddressDb]]
|
||||
|
||||
def listFundedAddresses(): Future[Vector[(AddressDb, CurrencyUnit)]]
|
||||
|
||||
def listFundedAddresses(
|
||||
account: HDAccount): Future[Vector[(AddressDb, CurrencyUnit)]]
|
||||
|
||||
def markUTXOsAsReserved(
|
||||
utxos: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]]
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.bitcoins.wallet.internal
|
||||
|
||||
import org.bitcoins.core.currency.CurrencyUnit
|
||||
import org.bitcoins.core.hd._
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
|
@ -70,6 +71,21 @@ private[wallet] trait AddressHandling extends WalletLogger {
|
|||
}
|
||||
}
|
||||
|
||||
override def listFundedAddresses(): Future[
|
||||
Vector[(AddressDb, CurrencyUnit)]] = {
|
||||
addressDAO.getFundedAddresses
|
||||
}
|
||||
|
||||
override def listFundedAddresses(
|
||||
account: HDAccount): Future[Vector[(AddressDb, CurrencyUnit)]] = {
|
||||
val spentAddressesF = addressDAO.getFundedAddresses
|
||||
|
||||
spentAddressesF.map { spentAddresses =>
|
||||
spentAddresses.filter(addr =>
|
||||
HDAccount.isSameAccount(addr._1.path, account))
|
||||
}
|
||||
}
|
||||
|
||||
/** Enumerates the public keys in this wallet */
|
||||
protected[wallet] def listPubkeys(): Future[Vector[ECPublicKey]] =
|
||||
addressDAO.findAllPubkeys()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.bitcoins.wallet.models
|
||||
|
||||
import org.bitcoins.core.currency.CurrencyUnit
|
||||
import org.bitcoins.core.hd.{
|
||||
HDAccount,
|
||||
HDChainType,
|
||||
|
@ -126,6 +127,19 @@ case class AddressDAO()(
|
|||
safeDatabase.runVec(query.result)
|
||||
}
|
||||
|
||||
def getFundedAddresses: Future[Vector[(AddressDb, CurrencyUnit)]] = {
|
||||
val query = table
|
||||
.join(spendingInfoTable)
|
||||
.on(_.scriptPubKey === _.scriptPubKey)
|
||||
.filter(_._2.state.inSet(TxoState.receivedStates))
|
||||
|
||||
safeDatabase
|
||||
.runVec(query.result)
|
||||
.map(_.map {
|
||||
case (addrDb, utxoDb) => (addrDb, utxoDb.output.value)
|
||||
})
|
||||
}
|
||||
|
||||
private def findMostRecentForChain(
|
||||
account: HDAccount,
|
||||
chain: HDChainType): slick.sql.SqlAction[
|
||||
|
|
Loading…
Add table
Reference in a new issue