Create HDWalletApi (#1693)

* Create HDWalletApi

* Rename createWallet to createHDWallet, add listDefaultAccountUtxos function

* Change return types to HDWalletApi

* Fix warning
This commit is contained in:
Ben Carman 2020-07-27 14:06:48 -05:00 committed by GitHub
parent b2b9ca7eec
commit 4abcf3f321
14 changed files with 622 additions and 360 deletions

View file

@ -2,7 +2,7 @@ package org.bitcoins.wallet
import org.bitcoins.core.hd.AddressType
import org.bitcoins.core.protocol.BitcoinAddress
import org.bitcoins.wallet.api.WalletApi
import org.bitcoins.wallet.api.HDWalletApi
import org.bitcoins.wallet.models.AccountDb
import scala.concurrent.Future
@ -11,7 +11,7 @@ import scala.concurrent.Future
* ScalaMock cannot stub traits with protected methods,
* so we need to stub them manually.
*/
abstract class MockWalletApi extends WalletApi {
abstract class MockWalletApi extends HDWalletApi {
override protected[wallet] def getNewChangeAddress(
account: AccountDb): Future[BitcoinAddress] = stub

View file

@ -89,10 +89,10 @@ object Main extends App with BitcoinSLogger {
uninitializedNode <- uninitializedNodeF
chainApi <- chainApiF
_ = logger.info("Initialized chain api")
wallet <- walletConf.createWallet(uninitializedNode,
chainApi,
BitcoinerLiveFeeRateProvider(60),
bip39PasswordOpt)
wallet <- walletConf.createHDWallet(uninitializedNode,
chainApi,
BitcoinerLiveFeeRateProvider(60),
bip39PasswordOpt)
} yield {
logger.info(s"Done configuring wallet")
wallet
@ -233,7 +233,7 @@ object Main extends App with BitcoinSLogger {
private def startHttpServer(
node: Node,
wallet: WalletApi,
wallet: HDWalletApi,
rpcPortOpt: Option[Int])(implicit
system: ActorSystem,
conf: BitcoinSAppConfig): Future[Http.ServerBinding] = {

View file

@ -6,12 +6,12 @@ import akka.http.scaladsl.server._
import org.bitcoins.commons.serializers.Picklers._
import org.bitcoins.core.currency._
import org.bitcoins.node.Node
import org.bitcoins.wallet.api.WalletApi
import org.bitcoins.wallet.api.HDWalletApi
import scala.concurrent.Future
import scala.util.{Failure, Success}
case class WalletRoutes(wallet: WalletApi, node: Node)(implicit
case class WalletRoutes(wallet: HDWalletApi, node: Node)(implicit
system: ActorSystem)
extends ServerRoute {
import system.dispatcher

View file

@ -92,7 +92,7 @@ class NeutrinoNodeWithWalletTest extends NodeUnitTest {
confirmedBalance <- wallet.getConfirmedBalance()
unconfirmedBalance <- wallet.getUnconfirmedBalance()
addresses <- wallet.listAddresses()
utxos <- wallet.listUtxos()
utxos <- wallet.listDefaultAccountUtxos()
} yield {
(expectedConfirmedAmount == confirmedBalance) &&
(expectedUnconfirmedAmount == unconfirmedBalance) &&
@ -175,7 +175,7 @@ class NeutrinoNodeWithWalletTest extends NodeUnitTest {
for {
addresses <- wallet.listAddresses()
utxos <- wallet.listUtxos()
utxos <- wallet.listDefaultAccountUtxos()
_ = assert(addresses.size == 6)
_ = assert(utxos.size == 3)
@ -189,14 +189,14 @@ class NeutrinoNodeWithWalletTest extends NodeUnitTest {
.sendToAddress(address, TestAmount)
addresses <- wallet.listAddresses()
utxos <- wallet.listUtxos()
utxos <- wallet.listDefaultAccountUtxos()
_ = assert(addresses.size == 7)
_ = assert(utxos.size == 3)
_ <- wallet.clearAllUtxosAndAddresses()
addresses <- wallet.listAddresses()
utxos <- wallet.listUtxos()
utxos <- wallet.listDefaultAccountUtxos()
_ = assert(addresses.isEmpty)
_ = assert(utxos.isEmpty)

View file

@ -3,17 +3,16 @@ package org.bitcoins.wallet
import org.bitcoins.core.hd.{AddressType, HDPurposes}
import org.bitcoins.core.protocol.{Bech32Address, P2PKHAddress, P2SHAddress}
import org.bitcoins.testkit.wallet.BitcoinSWalletTest
import org.bitcoins.wallet.api.WalletApi
import org.scalatest.FutureOutcome
class LegacyWalletTest extends BitcoinSWalletTest {
override type FixtureParam = WalletApi
override type FixtureParam = Wallet
override def withFixture(test: OneArgAsyncTest): FutureOutcome =
withLegacyWallet(test)
it should "generate legacy addresses" in { wallet: WalletApi =>
it should "generate legacy addresses" in { wallet: Wallet =>
for {
addr <- wallet.getNewAddress()
account <- wallet.getDefaultAccount()

View file

@ -3,18 +3,17 @@ package org.bitcoins.wallet
import org.bitcoins.core.hd.{AddressType, HDPurposes}
import org.bitcoins.core.protocol.{Bech32Address, P2PKHAddress, P2SHAddress}
import org.bitcoins.testkit.wallet.BitcoinSWalletTest
import org.bitcoins.wallet.api.WalletApi
import org.scalatest.FutureOutcome
class SegwitWalletTest extends BitcoinSWalletTest {
override type FixtureParam = WalletApi
override type FixtureParam = Wallet
override def withFixture(test: OneArgAsyncTest): FutureOutcome = {
withSegwitWallet(test)
}
it should "generate segwit addresses" in { wallet: WalletApi =>
it should "generate segwit addresses" in { wallet =>
for {
addr <- wallet.getNewAddress()
account <- wallet.getDefaultAccount()

View file

@ -140,9 +140,9 @@ class UTXOLifeCycleTest extends BitcoinSWalletTest {
for {
tx <- wallet.sendToOutputs(Vector(dummyOutput),
Some(SatoshisPerVirtualByte.one),
reserveUtxos = true)
Some(SatoshisPerVirtualByte.one))
_ <- wallet.processTransaction(tx, None)
_ <- wallet.markUTXOsAsReserved(tx)
allReserved <- wallet.listUtxos(TxoState.Reserved)
_ = assert(

View file

@ -6,7 +6,7 @@ import org.bitcoins.core.protocol.BitcoinAddress
import org.bitcoins.core.protocol.transaction.TransactionOutput
import org.bitcoins.core.script.constant.{BytesToPushOntoStack, ScriptConstant}
import org.bitcoins.core.script.control.OP_RETURN
import org.bitcoins.core.wallet.fee.{SatoshisPerByte, SatoshisPerVirtualByte}
import org.bitcoins.core.wallet.fee.SatoshisPerByte
import org.bitcoins.crypto.CryptoUtil
import org.bitcoins.testkit.wallet.BitcoinSWalletTest
import org.bitcoins.testkit.wallet.FundWalletUtil.FundedWallet
@ -62,10 +62,7 @@ class WalletSendingTest extends BitcoinSWalletTest {
val wallet = fundedWallet.wallet
for {
tx <- wallet.sendToAddresses(addresses,
amounts,
feeRateOpt,
reserveUtxos = false)
tx <- wallet.sendToAddresses(addresses, amounts, feeRateOpt)
} yield {
val expectedOutputs = addresses.zip(amounts).map {
case (addr, amount) => TransactionOutput(amount, addr.scriptPubKey)
@ -79,10 +76,7 @@ class WalletSendingTest extends BitcoinSWalletTest {
val wallet = fundedWallet.wallet
val sendToAddressesF =
wallet.sendToAddresses(addresses,
amounts.tail,
feeRateOpt,
reserveUtxos = false)
wallet.sendToAddresses(addresses, amounts.tail, feeRateOpt)
recoverToSucceededIf[IllegalArgumentException] {
sendToAddressesF
@ -94,10 +88,7 @@ class WalletSendingTest extends BitcoinSWalletTest {
val wallet = fundedWallet.wallet
val sendToAddressesF =
wallet.sendToAddresses(addresses.tail,
amounts,
feeRateOpt,
reserveUtxos = false)
wallet.sendToAddresses(addresses.tail, amounts, feeRateOpt)
recoverToSucceededIf[IllegalArgumentException] {
sendToAddressesF
@ -112,8 +103,7 @@ class WalletSendingTest extends BitcoinSWalletTest {
}
for {
tx <-
wallet.sendToOutputs(expectedOutputs, feeRateOpt, reserveUtxos = false)
tx <- wallet.sendToOutputs(expectedOutputs, feeRateOpt)
} yield {
assert(expectedOutputs.diff(tx.outputs).isEmpty)
}
@ -203,7 +193,7 @@ class WalletSendingTest extends BitcoinSWalletTest {
)
val sendToAddressesF =
wallet.sendToAddresses(addrs, amounts, feeRateOpt, reserveUtxos = false)
wallet.sendToAddresses(addrs, amounts, feeRateOpt)
recoverToSucceededIf[IllegalArgumentException] {
sendToAddressesF
@ -237,7 +227,8 @@ class WalletSendingTest extends BitcoinSWalletTest {
wallet: Wallet,
algo: CoinSelectionAlgo): Future[Assertion] = {
for {
allUtxos <- wallet.listUtxos()
account <- wallet.getDefaultAccount()
allUtxos <- wallet.listUtxos(account.hdAccount)
output = TransactionOutput(amountToSend, testAddress.scriptPubKey)
expectedUtxos = CoinSelector.selectByAlgo(algo,
allUtxos,

View file

@ -3,16 +3,14 @@ package org.bitcoins.wallet
import java.nio.file.Files
import org.bitcoins.core.hd.HDChainType.{Change, External}
import org.bitcoins.core.hd.{HDAccount, HDChainType, HDPurpose}
import org.bitcoins.core.hd.{HDAccount, HDChainType}
import org.bitcoins.core.protocol.BitcoinAddress
import org.bitcoins.core.util.FutureUtil
import org.bitcoins.crypto.AesPassword
import org.bitcoins.keymanager.KeyManagerUnlockError.MnemonicNotFound
import org.bitcoins.keymanager.{KeyManagerUnlockError, WalletStorage}
import org.bitcoins.testkit.EmbeddedPg
import org.bitcoins.testkit.wallet.BitcoinSWalletTest
import org.bitcoins.wallet.api.WalletApi.BlockMatchingResponse
import org.bitcoins.wallet.api.WalletApi
import org.bitcoins.wallet.models.AddressDb
import org.scalatest.FutureOutcome
import org.scalatest.compatible.Assertion
@ -30,7 +28,7 @@ class WalletUnitTest extends BitcoinSWalletTest {
behavior of "Wallet - unit test"
it must "write the mnemonic seed to the root datadir -- NOT A NETWORK sub directory" in {
wallet: WalletApi =>
wallet: Wallet =>
//since datadir has the path that relates it to a network ('mainnet'/'testnet'/'regtest')
//we need to get the parent of that to find where the encrypted seed should be
//this is where the bitcoin-s.conf should live too.
@ -41,7 +39,7 @@ class WalletUnitTest extends BitcoinSWalletTest {
}
it should "create a new wallet" in { wallet: WalletApi =>
it should "create a new wallet" in { wallet: Wallet =>
for {
accounts <- wallet.listAccounts()
addresses <- wallet.listAddresses()
@ -51,7 +49,7 @@ class WalletUnitTest extends BitcoinSWalletTest {
}
}
it should "generate addresses" in { wallet: WalletApi =>
it should "generate addresses" in { wallet: Wallet =>
for {
addr <- wallet.getNewAddress()
otherAddr <- wallet.getNewAddress()
@ -63,9 +61,7 @@ class WalletUnitTest extends BitcoinSWalletTest {
}
}
it should "know what the last address index is" in { walletApi =>
val wallet = walletApi.asInstanceOf[Wallet]
it should "know what the last address index is" in { wallet =>
def getMostRecent(
hdAccount: HDAccount,
chain: HDChainType): Future[AddressDb] = {
@ -138,7 +134,7 @@ class WalletUnitTest extends BitcoinSWalletTest {
}
it should "fail to unlock the wallet with a bad password" in {
wallet: WalletApi =>
wallet: Wallet =>
val badpassphrase = AesPassword.fromNonEmptyString("bad")
val errorType = wallet.unlock(badpassphrase, None) match {
@ -152,7 +148,7 @@ class WalletUnitTest extends BitcoinSWalletTest {
}
}
it should "match block filters" in { wallet: WalletApi =>
it should "match block filters" in { wallet: Wallet =>
for {
matched <- wallet.getMatchingBlocks(
scripts = Vector(

View file

@ -50,7 +50,7 @@ import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success}
abstract class Wallet
extends WalletApi
extends HDWalletApi
with UtxoHandling
with AddressHandling
with AccountHandling
@ -367,7 +367,8 @@ abstract class Wallet
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
fromAccount: AccountDb): Future[Transaction] = {
fromAccount: AccountDb,
newTags: Vector[AddressTag]): Future[Transaction] = {
require(
address.networkParameters.isSameNetworkBytes(networkParameters),
s"Cannot send to address on other network, got ${address.networkParameters}"
@ -396,7 +397,7 @@ abstract class Wallet
feeRate,
changeAddr.scriptPubKey)
tx <- finishSend(txBuilder, utxos, amount, feeRate, Vector.empty)
tx <- finishSend(txBuilder, utxos, amount, feeRate, newTags)
} yield tx
}
@ -455,7 +456,7 @@ abstract class Wallet
amounts: Vector[CurrencyUnit],
feeRate: FeeUnit,
fromAccount: AccountDb,
reserveUtxos: Boolean): Future[Transaction] = {
newTags: Vector[AddressTag]): Future[Transaction] = {
require(amounts.size == addresses.size,
"Must have an amount for every address")
require(
@ -468,7 +469,7 @@ abstract class Wallet
logger.info(s"Sending $amount to $address at feerate $feeRate")
TransactionOutput(amount, address.scriptPubKey)
}
sendToOutputs(destinations, feeRate, fromAccount, reserveUtxos)
sendToOutputs(destinations, feeRate, fromAccount, newTags)
}
override def makeOpReturnCommitment(
@ -492,24 +493,23 @@ abstract class Wallet
val output = TransactionOutput(0.satoshis, scriptPubKey)
sendToOutputs(Vector(output), feeRate, fromAccount, reserveUtxos = false)
sendToOutputs(Vector(output), feeRate, fromAccount)
}
def sendToOutputs(
override def sendToOutputs(
outputs: Vector[TransactionOutput],
feeRate: FeeUnit,
fromAccount: AccountDb,
reserveUtxos: Boolean): Future[Transaction] = {
newTags: Vector[AddressTag]): Future[Transaction] = {
for {
(txBuilder, utxoInfos) <- fundRawTransactionInternal(
destinations = outputs,
feeRate = feeRate,
fromAccount = fromAccount,
keyManagerOpt = Some(keyManager),
fromTagOpt = None,
markAsReserved = reserveUtxos)
fromTagOpt = None)
sentAmount = outputs.foldLeft(CurrencyUnits.zero)(_ + _.value)
tx <- finishSend(txBuilder, utxoInfos, sentAmount, feeRate, Vector.empty)
tx <- finishSend(txBuilder, utxoInfos, sentAmount, feeRate, newTags)
} yield tx
}

View file

@ -0,0 +1,520 @@
package org.bitcoins.wallet.api
import org.bitcoins.commons.jsonmodels.wallet.CoinSelectionAlgo
import org.bitcoins.core.currency.CurrencyUnit
import org.bitcoins.core.hd.{AddressType, HDAccount, HDChainType, HDPurpose}
import org.bitcoins.core.protocol.transaction.{
Transaction,
TransactionOutPoint,
TransactionOutput
}
import org.bitcoins.core.protocol.{BitcoinAddress, BlockStamp}
import org.bitcoins.core.wallet.fee.FeeUnit
import org.bitcoins.core.wallet.utxo.{AddressTag, TxoState}
import org.bitcoins.keymanager.KeyManagerParams
import org.bitcoins.wallet.models.{AccountDb, AddressDb, SpendingInfoDb}
import scala.concurrent.Future
/**
* API for the wallet project.
*
* This wallet API is BIP44 compliant.
*
* @see [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44]]
*/
trait HDWalletApi extends WalletApi {
/** Gets the balance of the given account */
def getBalance(account: HDAccount): Future[CurrencyUnit] = {
val confirmedF = getConfirmedBalance(account)
val unconfirmedF = getUnconfirmedBalance(account)
for {
confirmed <- confirmedF
unconfirmed <- unconfirmedF
} yield {
confirmed + unconfirmed
}
}
def getConfirmedBalance(account: HDAccount): Future[CurrencyUnit]
def getUnconfirmedBalance(account: HDAccount): Future[CurrencyUnit]
/** Generates a new change address */
protected[wallet] def getNewChangeAddress(
account: AccountDb): Future[BitcoinAddress]
override def getNewChangeAddress(): Future[BitcoinAddress] = {
for {
account <- getDefaultAccount()
addr <- getNewChangeAddress(account)
} yield addr
}
/**
* Fetches the default account from the DB
* @return Future[AccountDb]
*/
protected[wallet] def getDefaultAccount(): Future[AccountDb]
/** Fetches the default account for the given address/account kind
* @param addressType
*/
protected[wallet] def getDefaultAccountForType(
addressType: AddressType): Future[AccountDb]
def sendWithAlgo(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
algo: CoinSelectionAlgo,
fromAccount: AccountDb,
newTags: Vector[AddressTag]): Future[Transaction]
def sendWithAlgo(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
algo: CoinSelectionAlgo,
fromAccount: AccountDb): Future[Transaction] =
sendWithAlgo(address, amount, feeRate, algo, fromAccount, Vector.empty)
def sendWithAlgo(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRateOpt: Option[FeeUnit],
algo: CoinSelectionAlgo,
fromAccount: AccountDb): Future[Transaction] = {
for {
feeRate <- determineFeeRate(feeRateOpt)
tx <- sendWithAlgo(address, amount, feeRate, algo, fromAccount)
} yield tx
}
override def sendWithAlgo(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRateOpt: Option[FeeUnit],
algo: CoinSelectionAlgo): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendWithAlgo(address, amount, feeRateOpt, algo, account)
} yield tx
}
override def sendWithAlgo(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
algo: CoinSelectionAlgo): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendWithAlgo(address, amount, feeRate, algo, account)
} yield tx
}
def sendWithAlgo(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
algo: CoinSelectionAlgo,
newTags: Vector[AddressTag]): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendWithAlgo(address, amount, feeRate, algo, account, newTags)
} yield tx
}
/**
* Sends money from the specified account
*
* todo: add error handling to signature
*/
def sendFromOutPoints(
outPoints: Vector[TransactionOutPoint],
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
fromAccount: AccountDb,
newTags: Vector[AddressTag]): Future[Transaction]
def sendFromOutPoints(
outPoints: Vector[TransactionOutPoint],
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
fromAccount: AccountDb): Future[Transaction] =
sendFromOutPoints(outPoints,
address,
amount,
feeRate,
fromAccount,
Vector.empty)
def sendFromOutPoints(
outPoints: Vector[TransactionOutPoint],
address: BitcoinAddress,
amount: CurrencyUnit,
feeRateOpt: Option[FeeUnit],
fromAccount: AccountDb): Future[Transaction] = {
for {
feeRate <- determineFeeRate(feeRateOpt)
tx <- sendFromOutPoints(outPoints, address, amount, feeRate, fromAccount)
} yield tx
}
override def sendFromOutPoints(
outPoints: Vector[TransactionOutPoint],
address: BitcoinAddress,
amount: CurrencyUnit,
feeRateOpt: Option[FeeUnit]
): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendFromOutPoints(outPoints, address, amount, feeRateOpt, account)
} yield tx
}
override def sendFromOutPoints(
outPoints: Vector[TransactionOutPoint],
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendFromOutPoints(outPoints, address, amount, feeRate, account)
} yield tx
}
def sendFromOutPoints(
outPoints: Vector[TransactionOutPoint],
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
newTags: Vector[AddressTag]): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <-
sendFromOutPoints(outPoints, address, amount, feeRate, account, newTags)
} yield tx
}
/**
* Sends money from the specified account
*
* todo: add error handling to signature
*/
def sendToAddress(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
fromAccount: AccountDb,
newTags: Vector[AddressTag]): Future[Transaction]
def sendToAddress(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
fromAccount: AccountDb): Future[Transaction] =
sendToAddress(address, amount, feeRate, fromAccount, Vector.empty)
def sendToAddress(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRateOpt: Option[FeeUnit],
fromAccount: AccountDb): Future[Transaction] = {
for {
feeRate <- determineFeeRate(feeRateOpt)
tx <- sendToAddress(address, amount, feeRate, fromAccount)
} yield tx
}
override def sendToAddress(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRateOpt: Option[FeeUnit]
): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendToAddress(address, amount, feeRateOpt, account)
} yield tx
}
override def sendToAddress(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendToAddress(address, amount, feeRate, account)
} yield tx
}
def sendToAddress(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
newTags: Vector[AddressTag]): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendToAddress(address, amount, feeRate, account, newTags)
} yield tx
}
/**
* Sends money from the specified account
*
* todo: add error handling to signature
*/
def sendToAddresses(
addresses: Vector[BitcoinAddress],
amounts: Vector[CurrencyUnit],
feeRate: FeeUnit,
fromAccount: AccountDb,
newTags: Vector[AddressTag]): Future[Transaction]
def sendToAddresses(
addresses: Vector[BitcoinAddress],
amounts: Vector[CurrencyUnit],
feeRate: FeeUnit,
fromAccount: AccountDb): Future[Transaction] =
sendToAddresses(addresses, amounts, feeRate, fromAccount, Vector.empty)
def sendToAddresses(
addresses: Vector[BitcoinAddress],
amounts: Vector[CurrencyUnit],
feeRateOpt: Option[FeeUnit],
fromAccount: AccountDb): Future[Transaction] = {
for {
feeRate <- determineFeeRate(feeRateOpt)
tx <- sendToAddresses(addresses, amounts, feeRate, fromAccount)
} yield tx
}
override def sendToAddresses(
addresses: Vector[BitcoinAddress],
amounts: Vector[CurrencyUnit],
feeRateOpt: Option[FeeUnit]
): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendToAddresses(addresses, amounts, feeRateOpt, account)
} yield tx
}
override def sendToAddresses(
addresses: Vector[BitcoinAddress],
amounts: Vector[CurrencyUnit],
feeRate: FeeUnit): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendToAddresses(addresses, amounts, feeRate, account)
} yield tx
}
def sendToAddresses(
addresses: Vector[BitcoinAddress],
amounts: Vector[CurrencyUnit],
feeRate: FeeUnit,
newTags: Vector[AddressTag]): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendToAddresses(addresses, amounts, feeRate, account, newTags)
} yield tx
}
/**
* Sends money from the specified account
*
* todo: add error handling to signature
*/
def sendToOutputs(
outputs: Vector[TransactionOutput],
feeRate: FeeUnit,
fromAccount: AccountDb,
newTags: Vector[AddressTag]): Future[Transaction]
def sendToOutputs(
outputs: Vector[TransactionOutput],
feeRate: FeeUnit,
fromAccount: AccountDb): Future[Transaction] =
sendToOutputs(outputs, feeRate, fromAccount, Vector.empty)
def sendToOutputs(
outputs: Vector[TransactionOutput],
feeRateOpt: Option[FeeUnit],
fromAccount: AccountDb): Future[Transaction] = {
for {
feeRate <- determineFeeRate(feeRateOpt)
tx <- sendToOutputs(outputs, feeRate, fromAccount)
} yield tx
}
def sendToOutputs(
outputs: Vector[TransactionOutput],
feeRate: FeeUnit,
newTags: Vector[AddressTag]): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendToOutputs(outputs, feeRate, account, newTags)
} yield tx
}
override def sendToOutputs(
outputs: Vector[TransactionOutput],
feeRateOpt: Option[FeeUnit]
): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendToOutputs(outputs, feeRateOpt, account)
} yield tx
}
override def sendToOutputs(
outputs: Vector[TransactionOutput],
feeRate: FeeUnit): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendToOutputs(outputs, feeRate, account)
} yield tx
}
def makeOpReturnCommitment(
message: String,
hashMessage: Boolean,
feeRate: FeeUnit,
fromAccount: AccountDb): Future[Transaction]
def makeOpReturnCommitment(
message: String,
hashMessage: Boolean,
feeRateOpt: Option[FeeUnit],
fromAccount: AccountDb): Future[Transaction] = {
for {
feeRate <- determineFeeRate(feeRateOpt)
tx <- makeOpReturnCommitment(message, hashMessage, feeRate, fromAccount)
} yield tx
}
override def makeOpReturnCommitment(
message: String,
hashMessage: Boolean,
feeRate: FeeUnit): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- makeOpReturnCommitment(message, hashMessage, feeRate, account)
} yield tx
}
def listDefaultAccountUtxos(): Future[Vector[SpendingInfoDb]] =
listUtxos(walletConfig.defaultAccount)
def listUtxos(account: HDAccount): Future[Vector[SpendingInfoDb]]
def listUtxos(
hdAccount: HDAccount,
tag: AddressTag): Future[Vector[SpendingInfoDb]]
def listUtxos(
hdAccount: HDAccount,
state: TxoState): Future[Vector[SpendingInfoDb]]
def listAddresses(account: HDAccount): Future[Vector[AddressDb]]
def listSpentAddresses(account: HDAccount): Future[Vector[AddressDb]]
def listFundedAddresses(
account: HDAccount): Future[Vector[(AddressDb, CurrencyUnit)]]
def listUnusedAddresses(account: HDAccount): Future[Vector[AddressDb]]
override def clearAllUtxosAndAddresses(): Future[HDWalletApi]
def clearUtxosAndAddresses(account: HDAccount): Future[HDWalletApi]
/** Gets the address associated with the pubkey at
* the resulting `BIP32Path` determined by the
* default account and the given chainType and addressIndex
*/
def getAddress(
chainType: HDChainType,
addressIndex: Int): Future[AddressDb] = {
for {
account <- getDefaultAccount()
address <- getAddress(account, chainType, addressIndex)
} yield address
}
/** Gets the address associated with the pubkey at
* the resulting `BIP32Path` determined the given
* account, chainType, and addressIndex
*/
def getAddress(
account: AccountDb,
chainType: HDChainType,
addressIndex: Int): Future[AddressDb]
def listAccounts(): Future[Vector[AccountDb]]
/** Lists all wallet accounts with the given type
* @param purpose
* @return [[Future[Vector[AccountDb]]
*/
def listAccounts(purpose: HDPurpose): Future[Vector[AccountDb]] =
listAccounts().map(_.filter(_.hdAccount.purpose == purpose))
def rescanNeutrinoWallet(
account: HDAccount,
startOpt: Option[BlockStamp],
endOpt: Option[BlockStamp],
addressBatchSize: Int,
useCreationTime: Boolean): Future[Unit]
override def rescanNeutrinoWallet(
startOpt: Option[BlockStamp],
endOpt: Option[BlockStamp],
addressBatchSize: Int,
useCreationTime: Boolean): Future[Unit] = {
for {
account <- getDefaultAccount()
_ <- rescanNeutrinoWallet(account.hdAccount,
startOpt,
endOpt,
addressBatchSize,
useCreationTime)
} yield ()
}
def fullRescanNeutrinoWallet(
account: HDAccount,
addressBatchSize: Int): Future[Unit] = {
rescanNeutrinoWallet(account = account,
startOpt = None,
endOpt = None,
addressBatchSize = addressBatchSize,
useCreationTime = false)
}
/** Helper method to rescan the ENTIRE blockchain. */
override def fullRescanNeutrinoWallet(addressBatchSize: Int): Future[Unit] = {
for {
account <- getDefaultAccount()
_ <- fullRescanNeutrinoWallet(account.hdAccount, addressBatchSize)
} yield ()
}
def createNewAccount(keyManagerParams: KeyManagerParams): Future[HDWalletApi]
/**
* Tries to create a new account in this wallet. Fails if the
* most recent account has no transaction history, as per
* BIP44
*
* @see [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#account BIP44 account section]]
*/
def createNewAccount(
hdAccount: HDAccount,
keyManagerParams: KeyManagerParams): Future[HDWalletApi]
}

View file

@ -8,7 +8,7 @@ import org.bitcoins.core.bloom.BloomFilter
import org.bitcoins.core.config.NetworkParameters
import org.bitcoins.core.currency.CurrencyUnit
import org.bitcoins.core.gcs.GolombFilter
import org.bitcoins.core.hd.{AddressType, HDAccount, HDChainType, HDPurpose}
import org.bitcoins.core.hd.AddressType
import org.bitcoins.core.protocol.blockchain.{Block, BlockHeader, ChainParams}
import org.bitcoins.core.protocol.script.ScriptPubKey
import org.bitcoins.core.protocol.transaction.{
@ -27,10 +27,10 @@ import org.bitcoins.crypto.{
}
import org.bitcoins.keymanager._
import org.bitcoins.keymanager.bip39.BIP39KeyManager
import org.bitcoins.wallet.WalletLogger
import org.bitcoins.wallet.api.WalletApi.BlockMatchingResponse
import org.bitcoins.wallet.config.WalletAppConfig
import org.bitcoins.wallet.models.{AccountDb, AddressDb, SpendingInfoDb}
import org.bitcoins.wallet.{Wallet, WalletLogger}
import org.bitcoins.wallet.models.{AddressDb, SpendingInfoDb}
import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success}
@ -120,18 +120,6 @@ trait WalletApi extends WalletLogger {
} yield confirmed + unconfirmed
}
/** Gets the balance of the given account */
def getBalance(account: HDAccount): Future[CurrencyUnit] = {
val confirmedF = getConfirmedBalance(account)
val unconfirmedF = getUnconfirmedBalance(account)
for {
confirmed <- confirmedF
unconfirmed <- unconfirmedF
} yield {
confirmed + unconfirmed
}
}
/** Gets the sum of all UTXOs in this wallet with the address tag */
def getBalance(tag: AddressTag): Future[CurrencyUnit] = {
val confirmedF = getConfirmedBalance(tag)
@ -146,15 +134,11 @@ trait WalletApi extends WalletLogger {
/** Gets the sum of all confirmed UTXOs in this wallet */
def getConfirmedBalance(): Future[CurrencyUnit]
def getConfirmedBalance(account: HDAccount): Future[CurrencyUnit]
def getConfirmedBalance(tag: AddressTag): Future[CurrencyUnit]
/** Gets the sum of all unconfirmed UTXOs in this wallet */
def getUnconfirmedBalance(): Future[CurrencyUnit]
def getUnconfirmedBalance(account: HDAccount): Future[CurrencyUnit]
def getUnconfirmedBalance(tag: AddressTag): Future[CurrencyUnit]
/**
@ -169,40 +153,24 @@ trait WalletApi extends WalletLogger {
*/
def listUtxos(): Future[Vector[SpendingInfoDb]]
def listUtxos(account: HDAccount): Future[Vector[SpendingInfoDb]]
def listUtxos(tag: AddressTag): Future[Vector[SpendingInfoDb]]
def listUtxos(
hdAccount: HDAccount,
tag: AddressTag): Future[Vector[SpendingInfoDb]]
def listUtxos(state: TxoState): Future[Vector[SpendingInfoDb]]
def listUtxos(
hdAccount: HDAccount,
state: TxoState): Future[Vector[SpendingInfoDb]]
def listAddresses(): Future[Vector[AddressDb]]
def listAddresses(account: HDAccount): Future[Vector[AddressDb]]
def listSpentAddresses(): Future[Vector[AddressDb]]
def listSpentAddresses(account: HDAccount): Future[Vector[AddressDb]]
def listFundedAddresses(): Future[Vector[(AddressDb, CurrencyUnit)]]
def listFundedAddresses(
account: HDAccount): Future[Vector[(AddressDb, CurrencyUnit)]]
def listUnusedAddresses(): Future[Vector[AddressDb]]
def listUnusedAddresses(account: HDAccount): Future[Vector[AddressDb]]
def markUTXOsAsReserved(
utxos: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]]
/** Marks all utxos that are ours in this transactions as reserved */
def markUTXOsAsReserved(tx: Transaction): Future[Vector[SpendingInfoDb]]
def unmarkUTXOsAsReserved(
utxos: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]]
@ -212,15 +180,6 @@ trait WalletApi extends WalletLogger {
/** Checks if the wallet contains any data */
def isEmpty(): Future[Boolean]
/** Removes all utxos and addresses from the wallet account.
* Don't call this unless you are sure you can recover
* your wallet
*/
def clearUtxosAndAddresses(account: HDAccount): Future[WalletApi]
def clearUtxosAndAddresses(): Future[WalletApi] =
clearUtxosAndAddresses(walletConfig.defaultAccount)
/** Removes all utxos and addresses from the wallet.
* Don't call this unless you are sure you can recover
* your wallet
@ -235,7 +194,7 @@ trait WalletApi extends WalletLogger {
def getNewAddress(addressType: AddressType): Future[BitcoinAddress]
/**
* Gets a new external address from the default account.
* Gets a new external address
* Calling this method multiple
* times will return the same address, until it has
* received funds.
@ -257,43 +216,19 @@ trait WalletApi extends WalletLogger {
}
/**
* Gets a external address from the account associated with
* the given AddressType. Calling this method multiple
* times will return the same address, until it has
* Gets a external address the given AddressType. Calling this
* method multiple times will return the same address, until it has
* received funds.
*/
def getUnusedAddress(addressType: AddressType): Future[BitcoinAddress]
/**
* Gets a external address from the default account.
* Calling this method multiple
* Gets a external address. Calling this method multiple
* times will return the same address, until it has
* received funds.
*/
def getUnusedAddress: Future[BitcoinAddress]
/** Gets the address associated with the pubkey at
* the resulting `BIP32Path` determined by the
* default account and the given chainType and addressIndex
*/
def getAddress(
chainType: HDChainType,
addressIndex: Int): Future[AddressDb] = {
for {
account <- getDefaultAccount()
address <- getAddress(account, chainType, addressIndex)
} yield address
}
/** Gets the address associated with the pubkey at
* the resulting `BIP32Path` determined the given
* account, chainType, and addressIndex
*/
def getAddress(
account: AccountDb,
chainType: HDChainType,
addressIndex: Int): Future[AddressDb]
/**
* Mimics the `getaddressinfo` RPC call in Bitcoin Core
*
@ -317,29 +252,7 @@ trait WalletApi extends WalletLogger {
}
/** Generates a new change address */
protected[wallet] def getNewChangeAddress(
account: AccountDb): Future[BitcoinAddress]
/** Generates a new change address for the default account */
final protected[wallet] def getNewChangeAddress(): Future[BitcoinAddress] = {
for {
account <- getDefaultAccount
address <- getNewChangeAddress(account)
} yield address
}
/**
* Fetches the default account from the DB
* @return Future[AccountDb]
*/
protected[wallet] def getDefaultAccount(): Future[AccountDb]
/** Fetches the default account for the given address/account kind
* @param addressType
*/
protected[wallet] def getDefaultAccountForType(
addressType: AddressType): Future[AccountDb]
protected[wallet] def getNewChangeAddress(): Future[BitcoinAddress]
/**
* Unlocks the wallet with the provided passphrase,
@ -349,15 +262,6 @@ trait WalletApi extends WalletLogger {
KeyManagerUnlockError,
WalletApi]
def listAccounts(): Future[Vector[AccountDb]]
/** Lists all wallet accounts with the given type
* @param purpose
* @return [[Future[Vector[AccountDb]]
*/
def listAccounts(purpose: HDPurpose): Future[Vector[AccountDb]] =
listAccounts().map(_.filter(_.hdAccount.purpose == purpose))
/**
* Iterates over the block filters in order to find filters that match to the given addresses
*
@ -406,37 +310,15 @@ trait WalletApi extends WalletLogger {
* @param endOpt end block (if None it ends at the current tip)
* @param addressBatchSize how many addresses to match in a single pass
*/
def rescanNeutrinoWallet(
account: HDAccount,
startOpt: Option[BlockStamp],
endOpt: Option[BlockStamp],
addressBatchSize: Int,
useCreationTime: Boolean): Future[Unit]
def rescanNeutrinoWallet(
startOpt: Option[BlockStamp],
endOpt: Option[BlockStamp],
addressBatchSize: Int,
useCreationTime: Boolean): Future[Unit] =
rescanNeutrinoWallet(account = walletConfig.defaultAccount,
startOpt = startOpt,
endOpt = endOpt,
addressBatchSize = addressBatchSize,
useCreationTime = useCreationTime)
/** Helper method to rescan the ENTIRE blockchain. */
def fullRescanNeutrinoWallet(addressBatchSize: Int): Future[Unit] =
fullRescanNeutrinoWallet(account = walletConfig.defaultAccount,
addressBatchSize = addressBatchSize)
def fullRescanNeutrinoWallet(
account: HDAccount,
addressBatchSize: Int): Future[Unit] =
rescanNeutrinoWallet(account = account,
startOpt = None,
endOpt = None,
addressBatchSize = addressBatchSize,
useCreationTime = false)
def fullRescanNeutrinoWallet(addressBatchSize: Int): Future[Unit]
/**
* Recreates the account using BIP-44 approach
@ -447,7 +329,7 @@ trait WalletApi extends WalletLogger {
def keyManager: BIP39KeyManager
private def determineFeeRate(feeRateOpt: Option[FeeUnit]): Future[FeeUnit] =
protected def determineFeeRate(feeRateOpt: Option[FeeUnit]): Future[FeeUnit] =
feeRateOpt match {
case None =>
feeRateApi.getFeeRate
@ -459,29 +341,17 @@ trait WalletApi extends WalletLogger {
outPoints: Vector[TransactionOutPoint],
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
fromAccount: AccountDb): Future[Transaction]
feeRate: FeeUnit): Future[Transaction]
def sendFromOutPoints(
outPoints: Vector[TransactionOutPoint],
address: BitcoinAddress,
amount: CurrencyUnit,
feeRateOpt: Option[FeeUnit],
fromAccount: AccountDb): Future[Transaction] = {
feeRateOpt: Option[FeeUnit]
): Future[Transaction] = {
for {
feeRate <- determineFeeRate(feeRateOpt)
tx <- sendFromOutPoints(outPoints, address, amount, feeRate, fromAccount)
} yield tx
}
def sendFromOutPoints(
outPoints: Vector[TransactionOutPoint],
address: BitcoinAddress,
amount: CurrencyUnit,
feeRateOpt: Option[FeeUnit]): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendFromOutPoints(outPoints, address, amount, feeRateOpt, account)
tx <- sendFromOutPoints(outPoints, address, amount, feeRate)
} yield tx
}
@ -489,215 +359,92 @@ trait WalletApi extends WalletLogger {
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
algo: CoinSelectionAlgo,
fromAccount: AccountDb,
newTags: Vector[AddressTag]): Future[Transaction]
def sendWithAlgo(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
algo: CoinSelectionAlgo,
fromAccount: AccountDb): Future[Transaction] =
sendWithAlgo(address, amount, feeRate, algo, fromAccount, Vector.empty)
algo: CoinSelectionAlgo): Future[Transaction]
def sendWithAlgo(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRateOpt: Option[FeeUnit],
algo: CoinSelectionAlgo,
fromAccount: AccountDb): Future[Transaction] = {
algo: CoinSelectionAlgo
): Future[Transaction] = {
for {
feeRate <- determineFeeRate(feeRateOpt)
tx <- sendWithAlgo(address, amount, feeRate, algo, fromAccount)
} yield tx
}
def sendWithAlgo(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRateOpt: Option[FeeUnit],
algo: CoinSelectionAlgo): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendWithAlgo(address, amount, feeRateOpt, algo, account)
tx <- sendWithAlgo(address, amount, feeRate, algo)
} yield tx
}
/**
* Sends money from the specified account
* Sends money to the address
*
* todo: add error handling to signature
*/
def sendToAddress(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
fromAccount: AccountDb): Future[Transaction]
feeRate: FeeUnit): Future[Transaction]
/**
* Sends money from the specified account
*
* todo: add error handling to signature
*/
def sendToAddress(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRateOpt: Option[FeeUnit],
fromAccount: AccountDb): Future[Transaction] = {
for {
feeRate <- determineFeeRate(feeRateOpt)
tx <- sendToAddress(address, amount, feeRate, fromAccount)
} yield tx
}
/**
* Sends money from the default account
*
* todo: add error handling to signature
*/
def sendToAddress(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRateOpt: Option[FeeUnit]
): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendToAddress(address, amount, feeRateOpt, account)
feeRate <- determineFeeRate(feeRateOpt)
tx <- sendToAddress(address, amount, feeRate)
} yield tx
}
def sendToAddress(
address: BitcoinAddress,
amount: CurrencyUnit,
feeRate: FeeUnit,
fromAccount: AccountDb,
newTags: Vector[AddressTag]): Future[Transaction]
/**
* Sends money from the specified account
* Sends funds using the specified outputs
*
* todo: add error handling to signature
*/
def sendToOutputs(
outputs: Vector[TransactionOutput],
feeRate: FeeUnit,
fromAccount: AccountDb,
reserveUtxos: Boolean): Future[Transaction]
def sendToOutputs(
outputs: Vector[TransactionOutput],
feeRateOpt: Option[FeeUnit],
fromAccount: AccountDb,
reserveUtxos: Boolean): Future[Transaction] = {
feeRateOpt: Option[FeeUnit]): Future[Transaction] = {
for {
feeRate <- determineFeeRate(feeRateOpt)
tx <- sendToOutputs(outputs, feeRate, fromAccount, reserveUtxos)
tx <- sendToOutputs(outputs, feeRate)
} yield tx
}
/**
* Sends money from the default account
*
* todo: add error handling to signature
*/
def sendToOutputs(
outputs: Vector[TransactionOutput],
feeRateOpt: Option[FeeUnit],
reserveUtxos: Boolean): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- sendToOutputs(outputs, feeRateOpt, account, reserveUtxos)
} yield tx
}
feeRate: FeeUnit): Future[Transaction]
/**
* Sends money from the specified account
*
* todo: add error handling to signature
* Sends funds to each address
*/
def sendToAddresses(
addresses: Vector[BitcoinAddress],
amounts: Vector[CurrencyUnit],
feeRate: FeeUnit,
fromAccount: AccountDb,
reserveUtxos: Boolean): Future[Transaction]
/**
* Sends money from the specified account
*
* todo: add error handling to signature
*/
def sendToAddresses(
addresses: Vector[BitcoinAddress],
amounts: Vector[CurrencyUnit],
feeRateOpt: Option[FeeUnit],
fromAccount: AccountDb,
reserveUtxos: Boolean): Future[Transaction] = {
feeRateOpt: Option[FeeUnit]): Future[Transaction] = {
for {
feeRate <- determineFeeRate(feeRateOpt)
tx <-
sendToAddresses(addresses, amounts, feeRate, fromAccount, reserveUtxos)
tx <- sendToAddresses(addresses, amounts, feeRate)
} yield tx
}
/**
* Sends money from the default account
*
* todo: add error handling to signature
*/
def sendToAddresses(
addresses: Vector[BitcoinAddress],
amounts: Vector[CurrencyUnit],
feeRateOpt: Option[FeeUnit],
reserveUtxos: Boolean): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <-
sendToAddresses(addresses, amounts, feeRateOpt, account, reserveUtxos)
} yield tx
}
feeRate: FeeUnit): Future[Transaction]
def makeOpReturnCommitment(
message: String,
hashMessage: Boolean,
feeRate: FeeUnit,
fromAccount: AccountDb): Future[Transaction]
def makeOpReturnCommitment(
message: String,
hashMessage: Boolean,
feeRateOpt: Option[FeeUnit],
fromAccount: AccountDb): Future[Transaction] = {
for {
feeRate <- determineFeeRate(feeRateOpt)
tx <- makeOpReturnCommitment(message, hashMessage, feeRate, fromAccount)
} yield tx
}
feeRate: FeeUnit): Future[Transaction]
def makeOpReturnCommitment(
message: String,
hashMessage: Boolean,
feeRateOpt: Option[FeeUnit]): Future[Transaction] = {
for {
account <- getDefaultAccount()
tx <- makeOpReturnCommitment(message, hashMessage, feeRateOpt, account)
feeRate <- determineFeeRate(feeRateOpt)
tx <- makeOpReturnCommitment(message, hashMessage, feeRate)
} yield tx
}
def createNewAccount(keyManagerParams: KeyManagerParams): Future[Wallet]
/**
* Tries to create a new account in this wallet. Fails if the
* most recent account has no transaction history, as per
* BIP44
*
* @see [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#account BIP44 account section]]
*/
def createNewAccount(
hdAccount: HDAccount,
keyManagerParams: KeyManagerParams): Future[Wallet]
}
object WalletApi {

View file

@ -14,7 +14,7 @@ import org.bitcoins.keymanager.{
KeyManagerParams,
WalletStorage
}
import org.bitcoins.wallet.api.WalletApi
import org.bitcoins.wallet.api.HDWalletApi
import org.bitcoins.wallet.db.WalletDbManagement
import org.bitcoins.wallet.models.AccountDAO
import org.bitcoins.wallet.{Wallet, WalletLogger}
@ -157,16 +157,17 @@ case class WalletAppConfig(
}
/** Creates a wallet based on this [[WalletAppConfig]] */
def createWallet(
def createHDWallet(
nodeApi: NodeApi,
chainQueryApi: ChainQueryApi,
feeRateApi: FeeRateApi,
bip39PasswordOpt: Option[String])(implicit
ec: ExecutionContext): Future[WalletApi] = {
WalletAppConfig.createWallet(nodeApi = nodeApi,
chainQueryApi = chainQueryApi,
feeRateApi = feeRateApi,
bip39PasswordOpt = bip39PasswordOpt)(this, ec)
ec: ExecutionContext): Future[HDWalletApi] = {
WalletAppConfig.createHDWallet(
nodeApi = nodeApi,
chainQueryApi = chainQueryApi,
feeRateApi = feeRateApi,
bip39PasswordOpt = bip39PasswordOpt)(this, ec)
}
/** Starts the associated application */
@ -187,13 +188,13 @@ object WalletAppConfig
WalletAppConfig(datadir, useLogbackConf, confs: _*)
/** Creates a wallet based on the given [[WalletAppConfig]] */
def createWallet(
def createHDWallet(
nodeApi: NodeApi,
chainQueryApi: ChainQueryApi,
feeRateApi: FeeRateApi,
bip39PasswordOpt: Option[String])(implicit
walletConf: WalletAppConfig,
ec: ExecutionContext): Future[WalletApi] = {
ec: ExecutionContext): Future[HDWalletApi] = {
walletConf.hasWallet().flatMap { walletExists =>
if (walletExists) {
logger.info(s"Using pre-existing wallet")

View file

@ -36,7 +36,7 @@ private[wallet] trait UtxoHandling extends WalletLogger {
/** @inheritdoc */
override def listUtxos(): Future[Vector[SpendingInfoDb]] = {
listUtxos(walletConfig.defaultAccount)
spendingInfoDAO.findAllUnspent()
}
override def listUtxos(
@ -255,6 +255,15 @@ private[wallet] trait UtxoHandling extends WalletLogger {
} yield utxos
}
/** @inheritdoc */
override def markUTXOsAsReserved(
tx: Transaction): Future[Vector[SpendingInfoDb]] = {
for {
utxos <- spendingInfoDAO.findOutputsBeingSpent(tx)
reserved <- markUTXOsAsReserved(utxos.toVector)
} yield reserved
}
override def unmarkUTXOsAsReserved(
utxos: Vector[SpendingInfoDb]): Future[Vector[SpendingInfoDb]] = {
val unreserved = utxos.filterNot(_.state == TxoState.Reserved)