From 13a895efe93321c0e5d547c282723f375f487a27 Mon Sep 17 00:00:00 2001
From: Chris Stewart <stewart.chris1234@gmail.com>
Date: Fri, 27 Sep 2024 13:40:29 -0500
Subject: [PATCH] 2024 09 24 simplify wallet (#5685)

* WIP: Simplify wallet

# Conflicts:
#	fee-provider/src/main/scala/org/bitcoins/feeprovider/FeeProviderFactory.scala

# Conflicts:
#	wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala

* Get walletTest/test passing

* Remove WalletApi.{start(),stop()}

 Conflicts:
	core/src/main/scala/org/bitcoins/core/api/wallet/WalletApi.scala
	wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala
	wallet/src/main/scala/org/bitcoins/wallet/WalletHolder.scala

* Cleanup RescanDLCTest

* Move checkRootAccount into AccountHandling.scala

* Fix rebase

* Fix docs
---
 .../org/bitcoins/server/RoutesSpec.scala      |   3 +-
 .../bitcoins/server/WalletRoutesSpec.scala    |   3 +-
 .../bitcoins/server/BitcoinSServerMain.scala  |  13 +-
 .../server/BitcoindRpcBackendUtil.scala       |   6 +-
 .../bitcoins/server/DLCWalletLoaderApi.scala  |   9 +-
 build.sbt                                     |   2 +-
 .../bitcoins/core/api/wallet/WalletApi.scala  |   9 +-
 .../bitcoins/dlc/wallet/RescanDLCTest.scala   |   9 +-
 .../bitcoins/dlc/wallet/DLCAppConfig.scala    |  14 +-
 .../org/bitcoins/dlc/wallet/DLCWallet.scala   |   9 +-
 docs/chain/chain-query-api.md                 |   2 +-
 docs/node/node-api.md                         |   2 +-
 docs/wallet/wallet-callbacks.md               |   3 +-
 docs/wallet/wallet-sync.md                    |   3 +-
 docs/wallet/wallet.md                         |   2 +-
 .../feeprovider/FeeProviderName.scala         |   2 +-
 .../feeprovider/RandomFeeProvider.scala       |   2 +-
 .../testkit/BitcoinSTestAppConfig.scala       |   1 +
 .../node/NodeTestWithCachedBitcoind.scala     |   3 -
 .../testkit/server/WalletLoaderFixtures.scala |   3 +-
 .../testkit/wallet/BitcoinSWalletTest.scala   |  32 ++---
 .../bitcoins/wallet/TrezorAddressTest.scala   |   5 +-
 .../org/bitcoins/wallet/WalletUnitTest.scala  |   2 +-
 .../scala/org/bitcoins/wallet/Wallet.scala    |  48 +------
 .../org/bitcoins/wallet/WalletHolder.scala    |  35 +----
 .../wallet/config/WalletAppConfig.scala       | 135 +++++++++++++-----
 .../wallet/internal/AccountHandling.scala     |  29 +++-
 27 files changed, 175 insertions(+), 211 deletions(-)

diff --git a/app/server-test/src/test/scala/org/bitcoins/server/RoutesSpec.scala b/app/server-test/src/test/scala/org/bitcoins/server/RoutesSpec.scala
index 879a4c638e..88d4318042 100644
--- a/app/server-test/src/test/scala/org/bitcoins/server/RoutesSpec.scala
+++ b/app/server-test/src/test/scala/org/bitcoins/server/RoutesSpec.scala
@@ -125,8 +125,7 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
     DLCWalletNeutrinoBackendLoader(
       walletHolder,
       mockChainApi,
-      mockNode,
-      feeRateApi
+      mockNode
     )
   }
 
diff --git a/app/server-test/src/test/scala/org/bitcoins/server/WalletRoutesSpec.scala b/app/server-test/src/test/scala/org/bitcoins/server/WalletRoutesSpec.scala
index 10647c9c03..bc009a6cb6 100644
--- a/app/server-test/src/test/scala/org/bitcoins/server/WalletRoutesSpec.scala
+++ b/app/server-test/src/test/scala/org/bitcoins/server/WalletRoutesSpec.scala
@@ -51,8 +51,7 @@ class WalletRoutesSpec
     DLCWalletNeutrinoBackendLoader(
       walletHolder,
       mockChainApi,
-      mockNode,
-      feeRateApi
+      mockNode
     )
 
   val walletRoutes: WalletRoutes =
diff --git a/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala b/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala
index 5f2a9d43fc..a0033a824f 100644
--- a/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala
+++ b/app/server/src/main/scala/org/bitcoins/server/BitcoinSServerMain.scala
@@ -29,7 +29,6 @@ import org.bitcoins.core.util.TimeUtil
 import org.bitcoins.dlc.node.DLCNode
 import org.bitcoins.dlc.node.config.DLCNodeAppConfig
 import org.bitcoins.dlc.wallet.*
-import org.bitcoins.feeprovider.MempoolSpaceTarget.HourFeeTarget
 import org.bitcoins.feeprovider.*
 import org.bitcoins.node.Node
 import org.bitcoins.node.config.NodeAppConfig
@@ -185,15 +184,6 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
       walletCreationTimeOpt = Some(creationTime)
     )(chainConf, system)
 
-    val defaultApi =
-      MempoolSpaceProvider(HourFeeTarget, network, torConf.socks5ProxyParams)
-    val feeProvider = FeeProviderFactory.getFeeProviderOrElse(
-      defaultApi,
-      conf.walletConf.feeProviderNameOpt,
-      conf.walletConf.feeProviderTargetOpt,
-      torConf.socks5ProxyParams,
-      network
-    )
     // get our wallet
     val walletHolder = WalletHolder.empty
     val neutrinoWalletLoaderF = {
@@ -203,8 +193,7 @@ class BitcoinSServerMain(override val serverArgParser: ServerArgParser)(implicit
         val l = DLCWalletNeutrinoBackendLoader(
           walletHolder,
           chainApi,
-          nodeApi = node,
-          feeRateApi = feeProvider
+          nodeApi = node
         )
         walletLoaderApiOpt = Some(l)
         l
diff --git a/app/server/src/main/scala/org/bitcoins/server/BitcoindRpcBackendUtil.scala b/app/server/src/main/scala/org/bitcoins/server/BitcoindRpcBackendUtil.scala
index 97dd34a7e8..640cc6f6f7 100644
--- a/app/server/src/main/scala/org/bitcoins/server/BitcoindRpcBackendUtil.scala
+++ b/app/server/src/main/scala/org/bitcoins/server/BitcoindRpcBackendUtil.scala
@@ -222,8 +222,7 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
     )
     val pairedWallet = Wallet(
       nodeApi = nodeApi,
-      chainQueryApi = bitcoind,
-      feeRateApi = wallet.feeRateApi
+      chainQueryApi = bitcoind
     )(wallet.walletConfig)
 
     walletCallbackP.success(pairedWallet)
@@ -305,8 +304,7 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
         walletCallbackP.future,
         chainCallbacksOpt
       ),
-      chainQueryApi = bitcoind,
-      feeRateApi = wallet.feeRateApi
+      chainQueryApi = bitcoind
     )(wallet.walletConfig, wallet.dlcConfig)
 
     walletCallbackP.success(pairedWallet)
diff --git a/app/server/src/main/scala/org/bitcoins/server/DLCWalletLoaderApi.scala b/app/server/src/main/scala/org/bitcoins/server/DLCWalletLoaderApi.scala
index 38d607f041..60ca6be644 100644
--- a/app/server/src/main/scala/org/bitcoins/server/DLCWalletLoaderApi.scala
+++ b/app/server/src/main/scala/org/bitcoins/server/DLCWalletLoaderApi.scala
@@ -50,7 +50,6 @@ sealed trait DLCWalletLoaderApi
   protected def loadWallet(
       chainQueryApi: ChainQueryApi,
       nodeApi: NodeApi,
-      feeProviderApi: FeeRateApi,
       walletNameOpt: Option[String],
       aesPasswordOpt: Option[AesPassword]
   )(implicit
@@ -71,8 +70,7 @@ sealed trait DLCWalletLoaderApi
       _ <- dlcConfig.start()
       dlcWallet <- dlcConfig.createDLCWallet(
         nodeApi = nodeApi,
-        chainQueryApi = chainQueryApi,
-        feeRateApi = feeProviderApi
+        chainQueryApi = chainQueryApi
       )(walletConfig)
     } yield (dlcWallet, walletConfig, dlcConfig)
   }
@@ -271,8 +269,7 @@ sealed trait DLCWalletLoaderApi
 case class DLCWalletNeutrinoBackendLoader(
     walletHolder: WalletHolder,
     chainQueryApi: ChainQueryApi,
-    nodeApi: NodeApi,
-    feeRateApi: FeeRateApi
+    nodeApi: NodeApi
 )(implicit
     override val conf: BitcoinSAppConfig,
     override val system: ActorSystem
@@ -301,7 +298,6 @@ case class DLCWalletNeutrinoBackendLoader(
       (dlcWallet, walletConfig, dlcConfig) <- loadWallet(
         chainQueryApi = chainQueryApi,
         nodeApi = nodeApi,
-        feeProviderApi = feeRateApi,
         walletNameOpt = walletNameOpt,
         aesPasswordOpt = aesPasswordOpt
       )
@@ -351,7 +347,6 @@ case class DLCWalletBitcoindBackendLoader(
       (dlcWallet, walletConfig, dlcConfig) <- loadWallet(
         chainQueryApi = bitcoind,
         nodeApi = nodeApi,
-        feeProviderApi = feeProvider,
         walletNameOpt = walletNameOpt,
         aesPasswordOpt = aesPasswordOpt
       )
diff --git a/build.sbt b/build.sbt
index bb6f63449f..c32cf0d6e0 100644
--- a/build.sbt
+++ b/build.sbt
@@ -775,7 +775,7 @@ lazy val wallet = project
     name := "bitcoin-s-wallet",
     libraryDependencies ++= Deps.wallet(scalaVersion.value)
   )
-  .dependsOn(coreJVM, appCommons, dbCommons, keyManager, asyncUtilsJVM, tor)
+  .dependsOn(coreJVM, appCommons, dbCommons, keyManager, asyncUtilsJVM, feeProvider, tor)
 
 lazy val walletTest = project
   .in(file("wallet-test"))
diff --git a/core/src/main/scala/org/bitcoins/core/api/wallet/WalletApi.scala b/core/src/main/scala/org/bitcoins/core/api/wallet/WalletApi.scala
index 3a2c0b26a3..ee6be69c5b 100644
--- a/core/src/main/scala/org/bitcoins/core/api/wallet/WalletApi.scala
+++ b/core/src/main/scala/org/bitcoins/core/api/wallet/WalletApi.scala
@@ -8,7 +8,6 @@ import org.bitcoins.core.currency.CurrencyUnit
 import org.bitcoins.core.hd.HDAccount
 import org.bitcoins.core.protocol.BitcoinAddress
 import org.bitcoins.core.protocol.transaction.Transaction
-import org.bitcoins.core.util.StartStopAsync
 import org.bitcoins.core.wallet.fee.FeeUnit
 import org.bitcoins.crypto.DoubleSha256DigestBE
 
@@ -22,7 +21,7 @@ import scala.concurrent.{ExecutionContext, Future}
   * @see
   *   [[https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki BIP44]]
   */
-trait WalletApi extends StartStopAsync[WalletApi] {
+trait WalletApi {
   def accountHandling: AccountHandlingApi
   def fundTxHandling: FundTransactionHandlingApi
   def rescanHandling: RescanHandlingApi
@@ -33,7 +32,7 @@ trait WalletApi extends StartStopAsync[WalletApi] {
 
   val nodeApi: NodeApi
   val chainQueryApi: ChainQueryApi
-  val feeRateApi: FeeRateApi
+  def feeRateApi: FeeRateApi
   val creationTime: Instant
 
   def broadcastTransaction(transaction: Transaction): Future[Unit] =
@@ -41,10 +40,6 @@ trait WalletApi extends StartStopAsync[WalletApi] {
 
   def getFeeRate(): Future[FeeUnit] = feeRateApi.getFeeRate()
 
-  def start(): Future[WalletApi]
-
-  def stop(): Future[WalletApi]
-
   /** Gets the sum of all UTXOs in this wallet */
   def getBalance()(implicit ec: ExecutionContext): Future[CurrencyUnit] = {
     val confirmedF = getConfirmedBalance()
diff --git a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/RescanDLCTest.scala b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/RescanDLCTest.scala
index 0ac68e8032..18e918e3f3 100644
--- a/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/RescanDLCTest.scala
+++ b/dlc-wallet-test/src/test/scala/org/bitcoins/dlc/wallet/RescanDLCTest.scala
@@ -6,8 +6,9 @@ import org.bitcoins.core.protocol.dlc.models.{
   DisjointUnionContractInfo,
   SingleContractInfo
 }
+import org.bitcoins.core.wallet.rescan.RescanState
 import org.bitcoins.rpc.client.common.BitcoindRpcClient
-import org.bitcoins.testkit.wallet.DLCWalletUtil._
+import org.bitcoins.testkit.wallet.DLCWalletUtil.*
 import org.bitcoins.testkit.wallet.{DLCWalletUtil, DualWalletTestCachedBitcoind}
 import org.scalatest.FutureOutcome
 
@@ -55,7 +56,7 @@ class RescanDLCTest extends DualWalletTestCachedBitcoind {
 
       Vector(hash) <- bitcoind.generate(1)
 
-      _ <- wallet.rescanHandling.rescanNeutrinoWallet(
+      rescanState <- wallet.rescanHandling.rescanNeutrinoWallet(
         startOpt = None,
         endOpt = Some(BlockHash(hash)),
         addressBatchSize = 20,
@@ -64,6 +65,7 @@ class RescanDLCTest extends DualWalletTestCachedBitcoind {
       )
 
       postStatus <- getDLCStatus(wallet)
+      _ <- RescanState.awaitRescanDone(rescanState)
     } yield assert(postStatus.state == DLCState.Claimed)
   }
 
@@ -100,7 +102,7 @@ class RescanDLCTest extends DualWalletTestCachedBitcoind {
 
       Vector(hash) <- bitcoind.generate(1)
 
-      _ <- wallet.rescanHandling.rescanNeutrinoWallet(
+      rescanState <- wallet.rescanHandling.rescanNeutrinoWallet(
         startOpt = None,
         endOpt = Some(BlockHash(hash)),
         addressBatchSize = 20,
@@ -109,6 +111,7 @@ class RescanDLCTest extends DualWalletTestCachedBitcoind {
       )
 
       postStatus <- getDLCStatus(wallet)
+      _ <- RescanState.awaitRescanDone(rescanState)
     } yield assert(postStatus.state == DLCState.RemoteClaimed)
   }
 }
diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCAppConfig.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCAppConfig.scala
index 449dac5487..abdcf24c69 100644
--- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCAppConfig.scala
+++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCAppConfig.scala
@@ -6,7 +6,6 @@ import org.bitcoins.commons.config.{AppConfigFactoryBase, ConfigOps}
 import org.bitcoins.core.api.CallbackConfig
 import org.bitcoins.core.api.chain.ChainQueryApi
 import org.bitcoins.core.api.dlc.wallet.db.DLCDb
-import org.bitcoins.core.api.feeprovider.FeeRateApi
 import org.bitcoins.core.api.node.NodeApi
 import org.bitcoins.core.protocol.dlc.models.DLCState.{
   AdaptorSigComputationState,
@@ -144,13 +143,11 @@ case class DLCAppConfig(
 
   def createDLCWallet(
       nodeApi: NodeApi,
-      chainQueryApi: ChainQueryApi,
-      feeRateApi: FeeRateApi
+      chainQueryApi: ChainQueryApi
   )(implicit walletConf: WalletAppConfig): Future[DLCWallet] = {
     DLCAppConfig.createDLCWallet(
       nodeApi = nodeApi,
-      chainQueryApi = chainQueryApi,
-      feeRateApi = feeRateApi
+      chainQueryApi = chainQueryApi
     )(walletConf, this)
   }
 
@@ -327,8 +324,7 @@ object DLCAppConfig
   /** Creates a wallet based on the given [[WalletAppConfig]] */
   def createDLCWallet(
       nodeApi: NodeApi,
-      chainQueryApi: ChainQueryApi,
-      feeRateApi: FeeRateApi
+      chainQueryApi: ChainQueryApi
   )(implicit
       walletConf: WalletAppConfig,
       dlcConf: DLCAppConfig
@@ -339,12 +335,12 @@ object DLCAppConfig
       if (walletExists) {
         logger.info(s"Using pre-existing wallet")
         val wallet =
-          DLCWallet(nodeApi, chainQueryApi, feeRateApi)
+          DLCWallet(nodeApi, chainQueryApi)
         Future.successful(wallet)
       } else {
         logger.info(s"Creating new wallet")
         val unInitializedWallet =
-          DLCWallet(nodeApi, chainQueryApi, feeRateApi)
+          DLCWallet(nodeApi, chainQueryApi)
 
         Wallet
           .initialize(
diff --git a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCWallet.scala b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCWallet.scala
index d5c5fe85ef..a13916f16c 100644
--- a/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCWallet.scala
+++ b/dlc-wallet/src/main/scala/org/bitcoins/dlc/wallet/DLCWallet.scala
@@ -3,7 +3,6 @@ package org.bitcoins.dlc.wallet
 import org.bitcoins.core.api.chain.ChainQueryApi
 import org.bitcoins.core.api.dlc.wallet.DLCNeutrinoHDWalletApi
 import org.bitcoins.core.api.dlc.wallet.db.DLCDb
-import org.bitcoins.core.api.feeprovider.FeeRateApi
 import org.bitcoins.core.api.node.NodeApi
 import org.bitcoins.core.api.wallet.db.*
 import org.bitcoins.core.currency.*
@@ -2267,8 +2266,7 @@ object DLCWallet extends WalletLogger {
 
   private case class DLCWalletImpl(
       nodeApi: NodeApi,
-      chainQueryApi: ChainQueryApi,
-      feeRateApi: FeeRateApi
+      chainQueryApi: ChainQueryApi
   )(implicit
       val walletConfig: WalletAppConfig,
       val dlcConfig: DLCAppConfig
@@ -2276,10 +2274,9 @@ object DLCWallet extends WalletLogger {
 
   def apply(
       nodeApi: NodeApi,
-      chainQueryApi: ChainQueryApi,
-      feeRateApi: FeeRateApi
+      chainQueryApi: ChainQueryApi
   )(implicit config: WalletAppConfig, dlcConfig: DLCAppConfig): DLCWallet = {
-    DLCWalletImpl(nodeApi, chainQueryApi, feeRateApi)
+    DLCWalletImpl(nodeApi, chainQueryApi)
   }
 
   private object AcceptingOffersLatch {
diff --git a/docs/chain/chain-query-api.md b/docs/chain/chain-query-api.md
index d615702384..ea7a89585d 100644
--- a/docs/chain/chain-query-api.md
+++ b/docs/chain/chain-query-api.md
@@ -188,7 +188,7 @@ val chainApi = new ChainQueryApi {
 
 // Finally, we can initialize our wallet with our own node api
 val wallet =
-    Wallet(nodeApi = nodeApi, chainQueryApi = chainApi, feeRateApi = ConstantFeeRateProvider(SatoshisPerVirtualByte.one))
+    Wallet(nodeApi = nodeApi, chainQueryApi = chainApi)
 
 // Then to trigger one of the events we can run
 wallet.chainQueryApi.getFiltersBetweenHeights(100, 150)
diff --git a/docs/node/node-api.md b/docs/node/node-api.md
index 50071a1b10..17d36a3349 100644
--- a/docs/node/node-api.md
+++ b/docs/node/node-api.md
@@ -95,7 +95,7 @@ val exampleCallback = createCallback(exampleProcessBlock)
 
 // Finally, we can initialize our wallet with our own node api
 val wallet =
-    Wallet(nodeApi = nodeApi, chainQueryApi = chainApi, feeRateApi = ConstantFeeRateProvider(SatoshisPerVirtualByte.one))
+    Wallet(nodeApi = nodeApi, chainQueryApi = chainApi)
 
 // Then to trigger the event we can run
 val exampleBlock = DoubleSha256DigestBE(
diff --git a/docs/wallet/wallet-callbacks.md b/docs/wallet/wallet-callbacks.md
index 9a2e47a437..bf4e3bc76f 100644
--- a/docs/wallet/wallet-callbacks.md
+++ b/docs/wallet/wallet-callbacks.md
@@ -70,8 +70,7 @@ val exampleCallbacks = WalletCallbacks(
 val wallet =
     Wallet(
            nodeApi = bitcoind,
-           chainQueryApi = bitcoind,
-           feeRateApi = ConstantFeeRateProvider(SatoshisPerVirtualByte.one))
+           chainQueryApi = bitcoind)
 
 // Finally, we can add the callbacks to our wallet config
 walletConf.addCallbacks(exampleCallbacks)
diff --git a/docs/wallet/wallet-sync.md b/docs/wallet/wallet-sync.md
index 3fe2a84bc0..342d1f275b 100644
--- a/docs/wallet/wallet-sync.md
+++ b/docs/wallet/wallet-sync.md
@@ -115,8 +115,7 @@ val genesisHashBEF = bitcoind.getBlockHash(0)
 //a fresh wallet
 implicit val walletAppConfig: WalletAppConfig = WalletAppConfig.fromDefaultDatadir()
 
-val feeRateProvider: FeeRateApi = MempoolSpaceProvider.fromBlockTarget(6, proxyParams = None)
-val wallet = Wallet(bitcoind, bitcoind, feeRateProvider)
+val wallet = Wallet(bitcoind, bitcoind)
 
 //yay! we have a synced wallet
 val syncedWalletF = genesisHashBEF.flatMap { genesisHash => 
diff --git a/docs/wallet/wallet.md b/docs/wallet/wallet.md
index 27e2b7433a..da34128d52 100644
--- a/docs/wallet/wallet.md
+++ b/docs/wallet/wallet.md
@@ -150,7 +150,7 @@ val wallet = Wallet(new NodeApi {
     override def broadcastTransactions(txs: Vector[Transaction]): Future[Unit] = Future.successful(())
     override def downloadBlocks(blockHashes: Vector[DoubleSha256DigestBE]): Future[Unit] = Future.successful(())
     override def getConnectionCount: Future[Int] = Future.successful(0)
-  }, chainApi, ConstantFeeRateProvider(SatoshisPerVirtualByte.one))
+  }, chainApi)
 val walletF: Future[WalletApi] = configF.flatMap { _ =>
   Wallet.initialize(wallet, wallet.accountHandling, None)
 }
diff --git a/fee-provider/src/main/scala/org/bitcoins/feeprovider/FeeProviderName.scala b/fee-provider/src/main/scala/org/bitcoins/feeprovider/FeeProviderName.scala
index 088936721f..27d993e1a0 100644
--- a/fee-provider/src/main/scala/org/bitcoins/feeprovider/FeeProviderName.scala
+++ b/fee-provider/src/main/scala/org/bitcoins/feeprovider/FeeProviderName.scala
@@ -17,7 +17,7 @@ object FeeProviderName extends StringFactory[FeeProviderName] {
   case object Random extends FeeProviderName
 
   val all: Vector[FeeProviderName] =
-    Vector(BitcoinerLive, BitGo, Constant, MempoolSpace)
+    Vector(BitcoinerLive, BitGo, Constant, MempoolSpace, Random)
 
   override def fromStringOpt(str: String): Option[FeeProviderName] = {
     all.find(_.toString.toLowerCase == str.toLowerCase)
diff --git a/fee-provider/src/main/scala/org/bitcoins/feeprovider/RandomFeeProvider.scala b/fee-provider/src/main/scala/org/bitcoins/feeprovider/RandomFeeProvider.scala
index c1c246a3d8..a762585483 100644
--- a/fee-provider/src/main/scala/org/bitcoins/feeprovider/RandomFeeProvider.scala
+++ b/fee-provider/src/main/scala/org/bitcoins/feeprovider/RandomFeeProvider.scala
@@ -14,7 +14,7 @@ class RandomFeeProvider extends FeeRateApi {
   var lastFeeRate: Option[FeeUnit] = None
 
   override def getFeeRate(): Future[FeeUnit] = {
-    val raw = scala.util.Random.between(1, 10000)
+    val raw = scala.util.Random.between(1, 1000)
     val feeRate = SatoshisPerVirtualByte(Satoshis(raw))
     lastFeeRate = Some(feeRate)
     Future.successful(feeRate)
diff --git a/testkit/src/main/scala/org/bitcoins/testkit/BitcoinSTestAppConfig.scala b/testkit/src/main/scala/org/bitcoins/testkit/BitcoinSTestAppConfig.scala
index 39e295a179..42f4606e1e 100644
--- a/testkit/src/main/scala/org/bitcoins/testkit/BitcoinSTestAppConfig.scala
+++ b/testkit/src/main/scala/org/bitcoins/testkit/BitcoinSTestAppConfig.scala
@@ -84,6 +84,7 @@ object BitcoinSTestAppConfig {
            |     relay = true
            |     enable-peer-discovery = false
            |  }
+           |  fee-provider.name = "random"
            |  proxy.enabled = $torEnabled
            |  tor.enabled = $torEnabled
            |  tor.use-random-ports = false  
diff --git a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestWithCachedBitcoind.scala b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestWithCachedBitcoind.scala
index 9e8139f033..65491d225c 100644
--- a/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestWithCachedBitcoind.scala
+++ b/testkit/src/main/scala/org/bitcoins/testkit/node/NodeTestWithCachedBitcoind.scala
@@ -216,11 +216,8 @@ trait NodeTestWithCachedBitcoind extends BaseNodeTest with CachedTor {
   ): Future[Unit] = {
     val node = nodeWithBitcoind.node
     val destroyNodeF = tearDownNode(node, appConfig)
-    val destroyWalletF =
-      BitcoinSWalletTest.destroyWallet(nodeWithBitcoind.wallet)
     for {
       _ <- destroyNodeF
-      _ <- destroyWalletF
       _ <- BitcoinSWalletTest.destroyWalletAppConfig(appConfig.walletConf)
     } yield ()
   }
diff --git a/testkit/src/main/scala/org/bitcoins/testkit/server/WalletLoaderFixtures.scala b/testkit/src/main/scala/org/bitcoins/testkit/server/WalletLoaderFixtures.scala
index 4c95f6b6f5..c2e27b84b9 100644
--- a/testkit/src/main/scala/org/bitcoins/testkit/server/WalletLoaderFixtures.scala
+++ b/testkit/src/main/scala/org/bitcoins/testkit/server/WalletLoaderFixtures.scala
@@ -24,8 +24,7 @@ trait WalletLoaderFixtures
         // initialize the default wallet so it can be used in tests
         _ <- config.walletConf.createHDWallet(
           nodeApi = bitcoind,
-          chainQueryApi = bitcoind,
-          feeRateApi = bitcoind
+          chainQueryApi = bitcoind
         )
 
         walletHolder = WalletHolder.empty
diff --git a/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSWalletTest.scala b/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSWalletTest.scala
index c012921071..2b46e809e8 100644
--- a/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSWalletTest.scala
+++ b/testkit/src/main/scala/org/bitcoins/testkit/wallet/BitcoinSWalletTest.scala
@@ -9,7 +9,6 @@ import org.bitcoins.core.api.node.NodeApi
 import org.bitcoins.core.api.wallet.WalletApi
 import org.bitcoins.core.currency.*
 import org.bitcoins.dlc.wallet.{DLCAppConfig, DLCWallet}
-import org.bitcoins.feeprovider.RandomFeeProvider
 import org.bitcoins.node.NodeCallbacks
 import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion}
 import org.bitcoins.server.BitcoinSAppConfig
@@ -75,9 +74,8 @@ trait BitcoinSWalletTest
       makeDependentFixture[Wallet](
         build =
           createNewWallet(nodeApi = nodeApi, chainQueryApi = chainQueryApi),
-        destroy = { wallet =>
+        destroy = { (_: WalletApi) =>
           for {
-            _ <- destroyWallet(wallet)
             _ <- destroyWalletAppConfig(newWalletConf)
           } yield ()
         }
@@ -93,9 +91,8 @@ trait BitcoinSWalletTest
   )(implicit walletAppConfig: WalletAppConfig): FutureOutcome = {
     makeDependentFixture(
       build = () => FundWalletUtil.createFundedWallet(nodeApi, chainQueryApi),
-      destroy = { (funded: FundedWallet) =>
+      destroy = { (_: FundedWallet) =>
         for {
-          _ <- destroyWallet(funded.wallet)
           _ <- destroyWalletAppConfig(walletAppConfig)
         } yield ()
       }
@@ -107,9 +104,8 @@ trait BitcoinSWalletTest
   )(implicit walletAppConfig: WalletAppConfig): FutureOutcome = {
     makeDependentFixture(
       build = () => FundWalletUtil.createFundedWallet(nodeApi, chainQueryApi),
-      destroy = { (funded: FundedWallet) =>
+      destroy = { (_: FundedWallet) =>
         for {
-          _ <- destroyWallet(funded.wallet)
           _ <- destroyWalletAppConfig(walletAppConfig)
         } yield ()
       }
@@ -152,9 +148,8 @@ trait BitcoinSWalletTest
       build = { () =>
         createDefaultWallet(nodeApi, chainQueryApi)
       },
-      destroy = { wallet =>
+      destroy = { (_: WalletApi) =>
         for {
-          _ <- destroyWallet(wallet)
           _ <- destroyWalletAppConfig(walletAppConfig)
         } yield ()
       }
@@ -168,7 +163,7 @@ trait BitcoinSWalletTest
       build = { () =>
         createWallet2Accounts(nodeApi, chainQueryApi)
       },
-      destroy = destroyWallet
+      destroy = { (_: WalletApi) => Future.unit }
     )(test)
   }
 
@@ -285,7 +280,7 @@ object BitcoinSWalletTest extends WalletLogger {
 
       walletConfig.start().flatMap { _ =>
         val wallet =
-          Wallet(nodeApi, chainQueryApi, new RandomFeeProvider)(walletConfig)
+          Wallet(nodeApi, chainQueryApi)(walletConfig)
         Wallet.initialize(wallet,
                           wallet.accountHandling,
                           walletConfig.bip39PasswordOpt)
@@ -310,7 +305,7 @@ object BitcoinSWalletTest extends WalletLogger {
 
     initConfs.flatMap { _ =>
       val wallet =
-        DLCWallet(nodeApi, chainQueryApi, new RandomFeeProvider)(
+        DLCWallet(nodeApi, chainQueryApi)(
           config.walletConf,
           config.dlcConf
         )
@@ -351,8 +346,7 @@ object BitcoinSWalletTest extends WalletLogger {
       walletWithCallback = Wallet(
         nodeApi =
           SyncUtil.getNodeApiWalletCallback(bitcoind, walletCallbackP.future),
-        chainQueryApi = bitcoind,
-        feeRateApi = new RandomFeeProvider
+        chainQueryApi = bitcoind
       )(wallet.walletConfig)
       // complete the walletCallbackP so we can handle the callbacks when they are
       // called without hanging forever.
@@ -523,23 +517,13 @@ object BitcoinSWalletTest extends WalletLogger {
       walletWithBitcoind: WalletWithBitcoind[_]
   )(implicit ec: ExecutionContext): Future[Unit] = {
     for {
-      _ <- destroyWallet(walletWithBitcoind.wallet)
       _ <- destroyWalletAppConfig(walletWithBitcoind.walletConfig)
     } yield ()
   }
 
-  def destroyWallet(
-      wallet: WalletApi
-  )(implicit ec: ExecutionContext): Future[Unit] = {
-    for {
-      _ <- wallet.stop()
-    } yield ()
-  }
-
   def destroyDLCWallet(wallet: DLCWallet): Future[Unit] = {
     import wallet.ec
     for {
-      _ <- destroyWallet(wallet)
       _ <- destroyWalletAppConfig(wallet.walletConfig)
       _ <- wallet.dlcConfig.stop()
     } yield ()
diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/TrezorAddressTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/TrezorAddressTest.scala
index 33cd8f18d2..1284e8061e 100644
--- a/wallet-test/src/test/scala/org/bitcoins/wallet/TrezorAddressTest.scala
+++ b/wallet-test/src/test/scala/org/bitcoins/wallet/TrezorAddressTest.scala
@@ -6,9 +6,7 @@ import org.bitcoins.core.crypto.{ExtPublicKey, MnemonicCode}
 import org.bitcoins.core.hd._
 import org.bitcoins.core.protocol.BitcoinAddress
 import org.bitcoins.core.util.FutureUtil
-import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
 import org.bitcoins.core.wallet.keymanagement.KeyManagerParams
-import org.bitcoins.feeprovider.ConstantFeeRateProvider
 import org.bitcoins.testkit.BitcoinSTestAppConfig
 import org.bitcoins.testkit.chain.MockChainQueryApi
 import org.bitcoins.testkit.fixtures.EmptyFixture
@@ -153,8 +151,7 @@ class TrezorAddressTest extends BitcoinSWalletTest with EmptyFixture {
       wallet =
         Wallet(
           MockNodeApi,
-          MockChainQueryApi,
-          ConstantFeeRateProvider(SatoshisPerVirtualByte.one)
+          MockChainQueryApi
         )(config)
       init <- Wallet.initialize(
         wallet = wallet,
diff --git a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala
index 71518fd80a..dd80e01727 100644
--- a/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala
+++ b/wallet-test/src/test/scala/org/bitcoins/wallet/WalletUnitTest.scala
@@ -204,7 +204,7 @@ class WalletUnitTest extends BitcoinSWalletTest {
       val walletDiffKeyManagerF: Future[Wallet] = for {
         _ <- startedF
       } yield {
-        Wallet(wallet.nodeApi, wallet.chainQueryApi, wallet.feeRateApi)(
+        Wallet(wallet.nodeApi, wallet.chainQueryApi)(
           uniqueEntropyWalletConfig
         )
       }
diff --git a/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala b/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala
index 4f2839dd14..53a845c551 100644
--- a/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala
+++ b/wallet/src/main/scala/org/bitcoins/wallet/Wallet.scala
@@ -34,10 +34,10 @@ import scala.concurrent.{ExecutionContext, Future}
 import scala.util.control.NonFatal
 
 abstract class Wallet extends NeutrinoHDWalletApi with WalletLogger {
-
   def keyManager: BIP39KeyManager = {
     walletConfig.kmConf.toBip39KeyManager
   }
+  def feeRateApi: FeeRateApi = walletConfig.feeRateApi
   implicit val walletConfig: WalletAppConfig
 
   implicit val system: ActorSystem = walletConfig.system
@@ -137,44 +137,6 @@ abstract class Wallet extends NeutrinoHDWalletApi with WalletLogger {
 
   def walletCallbacks: WalletCallbacks = walletConfig.callBacks
 
-  private def checkRootAccount: Future[Unit] = {
-    val coinType = HDUtil.getCoinType(keyManager.kmParams.network)
-    val coin =
-      HDCoin(purpose = keyManager.kmParams.purpose, coinType = coinType)
-    val account = HDAccount(coin = coin, index = 0)
-    // safe since we're deriving from a priv
-    val xpub = keyManager.deriveXPub(account).get
-
-    accountDAO.read((account.coin, account.index)).flatMap {
-      case Some(account) =>
-        if (account.xpub != xpub) {
-          val errorMsg =
-            s"Divergent xpubs for account=$account. Existing database xpub=${account.xpub}, key manager's xpub=$xpub. " +
-              s"It is possible we have a different key manager being used than expected, key manager=${keyManager.kmParams.seedPath.toAbsolutePath.toString}"
-          Future.failed(new RuntimeException(errorMsg))
-        } else {
-          Future.unit
-        }
-      case None =>
-        val errorMsg = s"Missing root xpub for account $account in database"
-        Future.failed(new RuntimeException(errorMsg))
-    }
-  }
-
-  override def start(): Future[Wallet] = {
-    logger.info("Starting Wallet")
-
-    checkRootAccount.map { _ =>
-      walletConfig.startRebroadcastTxsScheduler(this)
-      startFeeRateCallbackScheduler()
-      this
-    }
-  }
-
-  override def stop(): Future[Wallet] = {
-    Future.successful(this)
-  }
-
   override def getNewAddress(): Future[BitcoinAddress] = {
     addressHandling.getNewAddress()
   }
@@ -353,18 +315,16 @@ object Wallet extends WalletLogger {
 
   private case class WalletImpl(
       nodeApi: NodeApi,
-      chainQueryApi: ChainQueryApi,
-      feeRateApi: FeeRateApi
+      chainQueryApi: ChainQueryApi
   )(implicit
       val walletConfig: WalletAppConfig
   ) extends Wallet
 
   def apply(
       nodeApi: NodeApi,
-      chainQueryApi: ChainQueryApi,
-      feeRateApi: FeeRateApi
+      chainQueryApi: ChainQueryApi
   )(implicit config: WalletAppConfig): Wallet = {
-    WalletImpl(nodeApi, chainQueryApi, feeRateApi)
+    WalletImpl(nodeApi, chainQueryApi)
   }
 
   /** Creates the master xpub for the key manager in the database
diff --git a/wallet/src/main/scala/org/bitcoins/wallet/WalletHolder.scala b/wallet/src/main/scala/org/bitcoins/wallet/WalletHolder.scala
index acb696b52d..5f5e5acba3 100644
--- a/wallet/src/main/scala/org/bitcoins/wallet/WalletHolder.scala
+++ b/wallet/src/main/scala/org/bitcoins/wallet/WalletHolder.scala
@@ -70,26 +70,8 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit
       newWallet: DLCNeutrinoHDWalletApi
   ): Future[DLCNeutrinoHDWalletApi] =
     synchronized {
-      val oldWalletOpt = walletOpt
-      walletOpt = None
-      val res = for {
-        _ <- {
-          oldWalletOpt match {
-            case Some(oldWallet) => oldWallet.stop()
-            case None            => Future.unit
-          }
-        }
-        _ <- newWallet.start()
-      } yield {
-        synchronized {
-          walletOpt = Some(newWallet)
-          newWallet
-        }
-      }
-
-      res.failed.foreach(ex => logger.error("Cannot start wallet ", ex))
-
-      res
+      walletOpt = Some(newWallet)
+      Future.successful(newWallet)
     }
 
   private def delegate[T]
@@ -116,19 +98,6 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit
   override lazy val feeRateApi: FeeRateApi = wallet.feeRateApi
   override lazy val creationTime: Instant = wallet.creationTime
 
-  override def start(): Future[WalletApi] = delegate(_.start())
-
-  override def stop(): Future[WalletApi] = {
-    val res = delegate(_.stop())
-
-    res.onComplete { _ =>
-      synchronized {
-        walletOpt = None
-      }
-    }
-
-    res
-  }
   override def getConfirmedBalance(): Future[CurrencyUnit] = delegate(
     _.getConfirmedBalance()
   )
diff --git a/wallet/src/main/scala/org/bitcoins/wallet/config/WalletAppConfig.scala b/wallet/src/main/scala/org/bitcoins/wallet/config/WalletAppConfig.scala
index e8bc9bf2fd..1271d6bf0d 100644
--- a/wallet/src/main/scala/org/bitcoins/wallet/config/WalletAppConfig.scala
+++ b/wallet/src/main/scala/org/bitcoins/wallet/config/WalletAppConfig.scala
@@ -8,14 +8,16 @@ import org.bitcoins.core.api.CallbackConfig
 import org.bitcoins.core.api.chain.ChainQueryApi
 import org.bitcoins.core.api.feeprovider.FeeRateApi
 import org.bitcoins.core.api.node.NodeApi
-import org.bitcoins.core.hd._
+import org.bitcoins.core.hd.*
 import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
-import org.bitcoins.core.wallet.keymanagement._
+import org.bitcoins.core.wallet.keymanagement.*
 import org.bitcoins.crypto.AesPassword
 import org.bitcoins.db.DatabaseDriver.{PostgreSQL, SQLite}
-import org.bitcoins.db._
+import org.bitcoins.db.*
 import org.bitcoins.db.models.MasterXPubDAO
 import org.bitcoins.db.util.{DBMasterXPubApi, MasterXPubUtil}
+import org.bitcoins.feeprovider.{FeeProviderFactory, MempoolSpaceProvider}
+import org.bitcoins.feeprovider.MempoolSpaceTarget.HourFeeTarget
 import org.bitcoins.keymanager.config.KeyManagerAppConfig
 import org.bitcoins.tor.config.TorAppConfig
 import org.bitcoins.wallet.callback.{
@@ -29,7 +31,7 @@ import org.bitcoins.wallet.{Wallet, WalletLogger}
 
 import java.nio.file.{Files, Path, Paths}
 import java.time.Instant
-import java.util.concurrent._
+import java.util.concurrent.*
 import scala.concurrent.duration.{
   Duration,
   DurationInt,
@@ -37,6 +39,7 @@ import scala.concurrent.duration.{
   FiniteDuration
 }
 import scala.concurrent.{Await, ExecutionContext, Future}
+import scala.util.control.NonFatal
 
 /** Configuration for the Bitcoin-S wallet
   * @param directory
@@ -57,6 +60,19 @@ case class WalletAppConfig(
 
   implicit override val ec: ExecutionContext = system.dispatcher
 
+  private val defaultApi =
+    MempoolSpaceProvider(HourFeeTarget, network, torConf.socks5ProxyParams)
+
+  lazy val feeRateApi: FeeRateApi = {
+    FeeProviderFactory.getFeeProviderOrElse(
+      defaultApi,
+      feeProviderNameOpt,
+      feeProviderTargetOpt,
+      torConf.socks5ProxyParams,
+      network
+    )
+  }
+
   override protected[bitcoins] def moduleName: String =
     WalletAppConfig.moduleName
 
@@ -65,7 +81,7 @@ case class WalletAppConfig(
   override protected[bitcoins] def newConfigOfType(
       configs: Vector[Config]
   ): WalletAppConfig =
-    WalletAppConfig(baseDatadir, configs)
+    WalletAppConfig(baseDatadir, configs, kmConfOpt)
 
   override def appConfig: WalletAppConfig = this
 
@@ -216,6 +232,8 @@ case class WalletAppConfig(
       Files.createDirectories(datadir)
     }
 
+    startFeeRateCallbackScheduler()
+
     for {
       _ <- super.start()
       _ <- kmConf.start()
@@ -257,6 +275,7 @@ case class WalletAppConfig(
     stopCallbacksF.flatMap { _ =>
       clearCallbacks()
       stopRebroadcastTxsScheduler()
+      stopFeeRateScheduler()
       // this eagerly shuts down all scheduled tasks on the scheduler
       // in the future, we should actually cancel all things that are scheduled
       // manually, and then shutdown the scheduler
@@ -325,41 +344,41 @@ case class WalletAppConfig(
   /** Creates a wallet based on this [[WalletAppConfig]] */
   def createHDWallet(
       nodeApi: NodeApi,
-      chainQueryApi: ChainQueryApi,
-      feeRateApi: FeeRateApi
+      chainQueryApi: ChainQueryApi
   )(implicit system: ActorSystem): Future[Wallet] = {
     WalletAppConfig.createHDWallet(
       nodeApi = nodeApi,
-      chainQueryApi = chainQueryApi,
-      feeRateApi = feeRateApi
+      chainQueryApi = chainQueryApi
     )(this, system)
   }
 
   private[this] var rebroadcastTransactionsCancelOpt
-      : Option[ScheduledFuture[_]] = None
+      : Option[ScheduledFuture[?]] = None
+  private var feeRateCancelOpt: Option[ScheduledFuture[?]] = None
 
   /** Starts the wallet's rebroadcast transaction scheduler */
-  def startRebroadcastTxsScheduler(wallet: Wallet): Unit = synchronized {
-    rebroadcastTransactionsCancelOpt match {
-      case Some(_) =>
-        // already scheduled, do nothing
-        ()
-      case None =>
-        logger.info(s"Starting wallet rebroadcast task")
+  private def startRebroadcastTxsScheduler(wallet: Wallet): Unit =
+    synchronized {
+      rebroadcastTransactionsCancelOpt match {
+        case Some(_) =>
+          // already scheduled, do nothing
+          ()
+        case None =>
+          logger.info(s"Starting wallet rebroadcast task")
 
-        val interval = rebroadcastFrequency.toSeconds
-        val initDelay = interval
-        val future =
-          scheduler.scheduleAtFixedRate(
-            RebroadcastTransactionsRunnable(wallet),
-            initDelay,
-            interval,
-            TimeUnit.SECONDS
-          )
-        rebroadcastTransactionsCancelOpt = Some(future)
-        ()
+          val interval = rebroadcastFrequency.toSeconds
+          val initDelay = interval
+          val future =
+            scheduler.scheduleAtFixedRate(
+              RebroadcastTransactionsRunnable(wallet),
+              initDelay,
+              interval,
+              TimeUnit.SECONDS
+            )
+          rebroadcastTransactionsCancelOpt = Some(future)
+          ()
+      }
     }
-  }
 
   /** Kills the wallet's rebroadcast transaction scheduler */
   def stopRebroadcastTxsScheduler(): Unit = synchronized {
@@ -368,20 +387,60 @@ case class WalletAppConfig(
         if (!cancel.isCancelled) {
           logger.info(s"Stopping wallet rebroadcast task")
           cancel.cancel(true)
-        } else {
-          rebroadcastTransactionsCancelOpt = None
         }
+        rebroadcastTransactionsCancelOpt = None
         ()
       case None => ()
     }
   }
 
+  private def stopFeeRateScheduler(): Unit = synchronized {
+    feeRateCancelOpt match {
+      case Some(cancel) =>
+        if (!cancel.isCancelled) {
+          cancel.cancel(true)
+        }
+        feeRateCancelOpt = None
+      case None =>
+        ()
+    }
+  }
+
   /** The creation time of the mnemonic seed If we cannot decrypt the seed
     * because of invalid passwords, we return None
     */
   def creationTime: Instant = {
     kmConf.creationTime
   }
+
+  private def startFeeRateCallbackScheduler(): Unit = {
+    val feeRateChangedRunnable = new Runnable {
+      override def run(): Unit = {
+        feeRateApi
+          .getFeeRate()
+          .map(feeRate => Some(feeRate))
+          .recover { case NonFatal(_) =>
+            // logger.error("Cannot get fee rate ", ex)
+            None
+          }
+          .foreach { feeRateOpt =>
+            callBacks.executeOnFeeRateChanged(
+              feeRateOpt.getOrElse(SatoshisPerVirtualByte.negativeOne)
+            )
+          }
+        ()
+      }
+    }
+
+    val cancel: ScheduledFuture[?] = scheduler.scheduleAtFixedRate(
+      feeRateChangedRunnable,
+      feeRatePollDelay.toSeconds,
+      feeRatePollInterval.toSeconds,
+      TimeUnit.SECONDS
+    )
+    feeRateCancelOpt = Some(cancel)
+
+  }
 }
 
 object WalletAppConfig
@@ -404,25 +463,24 @@ object WalletAppConfig
   /** Creates a wallet based on the given [[WalletAppConfig]] */
   def createHDWallet(
       nodeApi: NodeApi,
-      chainQueryApi: ChainQueryApi,
-      feeRateApi: FeeRateApi
+      chainQueryApi: ChainQueryApi
   )(implicit
       walletConf: WalletAppConfig,
       system: ActorSystem
   ): Future[Wallet] = {
     import system.dispatcher
-    walletConf.hasWallet().flatMap { walletExists =>
+    val walletF = walletConf.hasWallet().flatMap { walletExists =>
       val bip39PasswordOpt = walletConf.bip39PasswordOpt
 
       if (walletExists) {
         logger.info(s"Using pre-existing wallet")
         val wallet =
-          Wallet(nodeApi, chainQueryApi, feeRateApi)
+          Wallet(nodeApi, chainQueryApi)
         Future.successful(wallet)
       } else {
         logger.info(s"Creating new wallet")
         val unInitializedWallet =
-          Wallet(nodeApi, chainQueryApi, feeRateApi)
+          Wallet(nodeApi, chainQueryApi)
 
         Wallet.initialize(
           wallet = unInitializedWallet,
@@ -431,6 +489,11 @@ object WalletAppConfig
         )
       }
     }
+
+    walletF.map { wallet =>
+      walletConf.startRebroadcastTxsScheduler(wallet)
+      wallet
+    }
   }
 
   case class RebroadcastTransactionsRunnable(wallet: Wallet)(implicit
diff --git a/wallet/src/main/scala/org/bitcoins/wallet/internal/AccountHandling.scala b/wallet/src/main/scala/org/bitcoins/wallet/internal/AccountHandling.scala
index cc430a134e..c6f98e3593 100644
--- a/wallet/src/main/scala/org/bitcoins/wallet/internal/AccountHandling.scala
+++ b/wallet/src/main/scala/org/bitcoins/wallet/internal/AccountHandling.scala
@@ -18,6 +18,7 @@ import org.bitcoins.core.protocol.blockchain.{
   TestNetChainParams
 }
 import org.bitcoins.core.protocol.script.ScriptPubKey
+import org.bitcoins.core.util.HDUtil
 import org.bitcoins.db.SafeDatabase
 import org.bitcoins.wallet.callback.WalletCallbacks
 import org.bitcoins.wallet.config.WalletAppConfig
@@ -304,7 +305,7 @@ case class AccountHandling(
 
   override def getNewAddress(account: AccountDb): Future[BitcoinAddress] = {
     val action = getNewAddressAction(account)
-    safeDatabase.run(action)
+    checkRootAccount.flatMap(_ => safeDatabase.run(action))
   }
 
   def getNewAddressAction(account: AccountDb): DBIOAction[
@@ -477,7 +478,7 @@ case class AccountHandling(
     }
   }
 
-  protected def getLastAccountOpt(
+  private def getLastAccountOpt(
       purpose: HDPurpose
   ): Future[Option[AccountDb]] = {
     accountDAO
@@ -490,6 +491,30 @@ case class AccountHandling(
       .map(_.lastOption)
   }
 
+  private def checkRootAccount: Future[Unit] = {
+    val coinType = HDUtil.getCoinType(keyManager.kmParams.network)
+    val coin =
+      HDCoin(purpose = keyManager.kmParams.purpose, coinType = coinType)
+    val account = HDAccount(coin = coin, index = 0)
+    // safe since we're deriving from a priv
+    val xpub = keyManager.deriveXPub(account).get
+
+    accountDAO.read((account.coin, account.index)).flatMap {
+      case Some(account) =>
+        if (account.xpub != xpub) {
+          val errorMsg =
+            s"Divergent xpubs for account=$account. Existing database xpub=${account.xpub}, key manager's xpub=$xpub. " +
+              s"It is possible we have a different key manager being used than expected, key manager=${keyManager.kmParams.seedPath.toAbsolutePath.toString}"
+          Future.failed(new RuntimeException(errorMsg))
+        } else {
+          Future.unit
+        }
+      case None =>
+        val errorMsg = s"Missing root xpub for account $account in database"
+        Future.failed(new RuntimeException(errorMsg))
+    }
+  }
+
   /** The default HD coin for this wallet, read from config */
   protected[wallet] lazy val DEFAULT_HD_COIN: HDCoin = {
     val coinType = DEFAULT_HD_COIN_TYPE
