Repository: lightningnetwork/lnd
Pull request #3653 (2019-10-31 02:12:34)

chainfees: create new chainfees package extracting fees from lnwallet
In this commit, we create a new chainfees package, that houses all fee
related functionality used within the codebase. The creation of this new
package furthers our long-term goal of extracting functionality from the
bloated `lnwallet` package into new distinct packages. Additionally,
this new packages resolves a class of import cycle that could arise if a
new package that was imported by something in `lnwallet` wanted to use
the existing fee related functions in the prior `lnwallet` package.


Patch:
diff --git a/breacharbiter.go b/breacharbiter.go
index 3bb334537..3706f3bd4 100644
--- a/breacharbiter.go
+++ b/breacharbiter.go
@@ -21,6 +21,7 @@ import (
 	"github.com/lightningnetwork/lnd/htlcswitch"
 	"github.com/lightningnetwork/lnd/input"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 )
 
 var (
@@ -78,7 +79,7 @@ type BreachConfig struct {
 	// Estimator is used by the breach arbiter to determine an appropriate
 	// fee level when generating, signing, and broadcasting sweep
 	// transactions.
-	Estimator lnwallet.FeeEstimator
+	Estimator chainfee.Estimator
 
 	// GenSweepScript generates the receiving scripts for swept outputs.
 	GenSweepScript func() ([]byte, error)
diff --git a/chainregistry.go b/chainregistry.go
index 7be92afd9..ee07caaa4 100644
--- a/chainregistry.go
+++ b/chainregistry.go
@@ -30,6 +30,7 @@ import (
 	"github.com/lightningnetwork/lnd/keychain"
 	"github.com/lightningnetwork/lnd/lnwallet"
 	"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/routing/chainview"
 )
@@ -55,11 +56,11 @@ const (
 
 	// defaultBitcoinStaticFeePerKW is the fee rate of 50 sat/vbyte
 	// expressed in sat/kw.
-	defaultBitcoinStaticFeePerKW = lnwallet.SatPerKWeight(12500)
+	defaultBitcoinStaticFeePerKW = chainfee.SatPerKWeight(12500)
 
 	// defaultLitecoinStaticFeePerKW is the fee rate of 200 sat/vbyte
 	// expressed in sat/kw.
-	defaultLitecoinStaticFeePerKW = lnwallet.SatPerKWeight(50000)
+	defaultLitecoinStaticFeePerKW = chainfee.SatPerKWeight(50000)
 
 	// btcToLtcConversionRate is a fixed ratio used in order to scale up
 	// payments when running on the Litecoin chain.
@@ -112,7 +113,7 @@ func (c chainCode) String() string {
 type chainControl struct {
 	chainIO lnwallet.BlockChainIO
 
-	feeEstimator lnwallet.FeeEstimator
+	feeEstimator chainfee.Estimator
 
 	signer input.Signer
 
@@ -161,7 +162,7 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
 			FeeRate:       cfg.Bitcoin.FeeRate,
 			TimeLockDelta: cfg.Bitcoin.TimeLockDelta,
 		}
-		cc.feeEstimator = lnwallet.NewStaticFeeEstimator(
+		cc.feeEstimator = chainfee.NewStaticEstimator(
 			defaultBitcoinStaticFeePerKW, 0,
 		)
 	case litecoinChain:
@@ -171,7 +172,7 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
 			FeeRate:       cfg.Litecoin.FeeRate,
 			TimeLockDelta: cfg.Litecoin.TimeLockDelta,
 		}
-		cc.feeEstimator = lnwallet.NewStaticFeeEstimator(
+		cc.feeEstimator = chainfee.NewStaticEstimator(
 			defaultLitecoinStaticFeePerKW, 0,
 		)
 	default:
@@ -219,8 +220,8 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
 		if cfg.NeutrinoMode.FeeURL != "" {
 			ltndLog.Infof("Using API fee estimator!")
 
-			estimator := lnwallet.NewWebAPIFeeEstimator(
-				lnwallet.SparseConfFeeSource{
+			estimator := chainfee.NewWebAPIEstimator(
+				chainfee.SparseConfFeeSource{
 					URL: cfg.NeutrinoMode.FeeURL,
 				},
 				defaultBitcoinStaticFeePerKW,
@@ -323,8 +324,8 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
 			// if we're using bitcoind as a backend, then we can
 			// use live fee estimates, rather than a statically
 			// coded value.
-			fallBackFeeRate := lnwallet.SatPerKVByte(25 * 1000)
-			cc.feeEstimator, err = lnwallet.NewBitcoindFeeEstimator(
+			fallBackFeeRate := chainfee.SatPerKVByte(25 * 1000)
+			cc.feeEstimator, err = chainfee.NewBitcoindEstimator(
 				*rpcConfig, fallBackFeeRate.FeePerKWeight(),
 			)
 			if err != nil {
@@ -340,8 +341,8 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
 			// if we're using litecoind as a backend, then we can
 			// use live fee estimates, rather than a statically
 			// coded value.
-			fallBackFeeRate := lnwallet.SatPerKVByte(25 * 1000)
-			cc.feeEstimator, err = lnwallet.NewBitcoindFeeEstimator(
+			fallBackFeeRate := chainfee.SatPerKVByte(25 * 1000)
+			cc.feeEstimator, err = chainfee.NewBitcoindEstimator(
 				*rpcConfig, fallBackFeeRate.FeePerKWeight(),
 			)
 			if err != nil {
@@ -445,8 +446,8 @@ func newChainControlFromConfig(cfg *config, chanDB *channeldb.DB,
 			// if we're using btcd as a backend, then we can use
 			// live fee estimates, rather than a statically coded
 			// value.
-			fallBackFeeRate := lnwallet.SatPerKVByte(25 * 1000)
-			cc.feeEstimator, err = lnwallet.NewBtcdFeeEstimator(
+			fallBackFeeRate := chainfee.SatPerKVByte(25 * 1000)
+			cc.feeEstimator, err = chainfee.NewBtcdEstimator(
 				*rpcConfig, fallBackFeeRate.FeePerKWeight(),
 			)
 			if err != nil {
diff --git a/chancloser.go b/chancloser.go
index 3c015a5b5..12bd75605 100644
--- a/chancloser.go
+++ b/chancloser.go
@@ -9,6 +9,7 @@ import (
 	"github.com/davecgh/go-spew/spew"
 	"github.com/lightningnetwork/lnd/htlcswitch"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 )
 
@@ -150,7 +151,7 @@ type channelCloser struct {
 // passed configuration, and delivery+fee preference. The final argument should
 // only be populated iff, we're the initiator of this closing request.
 func newChannelCloser(cfg chanCloseCfg, deliveryScript []byte,
-	idealFeePerKw lnwallet.SatPerKWeight, negotiationHeight uint32,
+	idealFeePerKw chainfee.SatPerKWeight, negotiationHeight uint32,
 	closeReq *htlcswitch.ChanClose) *channelCloser {
 
 	// Given the target fee-per-kw, we'll compute what our ideal _total_
diff --git a/contractcourt/chain_arbitrator.go b/contractcourt/chain_arbitrator.go
index 96759f7ec..098bc5f3e 100644
--- a/contractcourt/chain_arbitrator.go
+++ b/contractcourt/chain_arbitrator.go
@@ -13,6 +13,7 @@ import (
 	"github.com/lightningnetwork/lnd/channeldb"
 	"github.com/lightningnetwork/lnd/input"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/sweep"
 )
@@ -131,7 +132,7 @@ type ChainArbitratorConfig struct {
 	Signer input.Signer
 
 	// FeeEstimator will be used to return fee estimates.
-	FeeEstimator lnwallet.FeeEstimator
+	FeeEstimator chainfee.Estimator
 
 	// ChainIO allows us to query the state of the current main chain.
 	ChainIO lnwallet.BlockChainIO
diff --git a/fundingmanager.go b/fundingmanager.go
index c18df5ab5..769c5a5ec 100644
--- a/fundingmanager.go
+++ b/fundingmanager.go
@@ -24,6 +24,7 @@ import (
 	"github.com/lightningnetwork/lnd/lnpeer"
 	"github.com/lightningnetwork/lnd/lnrpc"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/routing"
 	"golang.org/x/crypto/salsa20"
@@ -230,7 +231,7 @@ type fundingConfig struct {
 
 	// FeeEstimator calculates appropriate fee rates based on historical
 	// transaction information.
-	FeeEstimator lnwallet.FeeEstimator
+	FeeEstimator chainfee.Estimator
 
 	// Notifier is used by the FundingManager to determine when the
 	// channel's funding transaction has been confirmed on the blockchain
@@ -1218,7 +1219,7 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
 		NodeAddr:         fmsg.peer.Address(),
 		LocalFundingAmt:  0,
 		RemoteFundingAmt: amt,
-		CommitFeePerKw:   lnwallet.SatPerKWeight(msg.FeePerKiloWeight),
+		CommitFeePerKw:   chainfee.SatPerKWeight(msg.FeePerKiloWeight),
 		FundingFeePerKw:  0,
 		PushMSat:         msg.PushAmount,
 		Flags:            msg.ChannelFlags,
diff --git a/htlcswitch/link.go b/htlcswitch/link.go
index c0b62633c..4f0591865 100644
--- a/htlcswitch/link.go
+++ b/htlcswitch/link.go
@@ -24,6 +24,7 @@ import (
 	"github.com/lightningnetwork/lnd/lnpeer"
 	"github.com/lightningnetwork/lnd/lntypes"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/queue"
 	"github.com/lightningnetwork/lnd/ticker"
@@ -199,7 +200,7 @@ type ChannelLinkConfig struct {
 	// FeeEstimator is an instance of a live fee estimator which will be
 	// used to dynamically regulate the current fee of the commitment
 	// transaction to ensure timely confirmation.
-	FeeEstimator lnwallet.FeeEstimator
+	FeeEstimator chainfee.Estimator
 
 	// hodl.Mask is a bitvector composed of hodl.Flags, specifying breakpoints
 	// for HTLC forwarding internal to the switch.
@@ -570,7 +571,7 @@ func (l *channelLink) markReestablished() {
 // chain in a timely manner. The returned value is expressed in fee-per-kw, as
 // this is the native rate used when computing the fee for commitment
 // transactions, and the second-level HTLC transactions.
-func (l *channelLink) sampleNetworkFee() (lnwallet.SatPerKWeight, error) {
+func (l *channelLink) sampleNetworkFee() (chainfee.SatPerKWeight, error) {
 	// We'll first query for the sat/kw recommended to be confirmed within 3
 	// blocks.
 	feePerKw, err := l.cfg.FeeEstimator.EstimateFeePerKW(3)
@@ -587,7 +588,7 @@ func (l *channelLink) sampleNetworkFee() (lnwallet.SatPerKWeight, error) {
 // shouldAdjustCommitFee returns true if we should update our commitment fee to
 // match that of the network fee. We'll only update our commitment fee if the
 // network fee is +/- 10% to our network fee.
-func shouldAdjustCommitFee(netFee, chanFee lnwallet.SatPerKWeight) bool {
+func shouldAdjustCommitFee(netFee, chanFee chainfee.SatPerKWeight) bool {
 	switch {
 	// If the network fee is greater than the commitment fee, then we'll
 	// switch to it if it's at least 10% greater than the commit fee.
@@ -1061,7 +1062,7 @@ out:
 			// fee rate to our max fee allocation.
 			commitFee := l.channel.CommitFeeRate()
 			maxFee := l.channel.MaxFeeRate(l.cfg.MaxFeeAllocation)
-			newCommitFee := lnwallet.SatPerKWeight(
+			newCommitFee := chainfee.SatPerKWeight(
 				math.Min(float64(netFee), float64(maxFee)),
 			)
 			if !shouldAdjustCommitFee(newCommitFee, commitFee) {
@@ -1894,7 +1895,7 @@ func (l *channelLink) handleUpstreamMsg(msg lnwire.Message) {
 	case *lnwire.UpdateFee:
 		// We received fee update from peer. If we are the initiator we
 		// will fail the channel, if not we will apply the update.
-		fee := lnwallet.SatPerKWeight(msg.FeePerKw)
+		fee := chainfee.SatPerKWeight(msg.FeePerKw)
 		if err := l.channel.ReceiveUpdateFee(fee); err != nil {
 			l.fail(LinkFailureError{code: ErrInvalidUpdate},
 				"error receiving fee update: %v", err)
@@ -2394,7 +2395,7 @@ func (l *channelLink) HandleChannelUpdate(message lnwire.Message) {
 
 // updateChannelFee updates the commitment fee-per-kw on this channel by
 // committing to an update_fee message.
-func (l *channelLink) updateChannelFee(feePerKw lnwallet.SatPerKWeight) error {
+func (l *channelLink) updateChannelFee(feePerKw chainfee.SatPerKWeight) error {
 
 	l.log.Infof("updating commit fee to %v sat/kw", feePerKw)
 
diff --git a/htlcswitch/mock.go b/htlcswitch/mock.go
index 53d95720c..69bbec900 100644
--- a/htlcswitch/mock.go
+++ b/htlcswitch/mock.go
@@ -28,7 +28,7 @@ import (
 	"github.com/lightningnetwork/lnd/invoices"
 	"github.com/lightningnetwork/lnd/lnpeer"
 	"github.com/lightningnetwork/lnd/lntypes"
-	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/ticker"
 )
@@ -70,13 +70,13 @@ func (m *mockPreimageCache) SubscribeUpdates() *contractcourt.WitnessSubscriptio
 }
 
 type mockFeeEstimator struct {
-	byteFeeIn chan lnwallet.SatPerKWeight
+	byteFeeIn chan chainfee.SatPerKWeight
 
 	quit chan struct{}
 }
 
 func (m *mockFeeEstimator) EstimateFeePerKW(
-	numBlocks uint32) (lnwallet.SatPerKWeight, error) {
+	numBlocks uint32) (chainfee.SatPerKWeight, error) {
 
 	select {
 	case feeRate := <-m.byteFeeIn:
@@ -86,7 +86,7 @@ func (m *mockFeeEstimator) EstimateFeePerKW(
 	}
 }
 
-func (m *mockFeeEstimator) RelayFeePerKW() lnwallet.SatPerKWeight {
+func (m *mockFeeEstimator) RelayFeePerKW() chainfee.SatPerKWeight {
 	return 1e3
 }
 
@@ -98,7 +98,7 @@ func (m *mockFeeEstimator) Stop() error {
 	return nil
 }
 
-var _ lnwallet.FeeEstimator = (*mockFeeEstimator)(nil)
+var _ chainfee.Estimator = (*mockFeeEstimator)(nil)
 
 type mockForwardingLog struct {
 	sync.Mutex
diff --git a/htlcswitch/switch.go b/htlcswitch/switch.go
index b135e1fd5..aa040f4ae 100644
--- a/htlcswitch/switch.go
+++ b/htlcswitch/switch.go
@@ -18,6 +18,7 @@ import (
 	"github.com/lightningnetwork/lnd/htlcswitch/hop"
 	"github.com/lightningnetwork/lnd/lntypes"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/ticker"
 )
@@ -102,7 +103,7 @@ type ChanClose struct {
 	// This value is only utilized if the closure type is CloseRegular.
 	// This will be the starting offered fee when the fee negotiation
 	// process for the cooperative closure transaction kicks off.
-	TargetFeePerKw lnwallet.SatPerKWeight
+	TargetFeePerKw chainfee.SatPerKWeight
 
 	// Updates is used by request creator to receive the notifications about
 	// execution of the close channel request.
@@ -1368,7 +1369,7 @@ func (s *Switch) teardownCircuit(pkt *htlcPacket) error {
 // then the last parameter should be the ideal fee-per-kw that will be used as
 // a starting point for close negotiation.
 func (s *Switch) CloseLink(chanPoint *wire.OutPoint, closeType ChannelCloseType,
-	targetFeePerKw lnwallet.SatPerKWeight) (chan interface{},
+	targetFeePerKw chainfee.SatPerKWeight) (chan interface{},
 	chan error) {
 
 	// TODO(roasbeef) abstract out the close updates.
diff --git a/lnrpc/walletrpc/config_active.go b/lnrpc/walletrpc/config_active.go
index 9804bc119..aada57dcd 100644
--- a/lnrpc/walletrpc/config_active.go
+++ b/lnrpc/walletrpc/config_active.go
@@ -5,6 +5,7 @@ package walletrpc
 import (
 	"github.com/lightningnetwork/lnd/keychain"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/macaroons"
 	"github.com/lightningnetwork/lnd/sweep"
 )
@@ -30,7 +31,7 @@ type Config struct {
 
 	// FeeEstimator is an instance of the primary fee estimator instance
 	// the WalletKit will use to respond to fee estimation requests.
-	FeeEstimator lnwallet.FeeEstimator
+	FeeEstimator chainfee.Estimator
 
 	// Wallet is the primary wallet that the WalletKit will use to proxy
 	// any relevant requests to.
diff --git a/lnrpc/walletrpc/walletkit_server.go b/lnrpc/walletrpc/walletkit_server.go
index 023782f62..dbbd898da 100644
--- a/lnrpc/walletrpc/walletkit_server.go
+++ b/lnrpc/walletrpc/walletkit_server.go
@@ -19,6 +19,7 @@ import (
 	"github.com/lightningnetwork/lnd/lnrpc"
 	"github.com/lightningnetwork/lnd/lnrpc/signrpc"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/sweep"
 	"google.golang.org/grpc"
 	"gopkg.in/macaroon-bakery.v2/bakery"
@@ -303,7 +304,7 @@ func (w *WalletKit) SendOutputs(ctx context.Context,
 	// Now that we have the outputs mapped, we can request that the wallet
 	// attempt to create this transaction.
 	tx, err := w.cfg.Wallet.SendOutputs(
-		outputsToCreate, lnwallet.SatPerKWeight(req.SatPerKw),
+		outputsToCreate, chainfee.SatPerKWeight(req.SatPerKw),
 	)
 	if err != nil {
 		return nil, err
@@ -468,7 +469,7 @@ func (w *WalletKit) BumpFee(ctx context.Context,
 	}
 
 	// Construct the request's fee preference.
-	satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
+	satPerKw := chainfee.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
 	feePreference := sweep.FeePreference{
 		ConfTarget: uint32(in.TargetConf),
 		FeeRate:    satPerKw,
diff --git a/lnwallet/btcwallet/btcwallet.go b/lnwallet/btcwallet/btcwallet.go
index 84945c86a..3e51605a5 100644
--- a/lnwallet/btcwallet/btcwallet.go
+++ b/lnwallet/btcwallet/btcwallet.go
@@ -21,6 +21,7 @@ import (
 	"github.com/btcsuite/btcwallet/walletdb"
 	"github.com/lightningnetwork/lnd/keychain"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 )
 
 const (
@@ -289,7 +290,7 @@ func (b *BtcWallet) IsOurAddress(a btcutil.Address) bool {
 //
 // This is a part of the WalletController interface.
 func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
-	feeRate lnwallet.SatPerKWeight) (*wire.MsgTx, error) {
+	feeRate chainfee.SatPerKWeight) (*wire.MsgTx, error) {
 
 	// Convert our fee rate from sat/kw to sat/kb since it's required by
 	// SendOutputs.
@@ -314,7 +315,7 @@ func (b *BtcWallet) SendOutputs(outputs []*wire.TxOut,
 //
 // This is a part of the WalletController interface.
 func (b *BtcWallet) CreateSimpleTx(outputs []*wire.TxOut,
-	feeRate lnwallet.SatPerKWeight, dryRun bool) (*txauthor.AuthoredTx, error) {
+	feeRate chainfee.SatPerKWeight, dryRun bool) (*txauthor.AuthoredTx, error) {
 
 	// The fee rate is passed in using units of sat/kw, so we'll convert
 	// this to sat/KB as the CreateSimpleTx method requires this unit.
diff --git a/lnwallet/fee_estimator.go b/lnwallet/chainfee/estimator.go
similarity index 68%
rename from lnwallet/fee_estimator.go
rename to lnwallet/chainfee/estimator.go
index bda93d63b..5f89f1224 100644
--- a/lnwallet/fee_estimator.go
+++ b/lnwallet/chainfee/estimator.go
@@ -1,4 +1,4 @@
-package lnwallet
+package chainfee
 
 import (
 	"encoding/json"
@@ -10,85 +10,41 @@ import (
 	"sync"
 	"time"
 
-	"github.com/btcsuite/btcd/blockchain"
 	"github.com/btcsuite/btcd/rpcclient"
 	"github.com/btcsuite/btcutil"
 )
 
 const (
-	// FeePerKwFloor is the lowest fee rate in sat/kw that we should use for
-	// determining transaction fees.
-	FeePerKwFloor SatPerKWeight = 253
-
 	// maxBlockTarget is the highest number of blocks confirmations that
-	// a WebAPIFeeEstimator will cache fees for. This number is chosen
+	// a WebAPIEstimator will cache fees for. This number is chosen
 	// because it's the highest number of confs bitcoind will return a fee
 	// estimate for.
 	maxBlockTarget uint32 = 1009
 
 	// minBlockTarget is the lowest number of blocks confirmations that
-	// a WebAPIFeeEstimator will cache fees for. Requesting an estimate for
+	// a WebAPIEstimator will cache fees for. Requesting an estimate for
 	// less than this will result in an error.
 	minBlockTarget uint32 = 2
 
 	// minFeeUpdateTimeout represents the minimum interval in which a
-	// WebAPIFeeEstimator will request fresh fees from its API.
+	// WebAPIEstimator will request fresh fees from its API.
 	minFeeUpdateTimeout = 5 * time.Minute
 
 	// maxFeeUpdateTimeout represents the maximum interval in which a
-	// WebAPIFeeEstimator will request fresh fees from its API.
+	// WebAPIEstimator will request fresh fees from its API.
 	maxFeeUpdateTimeout = 20 * time.Minute
 )
 
-// SatPerKVByte represents a fee rate in sat/kb.
-type SatPerKVByte btcutil.Amount
-
-// FeeForVSize calculates the fee resulting from this fee rate and the given
-// vsize in vbytes.
-func (s SatPerKVByte) FeeForVSize(vbytes int64) btcutil.Amount {
-	return btcutil.Amount(s) * btcutil.Amount(vbytes) / 1000
-}
-
-// FeePerKWeight converts the current fee rate from sat/kb to sat/kw.
-func (s SatPerKVByte) FeePerKWeight() SatPerKWeight {
-	return SatPerKWeight(s / blockchain.WitnessScaleFactor)
-}
-
-// String returns a human-readable string of the fee rate.
-func (s SatPerKVByte) String() string {
-	return fmt.Sprintf("%v sat/kb", int64(s))
-}
-
-// SatPerKWeight represents a fee rate in sat/kw.
-type SatPerKWeight btcutil.Amount
-
-// FeeForWeight calculates the fee resulting from this fee rate and the given
-// weight in weight units (wu).
-func (s SatPerKWeight) FeeForWeight(wu int64) btcutil.Amount {
-	// The resulting fee is rounded down, as specified in BOLT#03.
-	return btcutil.Amount(s) * btcutil.Amount(wu) / 1000
-}
-
-// FeePerKVByte converts the current fee rate from sat/kw to sat/kb.
-func (s SatPerKWeight) FeePerKVByte() SatPerKVByte {
-	return SatPerKVByte(s * blockchain.WitnessScaleFactor)
-}
-
-// String returns a human-readable string of the fee rate.
-func (s SatPerKWeight) String() string {
-	return fmt.Sprintf("%v sat/kw", int64(s))
-}
-
-// FeeEstimator provides the ability to estimate on-chain transaction fees for
+// Estimator provides the ability to estimate on-chain transaction fees for
 // various combinations of transaction sizes and desired confirmation time
 // (measured by number of blocks).
-type FeeEstimator interface {
+type Estimator interface {
 	// EstimateFeePerKW takes in a target for the number of blocks until an
 	// initial confirmation and returns the estimated fee expressed in
 	// sat/kw.
 	EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error)
 
-	// Start signals the FeeEstimator to start any processes or goroutines
+	// Start signals the Estimator to start any processes or goroutines
 	// it needs to perform its duty.
 	Start() error
 
@@ -102,11 +58,11 @@ type FeeEstimator interface {
 	RelayFeePerKW() SatPerKWeight
 }
 
-// StaticFeeEstimator will return a static value for all fee calculation
-// requests. It is designed to be replaced by a proper fee calculation
-// implementation. The fees are not accessible directly, because changing them
-// would not be thread safe.
-type StaticFeeEstimator struct {
+// StaticEstimator will return a static value for all fee calculation requests.
+// It is designed to be replaced by a proper fee calculation implementation.
+// The fees are not accessible directly, because changing them would not be
+// thread safe.
+type StaticEstimator struct {
 	// feePerKW is the static fee rate in satoshis-per-vbyte that will be
 	// returned by this fee estimator.
 	feePerKW SatPerKWeight
@@ -116,11 +72,10 @@ type StaticFeeEstimator struct {
 	relayFee SatPerKWeight
 }
 
-// NewStaticFeeEstimator returns a new static fee estimator instance.
-func NewStaticFeeEstimator(feePerKW,
-	relayFee SatPerKWeight) *StaticFeeEstimator {
+// NewStaticEstimator returns a new static fee estimator instance.
+func NewStaticEstimator(feePerKW, relayFee SatPerKWeight) *StaticEstimator {
 
-	return &StaticFeeEstimator{
+	return &StaticEstimator{
 		feePerKW: feePerKW,
 		relayFee: relayFee,
 	}
@@ -128,43 +83,43 @@ func NewStaticFeeEstimator(feePerKW,
 
 // EstimateFeePerKW will return a static value for fee calculations.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (e StaticFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
+// NOTE: This method is part of the Estimator interface.
+func (e StaticEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
 	return e.feePerKW, nil
 }
 
 // RelayFeePerKW returns the minimum fee rate required for transactions to be
 // relayed.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (e StaticFeeEstimator) RelayFeePerKW() SatPerKWeight {
+// NOTE: This method is part of the Estimator interface.
+func (e StaticEstimator) RelayFeePerKW() SatPerKWeight {
 	return e.relayFee
 }
 
-// Start signals the FeeEstimator to start any processes or goroutines
+// Start signals the Estimator to start any processes or goroutines
 // it needs to perform its duty.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (e StaticFeeEstimator) Start() error {
+// NOTE: This method is part of the Estimator interface.
+func (e StaticEstimator) Start() error {
 	return nil
 }
 
 // Stop stops any spawned goroutines and cleans up the resources used
 // by the fee estimator.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (e StaticFeeEstimator) Stop() error {
+// NOTE: This method is part of the Estimator interface.
+func (e StaticEstimator) Stop() error {
 	return nil
 }
 
 // A compile-time assertion to ensure that StaticFeeEstimator implements the
-// FeeEstimator interface.
-var _ FeeEstimator = (*StaticFeeEstimator)(nil)
+// Estimator interface.
+var _ Estimator = (*StaticEstimator)(nil)
 
-// BtcdFeeEstimator is an implementation of the FeeEstimator interface backed
+// BtcdEstimator is an implementation of the Estimator interface backed
 // by the RPC interface of an active btcd node. This implementation will proxy
 // any fee estimation requests to btcd's RPC interface.
-type BtcdFeeEstimator struct {
+type BtcdEstimator struct {
 	// fallbackFeePerKW is the fall back fee rate in sat/kw that is returned
 	// if the fee estimator does not yet have enough data to actually
 	// produce fee estimates.
@@ -179,13 +134,13 @@ type BtcdFeeEstimator struct {
 	btcdConn *rpcclient.Client
 }
 
-// NewBtcdFeeEstimator creates a new BtcdFeeEstimator given a fully populated
+// NewBtcdEstimator creates a new BtcdEstimator given a fully populated
 // rpc config that is able to successfully connect and authenticate with the
 // btcd node, and also a fall back fee rate. The fallback fee rate is used in
 // the occasion that the estimator has insufficient data, or returns zero for a
 // fee estimate.
-func NewBtcdFeeEstimator(rpcConfig rpcclient.ConnConfig,
-	fallBackFeeRate SatPerKWeight) (*BtcdFeeEstimator, error) {
+func NewBtcdEstimator(rpcConfig rpcclient.ConnConfig,
+	fallBackFeeRate SatPerKWeight) (*BtcdEstimator, error) {
 
 	rpcConfig.DisableConnectOnNew = true
 	rpcConfig.DisableAutoReconnect = false
@@ -194,17 +149,17 @@ func NewBtcdFeeEstimator(rpcConfig rpcclient.ConnConfig,
 		return nil, err
 	}
 
-	return &BtcdFeeEstimator{
+	return &BtcdEstimator{
 		fallbackFeePerKW: fallBackFeeRate,
 		btcdConn:         chainConn,
 	}, nil
 }
 
-// Start signals the FeeEstimator to start any processes or goroutines
+// Start signals the Estimator to start any processes or goroutines
 // it needs to perform its duty.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (b *BtcdFeeEstimator) Start() error {
+// NOTE: This method is part of the Estimator interface.
+func (b *BtcdEstimator) Start() error {
 	if err := b.btcdConn.Connect(20); err != nil {
 		return err
 	}
@@ -233,7 +188,7 @@ func (b *BtcdFeeEstimator) Start() error {
 		b.minFeePerKW = FeePerKwFloor
 	}
 
-	walletLog.Debugf("Using minimum fee rate of %v sat/kw",
+	log.Debugf("Using minimum fee rate of %v sat/kw",
 		int64(b.minFeePerKW))
 
 	return nil
@@ -242,8 +197,8 @@ func (b *BtcdFeeEstimator) Start() error {
 // Stop stops any spawned goroutines and cleans up the resources used
 // by the fee estimator.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (b *BtcdFeeEstimator) Stop() error {
+// NOTE: This method is part of the Estimator interface.
+func (b *BtcdEstimator) Stop() error {
 	b.btcdConn.Shutdown()
 
 	return nil
@@ -252,15 +207,15 @@ func (b *BtcdFeeEstimator) Stop() error {
 // EstimateFeePerKW takes in a target for the number of blocks until an initial
 // confirmation and returns the estimated fee expressed in sat/kw.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (b *BtcdFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
+// NOTE: This method is part of the Estimator interface.
+func (b *BtcdEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
 	feeEstimate, err := b.fetchEstimate(numBlocks)
 	switch {
 	// If the estimator doesn't have enough data, or returns an error, then
 	// to return a proper value, then we'll return the default fall back
 	// fee rate.
 	case err != nil:
-		walletLog.Errorf("unable to query estimator: %v", err)
+		log.Errorf("unable to query estimator: %v", err)
 		fallthrough
 
 	case feeEstimate == 0:
@@ -273,14 +228,14 @@ func (b *BtcdFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, er
 // RelayFeePerKW returns the minimum fee rate required for transactions to be
 // relayed.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (b *BtcdFeeEstimator) RelayFeePerKW() SatPerKWeight {
+// NOTE: This method is part of the Estimator interface.
+func (b *BtcdEstimator) RelayFeePerKW() SatPerKWeight {
 	return b.minFeePerKW
 }
 
 // fetchEstimate returns a fee estimate for a transaction to be confirmed in
 // confTarget blocks. The estimate is returned in sat/kw.
-func (b *BtcdFeeEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, error) {
+func (b *BtcdEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, error) {
 	// First, we'll fetch the estimate for our confirmation target.
 	btcPerKB, err := b.btcdConn.EstimateFee(int64(confTarget))
 	if err != nil {
@@ -300,26 +255,26 @@ func (b *BtcdFeeEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, erro
 
 	// Finally, we'll enforce our fee floor.
 	if satPerKw < b.minFeePerKW {
-		walletLog.Debugf("Estimated fee rate of %v sat/kw is too low, "+
+		log.Debugf("Estimated fee rate of %v sat/kw is too low, "+
 			"using fee floor of %v sat/kw instead", satPerKw,
 			b.minFeePerKW)
 		satPerKw = b.minFeePerKW
 	}
 
-	walletLog.Debugf("Returning %v sat/kw for conf target of %v",
+	log.Debugf("Returning %v sat/kw for conf target of %v",
 		int64(satPerKw), confTarget)
 
 	return satPerKw, nil
 }
 
-// A compile-time assertion to ensure that BtcdFeeEstimator implements the
-// FeeEstimator interface.
-var _ FeeEstimator = (*BtcdFeeEstimator)(nil)
+// A compile-time assertion to ensure that BtcdEstimator implements the
+// Estimator interface.
+var _ Estimator = (*BtcdEstimator)(nil)
 
-// BitcoindFeeEstimator is an implementation of the FeeEstimator interface
-// backed by the RPC interface of an active bitcoind node. This implementation
-// will proxy any fee estimation requests to bitcoind's RPC interface.
-type BitcoindFeeEstimator struct {
+// BitcoindEstimator is an implementation of the Estimator interface backed by
+// the RPC interface of an active bitcoind node. This implementation will proxy
+// any fee estimation requests to bitcoind's RPC interface.
+type BitcoindEstimator struct {
 	// fallbackFeePerKW is the fallback fee rate in sat/kw that is returned
 	// if the fee estimator does not yet have enough data to actually
 	// produce fee estimates.
@@ -334,13 +289,13 @@ type BitcoindFeeEstimator struct {
 	bitcoindConn *rpcclient.Client
 }
 
-// NewBitcoindFeeEstimator creates a new BitcoindFeeEstimator given a fully
-// populated rpc config that is able to successfully connect and authenticate
-// with the bitcoind node, and also a fall back fee rate. The fallback fee rate
-// is used in the occasion that the estimator has insufficient data, or returns
-// zero for a fee estimate.
-func NewBitcoindFeeEstimator(rpcConfig rpcclient.ConnConfig,
-	fallBackFeeRate SatPerKWeight) (*BitcoindFeeEstimator, error) {
+// NewBitcoindEstimator creates a new BitcoindEstimator given a fully populated
+// rpc config that is able to successfully connect and authenticate with the
+// bitcoind node, and also a fall back fee rate. The fallback fee rate is used
+// in the occasion that the estimator has insufficient data, or returns zero
+// for a fee estimate.
+func NewBitcoindEstimator(rpcConfig rpcclient.ConnConfig,
+	fallBackFeeRate SatPerKWeight) (*BitcoindEstimator, error) {
 
 	rpcConfig.DisableConnectOnNew = true
 	rpcConfig.DisableAutoReconnect = false
@@ -351,17 +306,17 @@ func NewBitcoindFeeEstimator(rpcConfig rpcclient.ConnConfig,
 		return nil, err
 	}
 
-	return &BitcoindFeeEstimator{
+	return &BitcoindEstimator{
 		fallbackFeePerKW: fallBackFeeRate,
 		bitcoindConn:     chainConn,
 	}, nil
 }
 
-// Start signals the FeeEstimator to start any processes or goroutines
+// Start signals the Estimator to start any processes or goroutines
 // it needs to perform its duty.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (b *BitcoindFeeEstimator) Start() error {
+// NOTE: This method is part of the Estimator interface.
+func (b *BitcoindEstimator) Start() error {
 	// Once the connection to the backend node has been established, we'll
 	// query it for its minimum relay fee. Since the `getinfo` RPC has been
 	// deprecated for `bitcoind`, we'll need to send a `getnetworkinfo`
@@ -396,7 +351,7 @@ func (b *BitcoindFeeEstimator) Start() error {
 		b.minFeePerKW = FeePerKwFloor
 	}
 
-	walletLog.Debugf("Using minimum fee rate of %v sat/kw",
+	log.Debugf("Using minimum fee rate of %v sat/kw",
 		int64(b.minFeePerKW))
 
 	return nil
@@ -405,23 +360,23 @@ func (b *BitcoindFeeEstimator) Start() error {
 // Stop stops any spawned goroutines and cleans up the resources used
 // by the fee estimator.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (b *BitcoindFeeEstimator) Stop() error {
+// NOTE: This method is part of the Estimator interface.
+func (b *BitcoindEstimator) Stop() error {
 	return nil
 }
 
 // EstimateFeePerKW takes in a target for the number of blocks until an initial
 // confirmation and returns the estimated fee expressed in sat/kw.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (b *BitcoindFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
+// NOTE: This method is part of the Estimator interface.
+func (b *BitcoindEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
 	feeEstimate, err := b.fetchEstimate(numBlocks)
 	switch {
 	// If the estimator doesn't have enough data, or returns an error, then
 	// to return a proper value, then we'll return the default fall back
 	// fee rate.
 	case err != nil:
-		walletLog.Errorf("unable to query estimator: %v", err)
+		log.Errorf("unable to query estimator: %v", err)
 		fallthrough
 
 	case feeEstimate == 0:
@@ -434,14 +389,14 @@ func (b *BitcoindFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight
 // RelayFeePerKW returns the minimum fee rate required for transactions to be
 // relayed.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (b *BitcoindFeeEstimator) RelayFeePerKW() SatPerKWeight {
+// NOTE: This method is part of the Estimator interface.
+func (b *BitcoindEstimator) RelayFeePerKW() SatPerKWeight {
 	return b.minFeePerKW
 }
 
 // fetchEstimate returns a fee estimate for a transaction to be confirmed in
 // confTarget blocks. The estimate is returned in sat/kw.
-func (b *BitcoindFeeEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, error) {
+func (b *BitcoindEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, error) {
 	// First, we'll send an "estimatesmartfee" command as a raw request,
 	// since it isn't supported by btcd but is available in bitcoind.
 	target, err := json.Marshal(uint64(confTarget))
@@ -478,26 +433,26 @@ func (b *BitcoindFeeEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight,
 
 	// Finally, we'll enforce our fee floor.
 	if satPerKw < b.minFeePerKW {
-		walletLog.Debugf("Estimated fee rate of %v sat/kw is too low, "+
+		log.Debugf("Estimated fee rate of %v sat/kw is too low, "+
 			"using fee floor of %v sat/kw instead", satPerKw,
 			b.minFeePerKW)
 
 		satPerKw = b.minFeePerKW
 	}
 
-	walletLog.Debugf("Returning %v sat/kw for conf target of %v",
+	log.Debugf("Returning %v sat/kw for conf target of %v",
 		int64(satPerKw), confTarget)
 
 	return satPerKw, nil
 }
 
-// A compile-time assertion to ensure that BitcoindFeeEstimator implements the
-// FeeEstimator interface.
-var _ FeeEstimator = (*BitcoindFeeEstimator)(nil)
+// A compile-time assertion to ensure that BitcoindEstimator implements the
+// Estimator interface.
+var _ Estimator = (*BitcoindEstimator)(nil)
 
-// WebAPIFeeSource is an interface allows the WebAPIFeeEstimator to query an
+// WebAPIFeeSource is an interface allows the WebAPIEstimator to query an
 // arbitrary HTTP-based fee estimator. Each new set/network will gain an
-// implementation of this interface in order to allow the WebAPIFeeEstimator to
+// implementation of this interface in order to allow the WebAPIEstimator to
 // be fully generic in its logic.
 type WebAPIFeeSource interface {
 	// GenQueryURL generates the full query URL. The value returned by this
@@ -554,9 +509,9 @@ func (s SparseConfFeeSource) ParseResponse(r io.Reader) (map[uint32]uint32, erro
 // WebAPIFeeSource interface.
 var _ WebAPIFeeSource = (*SparseConfFeeSource)(nil)
 
-// WebAPIFeeEstimator is an implementation of the FeeEstimator interface that
+// WebAPIEstimator is an implementation of the Estimator interface that
 // queries an HTTP-based fee estimation from an existing web API.
-type WebAPIFeeEstimator struct {
+type WebAPIEstimator struct {
 	started sync.Once
 	stopped sync.Once
 
@@ -581,12 +536,12 @@ type WebAPIFeeEstimator struct {
 	wg   sync.WaitGroup
 }
 
-// NewWebAPIFeeEstimator creates a new WebAPIFeeEstimator from a given URL and a
+// NewWebAPIEstimator creates a new WebAPIEstimator from a given URL and a
 // fallback default fee. The fees are updated whenever a new block is mined.
-func NewWebAPIFeeEstimator(
-	api WebAPIFeeSource, defaultFee SatPerKWeight) *WebAPIFeeEstimator {
+func NewWebAPIEstimator(
+	api WebAPIFeeSource, defaultFee SatPerKWeight) *WebAPIEstimator {
 
-	return &WebAPIFeeEstimator{
+	return &WebAPIEstimator{
 		apiSource:        api,
 		feeByBlockTarget: make(map[uint32]uint32),
 		defaultFeePerKw:  defaultFee,
@@ -597,8 +552,8 @@ func NewWebAPIFeeEstimator(
 // EstimateFeePerKW takes in a target for the number of blocks until an initial
 // confirmation and returns the estimated fee expressed in sat/kw.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (w *WebAPIFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
+// NOTE: This method is part of the Estimator interface.
+func (w *WebAPIEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight, error) {
 	if numBlocks > maxBlockTarget {
 		numBlocks = maxBlockTarget
 	} else if numBlocks < minBlockTarget {
@@ -618,20 +573,20 @@ func (w *WebAPIFeeEstimator) EstimateFeePerKW(numBlocks uint32) (SatPerKWeight,
 		satPerKw = FeePerKwFloor
 	}
 
-	walletLog.Debugf("Web API returning %v sat/kw for conf target of %v",
+	log.Debugf("Web API returning %v sat/kw for conf target of %v",
 		int64(satPerKw), numBlocks)
 
 	return satPerKw, nil
 }
 
-// Start signals the FeeEstimator to start any processes or goroutines it needs
+// Start signals the Estimator to start any processes or goroutines it needs
 // to perform its duty.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (w *WebAPIFeeEstimator) Start() error {
+// NOTE: This method is part of the Estimator interface.
+func (w *WebAPIEstimator) Start() error {
 	var err error
 	w.started.Do(func() {
-		walletLog.Infof("Starting web API fee estimator")
+		log.Infof("Starting web API fee estimator")
 
 		w.updateFeeTicker = time.NewTicker(w.randomFeeUpdateTimeout())
 		w.updateFeeEstimates()
@@ -646,10 +601,10 @@ func (w *WebAPIFeeEstimator) Start() error {
 // Stop stops any spawned goroutines and cleans up the resources used by the
 // fee estimator.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (w *WebAPIFeeEstimator) Stop() error {
+// NOTE: This method is part of the Estimator interface.
+func (w *WebAPIEstimator) Stop() error {
 	w.stopped.Do(func() {
-		walletLog.Infof("Stopping web API fee estimator")
+		log.Infof("Stopping web API fee estimator")
 
 		w.updateFeeTicker.Stop()
 
@@ -662,15 +617,15 @@ func (w *WebAPIFeeEstimator) Stop() error {
 // RelayFeePerKW returns the minimum fee rate required for transactions to be
 // relayed.
 //
-// NOTE: This method is part of the FeeEstimator interface.
-func (w *WebAPIFeeEstimator) RelayFeePerKW() SatPerKWeight {
+// NOTE: This method is part of the Estimator interface.
+func (w *WebAPIEstimator) RelayFeePerKW() SatPerKWeight {
 	return FeePerKwFloor
 }
 
 // randomFeeUpdateTimeout returns a random timeout between minFeeUpdateTimeout
 // and maxFeeUpdateTimeout that will be used to determine how often the Estimator
 // should retrieve fresh fees from its API.
-func (w *WebAPIFeeEstimator) randomFeeUpdateTimeout() time.Duration {
+func (w *WebAPIEstimator) randomFeeUpdateTimeout() time.Duration {
 	lower := int64(minFeeUpdateTimeout)
 	upper := int64(maxFeeUpdateTimeout)
 	return time.Duration(prand.Int63n(upper-lower) + lower)
@@ -679,7 +634,7 @@ func (w *WebAPIFeeEstimator) randomFeeUpdateTimeout() time.Duration {
 // getCachedFee takes in a target for the number of blocks until an initial
 // confirmation and returns an estimated fee (if one was returned by the API). If
 // the fee was not previously cached, we cache it here.
-func (w *WebAPIFeeEstimator) getCachedFee(numBlocks uint32) (uint32, error) {
+func (w *WebAPIEstimator) getCachedFee(numBlocks uint32) (uint32, error) {
 	w.feesMtx.Lock()
 	defer w.feesMtx.Unlock()
 
@@ -704,7 +659,7 @@ func (w *WebAPIFeeEstimator) getCachedFee(numBlocks uint32) (uint32, error) {
 }
 
 // updateFeeEstimates re-queries the API for fresh fees and caches them.
-func (w *WebAPIFeeEstimator) updateFeeEstimates() {
+func (w *WebAPIEstimator) updateFeeEstimates() {
 	// Rather than use the default http.Client, we'll make a custom one
 	// which will allow us to control how long we'll wait to read the
 	// response from the service. This way, if the service is down or
@@ -725,7 +680,7 @@ func (w *WebAPIFeeEstimator) updateFeeEstimates() {
 	targetURL := w.apiSource.GenQueryURL()
 	resp, err := netClient.Get(targetURL)
 	if err != nil {
-		walletLog.Errorf("unable to query web api for fee response: %v",
+		log.Errorf("unable to query web api for fee response: %v",
 			err)
 		return
 	}
@@ -735,7 +690,7 @@ func (w *WebAPIFeeEstimator) updateFeeEstimates() {
 	// to parse out the body to obtain our final result.
 	feesByBlockTarget, err := w.apiSource.ParseResponse(resp.Body)
 	if err != nil {
-		walletLog.Errorf("unable to query web api for fee response: %v",
+		log.Errorf("unable to query web api for fee response: %v",
 			err)
 		return
 	}
@@ -746,7 +701,7 @@ func (w *WebAPIFeeEstimator) updateFeeEstimates() {
 }
 
 // feeUpdateManager updates the fee estimates whenever a new block comes in.
-func (w *WebAPIFeeEstimator) feeUpdateManager() {
+func (w *WebAPIEstimator) feeUpdateManager() {
 	defer w.wg.Done()
 
 	for {
@@ -759,6 +714,6 @@ func (w *WebAPIFeeEstimator) feeUpdateManager() {
 	}
 }
 
-// A compile-time assertion to ensure that WebAPIFeeEstimator implements the
-// FeeEstimator interface.
-var _ FeeEstimator = (*WebAPIFeeEstimator)(nil)
+// A compile-time assertion to ensure that WebAPIEstimator implements the
+// Estimator interface.
+var _ Estimator = (*WebAPIEstimator)(nil)
diff --git a/lnwallet/chainfee/log.go b/lnwallet/chainfee/log.go
new file mode 100644
index 000000000..d5d040578
--- /dev/null
+++ b/lnwallet/chainfee/log.go
@@ -0,0 +1,29 @@
+package chainfee
+
+import (
+	"github.com/btcsuite/btclog"
+	"github.com/lightningnetwork/lnd/build"
+)
+
+// log is a logger that is initialized with no output filters.  This means the
+// package will not perform any logging by default until the caller requests
+// it.
+var log btclog.Logger
+
+// The default amount of logging is none.
+func init() {
+	UseLogger(build.NewSubLogger("CFEE", nil))
+}
+
+// DisableLog disables all library log output.  Logging output is disabled by
+// default until UseLogger is called.
+func DisableLog() {
+	UseLogger(btclog.Disabled)
+}
+
+// UseLogger uses a specified Logger to output package logging info.  This
+// should be used in preference to SetLogWriter if the caller is also using
+// btclog.
+func UseLogger(logger btclog.Logger) {
+	log = logger
+}
diff --git a/lnwallet/chainfee/rates.go b/lnwallet/chainfee/rates.go
new file mode 100644
index 000000000..48c3d7dfe
--- /dev/null
+++ b/lnwallet/chainfee/rates.go
@@ -0,0 +1,53 @@
+package chainfee
+
+import (
+	"fmt"
+
+	"github.com/btcsuite/btcd/blockchain"
+	"github.com/btcsuite/btcutil"
+)
+
+const (
+	// FeePerKwFloor is the lowest fee rate in sat/kw that we should use for
+	// determining transaction fees.
+	FeePerKwFloor SatPerKWeight = 253
+)
+
+// SatPerKVByte represents a fee rate in sat/kb.
+type SatPerKVByte btcutil.Amount
+
+// FeeForVSize calculates the fee resulting from this fee rate and the given
+// vsize in vbytes.
+func (s SatPerKVByte) FeeForVSize(vbytes int64) btcutil.Amount {
+	return btcutil.Amount(s) * btcutil.Amount(vbytes) / 1000
+}
+
+// FeePerKWeight converts the current fee rate from sat/kb to sat/kw.
+func (s SatPerKVByte) FeePerKWeight() SatPerKWeight {
+	return SatPerKWeight(s / blockchain.WitnessScaleFactor)
+}
+
+// String returns a human-readable string of the fee rate.
+func (s SatPerKVByte) String() string {
+	return fmt.Sprintf("%v sat/kb", int64(s))
+}
+
+// SatPerKWeight represents a fee rate in sat/kw.
+type SatPerKWeight btcutil.Amount
+
+// FeeForWeight calculates the fee resulting from this fee rate and the given
+// weight in weight units (wu).
+func (s SatPerKWeight) FeeForWeight(wu int64) btcutil.Amount {
+	// The resulting fee is rounded down, as specified in BOLT#03.
+	return btcutil.Amount(s) * btcutil.Amount(wu) / 1000
+}
+
+// FeePerKVByte converts the current fee rate from sat/kw to sat/kb.
+func (s SatPerKWeight) FeePerKVByte() SatPerKVByte {
+	return SatPerKVByte(s * blockchain.WitnessScaleFactor)
+}
+
+// String returns a human-readable string of the fee rate.
+func (s SatPerKWeight) String() string {
+	return fmt.Sprintf("%v sat/kw", int64(s))
+}
diff --git a/lnwallet/channel.go b/lnwallet/channel.go
index f9d077875..3366f2f74 100644
--- a/lnwallet/channel.go
+++ b/lnwallet/channel.go
@@ -22,6 +22,7 @@ import (
 	"github.com/lightningnetwork/lnd/chainntnfs"
 	"github.com/lightningnetwork/lnd/channeldb"
 	"github.com/lightningnetwork/lnd/input"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 )
 
@@ -512,7 +513,7 @@ type commitment struct {
 
 	// feePerKw is the fee per kw used to calculate this commitment
 	// transaction's fee.
-	feePerKw SatPerKWeight
+	feePerKw chainfee.SatPerKWeight
 
 	// dustLimit is the limit on the commitment transaction such that no
 	// output values should be below this amount.
@@ -759,7 +760,7 @@ func (c *commitment) toDiskCommit(ourCommit bool) *channeldb.ChannelCommitment {
 // commitment struct and updateLog. This function is used when we need to
 // restore commitment state written do disk back into memory once we need to
 // restart a channel session.
-func (lc *LightningChannel) diskHtlcToPayDesc(feeRate SatPerKWeight,
+func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight,
 	commitHeight uint64, htlc *channeldb.HTLC, localCommitKeys,
 	remoteCommitKeys *CommitmentKeyRing) (PaymentDescriptor, error) {
 
@@ -824,7 +825,7 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate SatPerKWeight,
 // these payment descriptors can be re-inserted into the in-memory updateLog
 // for each side.
 func (lc *LightningChannel) extractPayDescs(commitHeight uint64,
-	feeRate SatPerKWeight, htlcs []channeldb.HTLC, localCommitKeys,
+	feeRate chainfee.SatPerKWeight, htlcs []channeldb.HTLC, localCommitKeys,
 	remoteCommitKeys *CommitmentKeyRing) ([]PaymentDescriptor, []PaymentDescriptor, error) {
 
 	var (
@@ -894,7 +895,8 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool,
 	// HTLC"s into PaymentDescriptor's so we can re-insert them into our
 	// update log.
 	incomingHtlcs, outgoingHtlcs, err := lc.extractPayDescs(
-		diskCommit.CommitHeight, SatPerKWeight(diskCommit.FeePerKw),
+		diskCommit.CommitHeight,
+		chainfee.SatPerKWeight(diskCommit.FeePerKw),
 		diskCommit.Htlcs, localCommitKeys, remoteCommitKeys,
 	)
 	if err != nil {
@@ -915,7 +917,7 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool,
 		txn:               diskCommit.CommitTx,
 		sig:               diskCommit.CommitSig,
 		fee:               diskCommit.CommitFee,
-		feePerKw:          SatPerKWeight(diskCommit.FeePerKw),
+		feePerKw:          chainfee.SatPerKWeight(diskCommit.FeePerKw),
 		incomingHTLCs:     incomingHtlcs,
 		outgoingHTLCs:     outgoingHtlcs,
 	}
@@ -1509,7 +1511,7 @@ func (lc *LightningChannel) ResetState() {
 // if nothing happened.
 func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate,
 	remoteUpdateLog *updateLog, commitHeight uint64,
-	feeRate SatPerKWeight, remoteCommitKeys *CommitmentKeyRing,
+	feeRate chainfee.SatPerKWeight, remoteCommitKeys *CommitmentKeyRing,
 	remoteDustLimit btcutil.Amount) (*PaymentDescriptor, error) {
 
 	// Depending on the type of update message we'll map that to a distinct
@@ -1826,7 +1828,8 @@ func (lc *LightningChannel) restoreStateLogs(
 	for _, logUpdate := range pendingRemoteCommitDiff.LogUpdates {
 		payDesc, err := lc.logUpdateToPayDesc(
 			&logUpdate, lc.remoteUpdateLog, pendingHeight,
-			SatPerKWeight(pendingCommit.FeePerKw), pendingRemoteKeys,
+			chainfee.SatPerKWeight(pendingCommit.FeePerKw),
+			pendingRemoteKeys,
 			lc.channelState.RemoteChanCfg.DustLimit,
 		)
 		if err != nil {
@@ -2109,7 +2112,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
 		// an output on the commitment transaction.
 		if htlcIsDust(
 			htlc.Incoming, false,
-			SatPerKWeight(revokedSnapshot.FeePerKw),
+			chainfee.SatPerKWeight(revokedSnapshot.FeePerKw),
 			htlc.Amt.ToSatoshis(), chanState.RemoteChanCfg.DustLimit,
 		) {
 			continue
@@ -2198,13 +2201,13 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
 
 // htlcTimeoutFee returns the fee in satoshis required for an HTLC timeout
 // transaction based on the current fee rate.
-func htlcTimeoutFee(feePerKw SatPerKWeight) btcutil.Amount {
+func htlcTimeoutFee(feePerKw chainfee.SatPerKWeight) btcutil.Amount {
 	return feePerKw.FeeForWeight(input.HtlcTimeoutWeight)
 }
 
 // htlcSuccessFee returns the fee in satoshis required for an HTLC success
 // transaction based on the current fee rate.
-func htlcSuccessFee(feePerKw SatPerKWeight) btcutil.Amount {
+func htlcSuccessFee(feePerKw chainfee.SatPerKWeight) btcutil.Amount {
 	return feePerKw.FeeForWeight(input.HtlcSuccessWeight)
 }
 
@@ -2214,7 +2217,7 @@ func htlcSuccessFee(feePerKw SatPerKWeight) btcutil.Amount {
 // require as we currently used second-level HTLC transactions as off-chain
 // covenants. Depending on the two bits, we'll either be using a timeout or
 // success transaction which have different weights.
-func htlcIsDust(incoming, ourCommit bool, feePerKw SatPerKWeight,
+func htlcIsDust(incoming, ourCommit bool, feePerKw chainfee.SatPerKWeight,
 	htlcAmt, dustLimit btcutil.Amount) bool {
 
 	// First we'll determine the fee required for this HTLC based on if this is
@@ -2255,7 +2258,7 @@ func htlcIsDust(incoming, ourCommit bool, feePerKw SatPerKWeight,
 type htlcView struct {
 	ourUpdates   []*PaymentDescriptor
 	theirUpdates []*PaymentDescriptor
-	feePerKw     SatPerKWeight
+	feePerKw     chainfee.SatPerKWeight
 }
 
 // fetchHTLCView returns all the candidate HTLC updates which should be
@@ -2786,7 +2789,7 @@ func processFeeUpdate(feeUpdate *PaymentDescriptor, nextHeight uint64,
 
 	// If the update wasn't already locked in, update the current fee rate
 	// to reflect this update.
-	view.feePerKw = SatPerKWeight(feeUpdate.Amount.ToSatoshis())
+	view.feePerKw = chainfee.SatPerKWeight(feeUpdate.Amount.ToSatoshis())
 
 	if mutateState {
 		*addHeight = nextHeight
@@ -3131,9 +3134,9 @@ func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter,
 
 	// Ensure that the fee being applied is enough to be relayed across the
 	// network in a reasonable time frame.
-	if feePerKw < FeePerKwFloor {
+	if feePerKw < chainfee.FeePerKwFloor {
 		return fmt.Errorf("commitment fee per kw %v below fee floor %v",
-			feePerKw, FeePerKwFloor)
+			feePerKw, chainfee.FeePerKwFloor)
 	}
 
 	// If the added HTLCs will decrease the balance, make sure they won't
@@ -5049,7 +5052,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
 	// Next, we'll obtain HTLC resolutions for all the outgoing HTLC's we
 	// had on their commitment transaction.
 	htlcResolutions, err := extractHtlcResolutions(
-		SatPerKWeight(remoteCommit.FeePerKw), false, signer,
+		chainfee.SatPerKWeight(remoteCommit.FeePerKw), false, signer,
 		remoteCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
 		&chanState.RemoteChanCfg, *commitSpend.SpenderTxHash,
 	)
@@ -5246,10 +5249,11 @@ type HtlcResolutions struct {
 // newOutgoingHtlcResolution generates a new HTLC resolution capable of
 // allowing the caller to sweep an outgoing HTLC present on either their, or
 // the remote party's commitment transaction.
-func newOutgoingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig,
-	commitHash chainhash.Hash, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
-	feePerKw SatPerKWeight, dustLimit btcutil.Amount, csvDelay uint32, localCommit bool,
-) (*OutgoingHtlcResolution, error) {
+func newOutgoingHtlcResolution(signer input.Signer,
+	localChanCfg *channeldb.ChannelConfig, commitHash chainhash.Hash,
+	htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
+	feePerKw chainfee.SatPerKWeight, csvDelay uint32,
+	localCommit bool) (*OutgoingHtlcResolution, error) {
 
 	op := wire.OutPoint{
 		Hash:  commitHash,
@@ -5388,7 +5392,7 @@ func newOutgoingHtlcResolution(signer input.Signer, localChanCfg *channeldb.Chan
 // TODO(roasbeef) consolidate code with above func
 func newIncomingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig,
 	commitHash chainhash.Hash, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
-	feePerKw SatPerKWeight, dustLimit btcutil.Amount, csvDelay uint32,
+	feePerKw chainfee.SatPerKWeight, csvDelay uint32,
 	localCommit bool) (*IncomingHtlcResolution, error) {
 
 	op := wire.OutPoint{
@@ -5542,7 +5546,7 @@ func (r *OutgoingHtlcResolution) HtlcPoint() wire.OutPoint {
 // extractHtlcResolutions creates a series of outgoing HTLC resolutions, and
 // the local key used when generating the HTLC scrips. This function is to be
 // used in two cases: force close, or a unilateral close.
-func extractHtlcResolutions(feePerKw SatPerKWeight, ourCommit bool,
+func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, ourCommit bool,
 	signer input.Signer, htlcs []channeldb.HTLC, keyRing *CommitmentKeyRing,
 	localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
 	commitHash chainhash.Hash) (*HtlcResolutions, error) {
@@ -5573,7 +5577,7 @@ func extractHtlcResolutions(feePerKw SatPerKWeight, ourCommit bool,
 			// as we can satisfy the contract.
 			ihr, err := newIncomingHtlcResolution(
 				signer, localChanCfg, commitHash, &htlc, keyRing,
-				feePerKw, dustLimit, uint32(csvDelay), ourCommit,
+				feePerKw, uint32(csvDelay), ourCommit,
 			)
 			if err != nil {
 				return nil, err
@@ -5585,7 +5589,7 @@ func extractHtlcResolutions(feePerKw SatPerKWeight, ourCommit bool,
 
 		ohr, err := newOutgoingHtlcResolution(
 			signer, localChanCfg, commitHash, &htlc, keyRing,
-			feePerKw, dustLimit, uint32(csvDelay), ourCommit,
+			feePerKw, uint32(csvDelay), ourCommit,
 		)
 		if err != nil {
 			return nil, err
@@ -5763,7 +5767,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
 	// outgoing HTLC's that we'll need to claim as well.
 	txHash := commitTx.TxHash()
 	htlcResolutions, err := extractHtlcResolutions(
-		SatPerKWeight(localCommit.FeePerKw), true, signer,
+		chainfee.SatPerKWeight(localCommit.FeePerKw), true, signer,
 		localCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
 		&chanState.RemoteChanCfg, txHash,
 	)
@@ -5981,7 +5985,7 @@ func (lc *LightningChannel) StateSnapshot() *channeldb.ChannelSnapshot {
 // validateFeeRate ensures that if the passed fee is applied to the channel,
 // and a new commitment is created (which evaluates this fee), then the
 // initiator of the channel does not dip below their reserve.
-func (lc *LightningChannel) validateFeeRate(feePerKw SatPerKWeight) error {
+func (lc *LightningChannel) validateFeeRate(feePerKw chainfee.SatPerKWeight) error {
 	// We'll ensure that we can accommodate this new fee change, yet still
 	// be above our reserve balance. Otherwise, we'll reject the fee
 	// update.
@@ -6029,7 +6033,7 @@ func (lc *LightningChannel) validateFeeRate(feePerKw SatPerKWeight) error {
 // UpdateFee initiates a fee update for this channel. Must only be called by
 // the channel initiator, and must be called before sending update_fee to
 // the remote.
-func (lc *LightningChannel) UpdateFee(feePerKw SatPerKWeight) error {
+func (lc *LightningChannel) UpdateFee(feePerKw chainfee.SatPerKWeight) error {
 	lc.Lock()
 	defer lc.Unlock()
 
@@ -6057,7 +6061,7 @@ func (lc *LightningChannel) UpdateFee(feePerKw SatPerKWeight) error {
 
 // ReceiveUpdateFee handles an updated fee sent from remote. This method will
 // return an error if called as channel initiator.
-func (lc *LightningChannel) ReceiveUpdateFee(feePerKw SatPerKWeight) error {
+func (lc *LightningChannel) ReceiveUpdateFee(feePerKw chainfee.SatPerKWeight) error {
 	lc.Lock()
 	defer lc.Unlock()
 
@@ -6213,7 +6217,7 @@ func CreateCooperativeCloseTx(fundingTxIn wire.TxIn,
 
 // CalcFee returns the commitment fee to use for the given
 // fee rate (fee-per-kw).
-func (lc *LightningChannel) CalcFee(feeRate SatPerKWeight) btcutil.Amount {
+func (lc *LightningChannel) CalcFee(feeRate chainfee.SatPerKWeight) btcutil.Amount {
 	return feeRate.FeeForWeight(input.CommitWeight)
 }
 
@@ -6223,7 +6227,7 @@ func (lc *LightningChannel) CalcFee(feeRate SatPerKWeight) btcutil.Amount {
 //
 // NOTE: This should only be used for channels in which the local commitment is
 // the initiator.
-func (lc *LightningChannel) MaxFeeRate(maxAllocation float64) SatPerKWeight {
+func (lc *LightningChannel) MaxFeeRate(maxAllocation float64) chainfee.SatPerKWeight {
 	lc.RLock()
 	defer lc.RUnlock()
 
@@ -6237,7 +6241,9 @@ func (lc *LightningChannel) MaxFeeRate(maxAllocation float64) SatPerKWeight {
 
 	// Ensure the fee rate doesn't dip below the fee floor.
 	maxFeeRate := maxFee / (float64(weight) / 1000)
-	return SatPerKWeight(math.Max(maxFeeRate, float64(FeePerKwFloor)))
+	return chainfee.SatPerKWeight(
+		math.Max(maxFeeRate, float64(chainfee.FeePerKwFloor)),
+	)
 }
 
 // RemoteNextRevocation returns the channelState's RemoteNextRevocation.
@@ -6260,11 +6266,11 @@ func (lc *LightningChannel) IsInitiator() bool {
 
 // CommitFeeRate returns the current fee rate of the commitment transaction in
 // units of sat-per-kw.
-func (lc *LightningChannel) CommitFeeRate() SatPerKWeight {
+func (lc *LightningChannel) CommitFeeRate() chainfee.SatPerKWeight {
 	lc.RLock()
 	defer lc.RUnlock()
 
-	return SatPerKWeight(lc.channelState.LocalCommitment.FeePerKw)
+	return chainfee.SatPerKWeight(lc.channelState.LocalCommitment.FeePerKw)
 }
 
 // IsPending returns true if the channel's funding transaction has been fully
diff --git a/lnwallet/config.go b/lnwallet/config.go
index e86a8cbef..a73120c02 100644
--- a/lnwallet/config.go
+++ b/lnwallet/config.go
@@ -6,6 +6,7 @@ import (
 	"github.com/lightningnetwork/lnd/channeldb"
 	"github.com/lightningnetwork/lnd/input"
 	"github.com/lightningnetwork/lnd/keychain"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 )
 
 // Config is a struct which houses configuration parameters which modify the
@@ -42,7 +43,7 @@ type Config struct {
 
 	// FeeEstimator is the implementation that the wallet will use for the
 	// calculation of on-chain transaction fees.
-	FeeEstimator FeeEstimator
+	FeeEstimator chainfee.Estimator
 
 	// ChainIO is an instance of the BlockChainIO interface. ChainIO is
 	// used to lookup the existence of outputs within the UTXO set.
diff --git a/lnwallet/interface.go b/lnwallet/interface.go
index bf6c255da..1c6c2bd70 100644
--- a/lnwallet/interface.go
+++ b/lnwallet/interface.go
@@ -10,6 +10,7 @@ import (
 	"github.com/btcsuite/btcd/wire"
 	"github.com/btcsuite/btcutil"
 	"github.com/btcsuite/btcwallet/wallet/txauthor"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 )
 
 // AddressType is an enum-like type which denotes the possible address types
@@ -172,7 +173,7 @@ type WalletController interface {
 	// This method also takes the target fee expressed in sat/kw that should
 	// be used when crafting the transaction.
 	SendOutputs(outputs []*wire.TxOut,
-		feeRate SatPerKWeight) (*wire.MsgTx, error)
+		feeRate chainfee.SatPerKWeight) (*wire.MsgTx, error)
 
 	// CreateSimpleTx creates a Bitcoin transaction paying to the specified
 	// outputs. The transaction is not broadcasted to the network. In the
@@ -184,7 +185,7 @@ type WalletController interface {
 	// NOTE: The dryRun argument can be set true to create a tx that
 	// doesn't alter the database. A tx created with this set to true
 	// SHOULD NOT be broadcasted.
-	CreateSimpleTx(outputs []*wire.TxOut, feeRate SatPerKWeight,
+	CreateSimpleTx(outputs []*wire.TxOut, feeRate chainfee.SatPerKWeight,
 		dryRun bool) (*txauthor.AuthoredTx, error)
 
 	// ListUnspentWitness returns all unspent outputs which are version 0
diff --git a/lnwallet/log.go b/lnwallet/log.go
index 97f1c21ff..31881e2d1 100644
--- a/lnwallet/log.go
+++ b/lnwallet/log.go
@@ -7,6 +7,7 @@ import (
 	"github.com/btcsuite/btcwallet/wtxmgr"
 
 	"github.com/lightningnetwork/lnd/build"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 )
 
 // walletLog is a logger that is initialized with no output filters.  This
@@ -34,6 +35,7 @@ func UseLogger(logger btclog.Logger) {
 	btcwallet.UseLogger(logger)
 	wtxmgr.UseLogger(logger)
 	chain.UseLogger(logger)
+	chainfee.UseLogger(logger)
 }
 
 // logClosure is used to provide a closure over expensive logging operations
diff --git a/lnwallet/reservation.go b/lnwallet/reservation.go
index b96651ff0..920231330 100644
--- a/lnwallet/reservation.go
+++ b/lnwallet/reservation.go
@@ -10,6 +10,7 @@ import (
 	"github.com/btcsuite/btcutil"
 	"github.com/lightningnetwork/lnd/channeldb"
 	"github.com/lightningnetwork/lnd/input"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 )
 
@@ -128,7 +129,7 @@ type ChannelReservation struct {
 // creation of all channel reservations should be carried out via the
 // lnwallet.InitChannelReservation interface.
 func NewChannelReservation(capacity, localFundingAmt btcutil.Amount,
-	commitFeePerKw SatPerKWeight, wallet *LightningWallet,
+	commitFeePerKw chainfee.SatPerKWeight, wallet *LightningWallet,
 	id uint64, pushMSat lnwire.MilliSatoshi, chainHash *chainhash.Hash,
 	flags lnwire.FundingFlag,
 	tweaklessCommit bool) (*ChannelReservation, error) {
diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go
index ba65fe4b7..c3c2020df 100644
--- a/lnwallet/wallet.go
+++ b/lnwallet/wallet.go
@@ -21,6 +21,7 @@ import (
 	"github.com/lightningnetwork/lnd/channeldb"
 	"github.com/lightningnetwork/lnd/input"
 	"github.com/lightningnetwork/lnd/keychain"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwallet/chanvalidate"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/shachain"
@@ -89,11 +90,11 @@ type InitFundingReserveMsg struct {
 	// of initial commitment transactions. In order to ensure timely
 	// confirmation, it is recommended that this fee should be generous,
 	// paying some multiple of the accepted base fee rate of the network.
-	CommitFeePerKw SatPerKWeight
+	CommitFeePerKw chainfee.SatPerKWeight
 
 	// FundingFeePerKw is the fee rate in sat/kw to use for the initial
 	// funding transaction.
-	FundingFeePerKw SatPerKWeight
+	FundingFeePerKw chainfee.SatPerKWeight
 
 	// PushMSat is the number of milli-satoshis that should be pushed over
 	// the responder as part of the initial channel creation.
@@ -1323,7 +1324,7 @@ type coinSelection struct {
 // returned, and the value of the resulting funding output. This method locks
 // the selected outputs, and a function closure to unlock them in case of an
 // error is returned.
-func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerKWeight,
+func (l *LightningWallet) selectCoinsAndChange(feeRate chainfee.SatPerKWeight,
 	amt btcutil.Amount, minConfs int32, subtractFees bool) (
 	*coinSelection, error) {
 
@@ -1485,7 +1486,7 @@ func selectInputs(amt btcutil.Amount, coins []*Utxo) (btcutil.Amount, []*Utxo, e
 // change output to fund amt satoshis, adhering to the specified fee rate. The
 // specified fee rate should be expressed in sat/kw for coin selection to
 // function properly.
-func coinSelect(feeRate SatPerKWeight, amt btcutil.Amount,
+func coinSelect(feeRate chainfee.SatPerKWeight, amt btcutil.Amount,
 	coins []*Utxo) ([]*Utxo, btcutil.Amount, error) {
 
 	amtNeeded := amt
@@ -1549,7 +1550,7 @@ func coinSelect(feeRate SatPerKWeight, amt btcutil.Amount,
 // coinSelectSubtractFees attempts to select coins such that we'll spend up to
 // amt in total after fees, adhering to the specified fee rate. The selected
 // coins, the final output and change values are returned.
-func coinSelectSubtractFees(feeRate SatPerKWeight, amt,
+func coinSelectSubtractFees(feeRate chainfee.SatPerKWeight, amt,
 	dustLimit btcutil.Amount, coins []*Utxo) ([]*Utxo, btcutil.Amount,
 	btcutil.Amount, error) {
 
diff --git a/mock.go b/mock.go
index cbcba6463..609b78186 100644
--- a/mock.go
+++ b/mock.go
@@ -17,6 +17,7 @@ import (
 	"github.com/lightningnetwork/lnd/input"
 	"github.com/lightningnetwork/lnd/keychain"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 )
 
 // The block height returned by the mock BlockChainIO's GetBestBlock.
@@ -271,13 +272,13 @@ func (*mockWalletController) IsOurAddress(a btcutil.Address) bool {
 }
 
 func (*mockWalletController) SendOutputs(outputs []*wire.TxOut,
-	_ lnwallet.SatPerKWeight) (*wire.MsgTx, error) {
+	_ chainfee.SatPerKWeight) (*wire.MsgTx, error) {
 
 	return nil, nil
 }
 
 func (*mockWalletController) CreateSimpleTx(outputs []*wire.TxOut,
-	_ lnwallet.SatPerKWeight, _ bool) (*txauthor.AuthoredTx, error) {
+	_ chainfee.SatPerKWeight, _ bool) (*txauthor.AuthoredTx, error) {
 
 	return nil, nil
 }
diff --git a/rpcserver.go b/rpcserver.go
index 1502f3848..4833eb714 100644
--- a/rpcserver.go
+++ b/rpcserver.go
@@ -44,6 +44,7 @@ import (
 	"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
 	"github.com/lightningnetwork/lnd/lntypes"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/macaroons"
 	"github.com/lightningnetwork/lnd/monitoring"
@@ -815,7 +816,7 @@ func addrPairsToOutputs(addrPairs map[string]int64) ([]*wire.TxOut, error) {
 // more addresses specified in the passed payment map. The payment map maps an
 // address to a specified output value to be sent to that address.
 func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
-	feeRate lnwallet.SatPerKWeight) (*chainhash.Hash, error) {
+	feeRate chainfee.SatPerKWeight) (*chainhash.Hash, error) {
 
 	outputs, err := addrPairsToOutputs(paymentMap)
 	if err != nil {
@@ -1000,7 +1001,7 @@ func (r *rpcServer) SendCoins(ctx context.Context,
 
 	// Based on the passed fee related parameters, we'll determine an
 	// appropriate fee rate for this transaction.
-	satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
+	satPerKw := chainfee.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
 	feePerKw, err := sweep.DetermineFeePerKw(
 		r.server.cc.feeEstimator, sweep.FeePreference{
 			ConfTarget: uint32(in.TargetConf),
@@ -1122,7 +1123,7 @@ func (r *rpcServer) SendMany(ctx context.Context,
 
 	// Based on the passed fee related parameters, we'll determine an
 	// appropriate fee rate for this transaction.
-	satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
+	satPerKw := chainfee.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
 	feePerKw, err := sweep.DetermineFeePerKw(
 		r.server.cc.feeEstimator, sweep.FeePreference{
 			ConfTarget: uint32(in.TargetConf),
@@ -1504,7 +1505,7 @@ func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
 
 	// Based on the passed fee related parameters, we'll determine an
 	// appropriate fee rate for the funding transaction.
-	satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
+	satPerKw := chainfee.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
 	feeRate, err := sweep.DetermineFeePerKw(
 		r.server.cc.feeEstimator, sweep.FeePreference{
 			ConfTarget: uint32(in.TargetConf),
@@ -1649,7 +1650,7 @@ func (r *rpcServer) OpenChannelSync(ctx context.Context,
 
 	// Based on the passed fee related parameters, we'll determine an
 	// appropriate fee rate for the funding transaction.
-	satPerKw := lnwallet.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
+	satPerKw := chainfee.SatPerKVByte(in.SatPerByte * 1000).FeePerKWeight()
 	feeRate, err := sweep.DetermineFeePerKw(
 		r.server.cc.feeEstimator, sweep.FeePreference{
 			ConfTarget: uint32(in.TargetConf),
@@ -1847,7 +1848,7 @@ func (r *rpcServer) CloseChannel(in *lnrpc.CloseChannelRequest,
 		// Based on the passed fee related parameters, we'll determine
 		// an appropriate fee rate for the cooperative closure
 		// transaction.
-		satPerKw := lnwallet.SatPerKVByte(
+		satPerKw := chainfee.SatPerKVByte(
 			in.SatPerByte * 1000,
 		).FeePerKWeight()
 		feeRate, err := sweep.DetermineFeePerKw(
diff --git a/server.go b/server.go
index e43ad2db6..b8872e9ef 100644
--- a/server.go
+++ b/server.go
@@ -44,6 +44,7 @@ import (
 	"github.com/lightningnetwork/lnd/lnrpc"
 	"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/nat"
 	"github.com/lightningnetwork/lnd/netann"
@@ -1136,7 +1137,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
 		if cfg.WtClient.SweepFeeRate != 0 {
 			// We expose the sweep fee rate in sat/byte, but the
 			// tower protocol operations on sat/kw.
-			sweepRateSatPerByte := lnwallet.SatPerKVByte(
+			sweepRateSatPerByte := chainfee.SatPerKVByte(
 				1000 * cfg.WtClient.SweepFeeRate,
 			)
 			policy.SweepFeeRate = sweepRateSatPerByte.FeePerKWeight()
@@ -3071,7 +3072,7 @@ type openChanReq struct {
 
 	pushAmt lnwire.MilliSatoshi
 
-	fundingFeePerKw lnwallet.SatPerKWeight
+	fundingFeePerKw chainfee.SatPerKWeight
 
 	private bool
 
diff --git a/sweep/sweeper.go b/sweep/sweeper.go
index 2e3a1e1ca..51400f537 100644
--- a/sweep/sweeper.go
+++ b/sweep/sweeper.go
@@ -16,13 +16,14 @@ import (
 	"github.com/lightningnetwork/lnd/chainntnfs"
 	"github.com/lightningnetwork/lnd/input"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 )
 
 const (
 	// DefaultMaxFeeRate is the default maximum fee rate allowed within the
 	// UtxoSweeper. The current value is equivalent to a fee rate of 10,000
 	// sat/vbyte.
-	DefaultMaxFeeRate = lnwallet.FeePerKwFloor * 1e4
+	DefaultMaxFeeRate = chainfee.FeePerKwFloor * 1e4
 
 	// DefaultFeeRateBucketSize is the default size of fee rate buckets
 	// we'll use when clustering inputs into buckets with similar fee rates
@@ -92,7 +93,7 @@ type pendingInput struct {
 
 	// lastFeeRate is the most recent fee rate used for this input within a
 	// transaction broadcast to the network.
-	lastFeeRate lnwallet.SatPerKWeight
+	lastFeeRate chainfee.SatPerKWeight
 }
 
 // pendingInputs is a type alias for a set of pending inputs.
@@ -101,7 +102,7 @@ type pendingInputs = map[wire.OutPoint]*pendingInput
 // inputCluster is a helper struct to gather a set of pending inputs that should
 // be swept with the specified fee rate.
 type inputCluster struct {
-	sweepFeeRate lnwallet.SatPerKWeight
+	sweepFeeRate chainfee.SatPerKWeight
 	inputs       pendingInputs
 }
 
@@ -126,7 +127,7 @@ type PendingInput struct {
 
 	// LastFeeRate is the most recent fee rate used for the input being
 	// swept within a transaction broadcast to the network.
-	LastFeeRate lnwallet.SatPerKWeight
+	LastFeeRate chainfee.SatPerKWeight
 
 	// BroadcastAttempts is the number of attempts we've made to sweept the
 	// input.
@@ -182,7 +183,7 @@ type UtxoSweeper struct {
 
 	currentOutputScript []byte
 
-	relayFeeRate lnwallet.SatPerKWeight
+	relayFeeRate chainfee.SatPerKWeight
 
 	quit chan struct{}
 	wg   sync.WaitGroup
@@ -197,7 +198,7 @@ type UtxoSweeperConfig struct {
 	// FeeEstimator is used when crafting sweep transactions to estimate
 	// the necessary fee relative to the expected size of the sweep
 	// transaction.
-	FeeEstimator lnwallet.FeeEstimator
+	FeeEstimator chainfee.Estimator
 
 	// PublishTransaction facilitates the process of broadcasting a signed
 	// transaction to the appropriate network.
@@ -235,7 +236,7 @@ type UtxoSweeperConfig struct {
 
 	// MaxFeeRate is the the maximum fee rate allowed within the
 	// UtxoSweeper.
-	MaxFeeRate lnwallet.SatPerKWeight
+	MaxFeeRate chainfee.SatPerKWeight
 
 	// FeeRateBucketSize is the default size of fee rate buckets we'll use
 	// when clustering inputs into buckets with similar fee rates within the
@@ -403,7 +404,7 @@ func (s *UtxoSweeper) SweepInput(input input.Input,
 // feeRateForPreference returns a fee rate for the given fee preference. It
 // ensures that the fee rate respects the bounds of the UtxoSweeper.
 func (s *UtxoSweeper) feeRateForPreference(
-	feePreference FeePreference) (lnwallet.SatPerKWeight, error) {
+	feePreference FeePreference) (chainfee.SatPerKWeight, error) {
 
 	// Ensure a type of fee preference is specified to prevent using a
 	// default below.
@@ -637,10 +638,10 @@ func (s *UtxoSweeper) collector(blockEpochs <-chan *chainntnfs.BlockEpoch) {
 // bucketForFeeReate determines the proper bucket for a fee rate. This is done
 // in order to batch inputs with similar fee rates together.
 func (s *UtxoSweeper) bucketForFeeRate(
-	feeRate lnwallet.SatPerKWeight) lnwallet.SatPerKWeight {
+	feeRate chainfee.SatPerKWeight) chainfee.SatPerKWeight {
 
-	minBucket := s.relayFeeRate + lnwallet.SatPerKWeight(s.cfg.FeeRateBucketSize)
-	return lnwallet.SatPerKWeight(
+	minBucket := s.relayFeeRate + chainfee.SatPerKWeight(s.cfg.FeeRateBucketSize)
+	return chainfee.SatPerKWeight(
 		math.Ceil(float64(feeRate) / float64(minBucket)),
 	)
 }
@@ -650,8 +651,8 @@ func (s *UtxoSweeper) bucketForFeeRate(
 // sweep fee rate, which is determined by calculating the average fee rate of
 // all inputs within that cluster.
 func (s *UtxoSweeper) clusterBySweepFeeRate() []inputCluster {
-	bucketInputs := make(map[lnwallet.SatPerKWeight]pendingInputs)
-	inputFeeRates := make(map[wire.OutPoint]lnwallet.SatPerKWeight)
+	bucketInputs := make(map[chainfee.SatPerKWeight]pendingInputs)
+	inputFeeRates := make(map[wire.OutPoint]chainfee.SatPerKWeight)
 
 	// First, we'll group together all inputs with similar fee rates. This
 	// is done by determining the fee rate bucket they should belong in.
@@ -678,11 +679,11 @@ func (s *UtxoSweeper) clusterBySweepFeeRate() []inputCluster {
 	// calculating the average fee rate of the inputs within each set.
 	inputClusters := make([]inputCluster, 0, len(bucketInputs))
 	for _, inputs := range bucketInputs {
-		var sweepFeeRate lnwallet.SatPerKWeight
+		var sweepFeeRate chainfee.SatPerKWeight
 		for op := range inputs {
 			sweepFeeRate += inputFeeRates[op]
 		}
-		sweepFeeRate /= lnwallet.SatPerKWeight(len(inputs))
+		sweepFeeRate /= chainfee.SatPerKWeight(len(inputs))
 		inputClusters = append(inputClusters, inputCluster{
 			sweepFeeRate: sweepFeeRate,
 			inputs:       inputs,
@@ -836,7 +837,7 @@ func (s *UtxoSweeper) getInputLists(cluster inputCluster,
 
 // sweep takes a set of preselected inputs, creates a sweep tx and publishes the
 // tx. The output address is only marked as used if the publish succeeds.
-func (s *UtxoSweeper) sweep(inputs inputSet, feeRate lnwallet.SatPerKWeight,
+func (s *UtxoSweeper) sweep(inputs inputSet, feeRate chainfee.SatPerKWeight,
 	currentHeight int32) error {
 
 	// Generate an output script if there isn't an unused script available.
diff --git a/sweep/txgenerator.go b/sweep/txgenerator.go
index 4c5c5bc71..f0ef575ca 100644
--- a/sweep/txgenerator.go
+++ b/sweep/txgenerator.go
@@ -11,7 +11,7 @@ import (
 	"github.com/btcsuite/btcutil"
 	"github.com/btcsuite/btcwallet/wallet/txrules"
 	"github.com/lightningnetwork/lnd/input"
-	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 )
 
 var (
@@ -31,7 +31,7 @@ type inputSet []input.Input
 // inputs are skipped. No input sets with a total value after fees below the
 // dust limit are returned.
 func generateInputPartitionings(sweepableInputs []input.Input,
-	relayFeePerKW, feePerKW lnwallet.SatPerKWeight,
+	relayFeePerKW, feePerKW chainfee.SatPerKWeight,
 	maxInputsPerTx int) ([]inputSet, error) {
 
 	// Calculate dust limit based on the P2WPKH output script of the sweep
@@ -116,7 +116,7 @@ func generateInputPartitionings(sweepableInputs []input.Input,
 // minimizing any negative externalities we cause for the Bitcoin system as a
 // whole.
 func getPositiveYieldInputs(sweepableInputs []input.Input, maxInputs int,
-	feePerKW lnwallet.SatPerKWeight) (int, btcutil.Amount) {
+	feePerKW chainfee.SatPerKWeight) (int, btcutil.Amount) {
 
 	var weightEstimate input.TxWeightEstimator
 
@@ -169,7 +169,7 @@ func getPositiveYieldInputs(sweepableInputs []input.Input, maxInputs int,
 
 // createSweepTx builds a signed tx spending the inputs to a the output script.
 func createSweepTx(inputs []input.Input, outputPkScript []byte,
-	currentBlockHeight uint32, feePerKw lnwallet.SatPerKWeight,
+	currentBlockHeight uint32, feePerKw chainfee.SatPerKWeight,
 	signer input.Signer) (*wire.MsgTx, error) {
 
 	inputs, txWeight := getWeightEstimate(inputs)
diff --git a/sweep/walletsweep.go b/sweep/walletsweep.go
index e21457788..38d194887 100644
--- a/sweep/walletsweep.go
+++ b/sweep/walletsweep.go
@@ -9,6 +9,7 @@ import (
 	"github.com/btcsuite/btcutil"
 	"github.com/lightningnetwork/lnd/input"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 )
 
 const (
@@ -27,7 +28,7 @@ type FeePreference struct {
 
 	// FeeRate if non-zero, signals a fee pre fence expressed in the fee
 	// rate expressed in sat/kw for a particular transaction.
-	FeeRate lnwallet.SatPerKWeight
+	FeeRate chainfee.SatPerKWeight
 }
 
 // String returns a human-readable string of the fee preference.
@@ -42,8 +43,8 @@ func (p FeePreference) String() string {
 // an estimator, a confirmation target, and a manual value for sat/byte. A
 // value is chosen based on the two free parameters as one, or both of them can
 // be zero.
-func DetermineFeePerKw(feeEstimator lnwallet.FeeEstimator,
-	feePref FeePreference) (lnwallet.SatPerKWeight, error) {
+func DetermineFeePerKw(feeEstimator chainfee.Estimator,
+	feePref FeePreference) (chainfee.SatPerKWeight, error) {
 
 	switch {
 	// If both values are set, then we'll return an error as we require a
@@ -70,12 +71,12 @@ func DetermineFeePerKw(feeEstimator lnwallet.FeeEstimator,
 	// internally.
 	case feePref.FeeRate != 0:
 		feePerKW := feePref.FeeRate
-		if feePerKW < lnwallet.FeePerKwFloor {
+		if feePerKW < chainfee.FeePerKwFloor {
 			log.Infof("Manual fee rate input of %d sat/kw is "+
 				"too low, using %d sat/kw instead", feePerKW,
-				lnwallet.FeePerKwFloor)
+				chainfee.FeePerKwFloor)
 
-			feePerKW = lnwallet.FeePerKwFloor
+			feePerKW = chainfee.FeePerKwFloor
 		}
 
 		return feePerKW, nil
@@ -152,10 +153,10 @@ type WalletSweepPackage struct {
 // by the delivery address. The sweep transaction will be crafted with the
 // target fee rate, and will use the utxoSource and outpointLocker as sources
 // for wallet funds.
-func CraftSweepAllTx(feeRate lnwallet.SatPerKWeight, blockHeight uint32,
+func CraftSweepAllTx(feeRate chainfee.SatPerKWeight, blockHeight uint32,
 	deliveryAddr btcutil.Address, coinSelectLocker CoinSelectionLocker,
 	utxoSource UtxoSource, outpointLocker OutpointLocker,
-	feeEstimator lnwallet.FeeEstimator,
+	feeEstimator chainfee.Estimator,
 	signer input.Signer) (*WalletSweepPackage, error) {
 
 	// TODO(roasbeef): turn off ATPL as well when available?
diff --git a/watchtower/wtdb/codec.go b/watchtower/wtdb/codec.go
index 4cfa6b6b4..e6b99db6d 100644
--- a/watchtower/wtdb/codec.go
+++ b/watchtower/wtdb/codec.go
@@ -4,7 +4,7 @@ import (
 	"io"
 
 	"github.com/lightningnetwork/lnd/channeldb"
-	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/watchtower/blob"
 	"github.com/lightningnetwork/lnd/watchtower/wtpolicy"
 )
@@ -58,7 +58,7 @@ func ReadElement(r io.Reader, element interface{}) error {
 		}
 
 		e.BlobType = blob.Type(blobType)
-		e.SweepFeeRate = lnwallet.SatPerKWeight(sweepFeeRate)
+		e.SweepFeeRate = chainfee.SatPerKWeight(sweepFeeRate)
 
 	// Type is still unknown to wtdb extensions, fail.
 	default:
diff --git a/watchtower/wtpolicy/policy.go b/watchtower/wtpolicy/policy.go
index db636b684..9c7f5e64e 100644
--- a/watchtower/wtpolicy/policy.go
+++ b/watchtower/wtpolicy/policy.go
@@ -7,6 +7,7 @@ import (
 	"github.com/btcsuite/btcd/wire"
 	"github.com/btcsuite/btcutil"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/watchtower/blob"
 )
 
@@ -27,11 +28,11 @@ const (
 
 	// DefaultSweepFeeRate specifies the fee rate used to construct justice
 	// transactions. The value is expressed in satoshis per kilo-weight.
-	DefaultSweepFeeRate = lnwallet.SatPerKWeight(2500)
+	DefaultSweepFeeRate = chainfee.SatPerKWeight(2500)
 
 	// MinSweepFeeRate is the minimum sweep fee rate a client may use in its
 	// policy, the current value is 4 sat/vbyte.
-	MinSweepFeeRate = lnwallet.SatPerKWeight(1000)
+	MinSweepFeeRate = chainfee.SatPerKWeight(1000)
 )
 
 var (
@@ -97,7 +98,7 @@ type TxPolicy struct {
 	// constructing the justice transaction. All sweep transactions created
 	// for this session must use this value during construction, and the
 	// signatures must implicitly commit to the resulting output values.
-	SweepFeeRate lnwallet.SatPerKWeight
+	SweepFeeRate chainfee.SatPerKWeight
 }
 
 // Policy defines the negotiated parameters for a session between a client and
diff --git a/watchtower/wtwire/create_session.go b/watchtower/wtwire/create_session.go
index 338dda83e..7047ce30e 100644
--- a/watchtower/wtwire/create_session.go
+++ b/watchtower/wtwire/create_session.go
@@ -3,7 +3,7 @@ package wtwire
 import (
 	"io"
 
-	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/watchtower/blob"
 )
 
@@ -34,7 +34,7 @@ type CreateSession struct {
 	// constructing the justice transaction. All sweep transactions created
 	// for this session must use this value during construction, and the
 	// signatures must implicitly commit to the resulting output values.
-	SweepFeeRate lnwallet.SatPerKWeight
+	SweepFeeRate chainfee.SatPerKWeight
 }
 
 // A compile time check to ensure CreateSession implements the wtwire.Message
diff --git a/watchtower/wtwire/wtwire.go b/watchtower/wtwire/wtwire.go
index 1af9433d5..447255602 100644
--- a/watchtower/wtwire/wtwire.go
+++ b/watchtower/wtwire/wtwire.go
@@ -8,7 +8,7 @@ import (
 	"github.com/btcsuite/btcd/btcec"
 	"github.com/btcsuite/btcd/chaincfg/chainhash"
 	"github.com/btcsuite/btcd/wire"
-	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/watchtower/blob"
 )
@@ -74,7 +74,7 @@ func WriteElement(w io.Writer, element interface{}) error {
 			return err
 		}
 
-	case lnwallet.SatPerKWeight:
+	case chainfee.SatPerKWeight:
 		var b [8]byte
 		binary.BigEndian.PutUint64(b[:], uint64(e))
 		if _, err := w.Write(b[:]); err != nil {
@@ -194,12 +194,12 @@ func ReadElement(r io.Reader, element interface{}) error {
 		}
 		*e = bytes
 
-	case *lnwallet.SatPerKWeight:
+	case *chainfee.SatPerKWeight:
 		var b [8]byte
 		if _, err := io.ReadFull(r, b[:]); err != nil {
 			return err
 		}
-		*e = lnwallet.SatPerKWeight(binary.BigEndian.Uint64(b[:]))
+		*e = chainfee.SatPerKWeight(binary.BigEndian.Uint64(b[:]))
 
 	case *ErrorCode:
 		var b [2]byte


Test patch:
diff --git a/breacharbiter_test.go b/breacharbiter_test.go
index 7f471ea2e..0b0a9c3f1 100644
--- a/breacharbiter_test.go
+++ b/breacharbiter_test.go
@@ -31,6 +31,7 @@ import (
 	"github.com/lightningnetwork/lnd/keychain"
 	"github.com/lightningnetwork/lnd/lntest/wait"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/shachain"
 )
@@ -1675,7 +1676,7 @@ func createTestArbiter(t *testing.T, contractBreaches chan *ContractBreachEvent,
 	ba := newBreachArbiter(&BreachConfig{
 		CloseLink:          func(_ *wire.OutPoint, _ htlcswitch.ChannelCloseType) {},
 		DB:                 db,
-		Estimator:          lnwallet.NewStaticFeeEstimator(12500, 0),
+		Estimator:          chainfee.NewStaticEstimator(12500, 0),
 		GenSweepScript:     func() ([]byte, error) { return nil, nil },
 		ContractBreaches:   contractBreaches,
 		Signer:             signer,
@@ -1824,7 +1825,7 @@ func createInitChannels(revocationWindow int) (*lnwallet.LightningChannel, *lnwa
 		return nil, nil, nil, err
 	}
 
-	estimator := lnwallet.NewStaticFeeEstimator(12500, 0)
+	estimator := chainfee.NewStaticEstimator(12500, 0)
 	feePerKw, err := estimator.EstimateFeePerKW(1)
 	if err != nil {
 		return nil, nil, nil, err
diff --git a/fundingmanager_test.go b/fundingmanager_test.go
index 759f783b0..024339d90 100644
--- a/fundingmanager_test.go
+++ b/fundingmanager_test.go
@@ -32,6 +32,7 @@ import (
 	"github.com/lightningnetwork/lnd/lnpeer"
 	"github.com/lightningnetwork/lnd/lnrpc"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 )
 
@@ -218,7 +219,7 @@ func createTestWallet(cdb *channeldb.DB, netParams *chaincfg.Params,
 	notifier chainntnfs.ChainNotifier, wc lnwallet.WalletController,
 	signer input.Signer, keyRing keychain.SecretKeyRing,
 	bio lnwallet.BlockChainIO,
-	estimator lnwallet.FeeEstimator) (*lnwallet.LightningWallet, error) {
+	estimator chainfee.Estimator) (*lnwallet.LightningWallet, error) {
 
 	wallet, err := lnwallet.NewLightningWallet(lnwallet.Config{
 		Database:           cdb,
@@ -247,7 +248,7 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
 	options ...cfgOption) (*testNode, error) {
 
 	netParams := activeNetParams.Params
-	estimator := lnwallet.NewStaticFeeEstimator(62500, 0)
+	estimator := chainfee.NewStaticEstimator(62500, 0)
 
 	chainNotifier := &mockNotifier{
 		oneConfChannel: make(chan *chainntnfs.TxConfirmation, 1),
diff --git a/htlcswitch/link_test.go b/htlcswitch/link_test.go
index 86463ee4d..13dd78693 100644
--- a/htlcswitch/link_test.go
+++ b/htlcswitch/link_test.go
@@ -31,6 +31,7 @@ import (
 	"github.com/lightningnetwork/lnd/lnpeer"
 	"github.com/lightningnetwork/lnd/lntypes"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/ticker"
 )
@@ -1959,7 +1960,7 @@ func TestChannelLinkBandwidthConsistency(t *testing.T) {
 	// incoming HTLCs automatically.
 	coreLink.cfg.HodlMask = hodl.MaskFromFlags(hodl.ExitSettle)
 
-	estimator := lnwallet.NewStaticFeeEstimator(6000, 0)
+	estimator := chainfee.NewStaticEstimator(6000, 0)
 	feePerKw, err := estimator.EstimateFeePerKW(1)
 	if err != nil {
 		t.Fatalf("unable to query fee estimator: %v", err)
@@ -2379,7 +2380,7 @@ func TestChannelLinkBandwidthConsistencyOverflow(t *testing.T) {
 		aliceMsgs              = coreLink.cfg.Peer.(*mockPeer).sentMsgs
 	)
 
-	estimator := lnwallet.NewStaticFeeEstimator(6000, 0)
+	estimator := chainfee.NewStaticEstimator(6000, 0)
 	feePerKw, err := estimator.EstimateFeePerKW(1)
 	if err != nil {
 		t.Fatalf("unable to query fee estimator: %v", err)
@@ -2630,7 +2631,7 @@ func TestChannelLinkTrimCircuitsPending(t *testing.T) {
 
 	// Compute the static fees that will be used to determine the
 	// correctness of Alice's bandwidth when forwarding HTLCs.
-	estimator := lnwallet.NewStaticFeeEstimator(6000, 0)
+	estimator := chainfee.NewStaticEstimator(6000, 0)
 	feePerKw, err := estimator.EstimateFeePerKW(1)
 	if err != nil {
 		t.Fatalf("unable to query fee estimator: %v", err)
@@ -2909,7 +2910,7 @@ func TestChannelLinkTrimCircuitsNoCommit(t *testing.T) {
 
 	// Compute the static fees that will be used to determine the
 	// correctness of Alice's bandwidth when forwarding HTLCs.
-	estimator := lnwallet.NewStaticFeeEstimator(6000, 0)
+	estimator := chainfee.NewStaticEstimator(6000, 0)
 	feePerKw, err := estimator.EstimateFeePerKW(1)
 	if err != nil {
 		t.Fatalf("unable to query fee estimator: %v", err)
@@ -3167,7 +3168,7 @@ func TestChannelLinkBandwidthChanReserve(t *testing.T) {
 		aliceMsgs              = coreLink.cfg.Peer.(*mockPeer).sentMsgs
 	)
 
-	estimator := lnwallet.NewStaticFeeEstimator(6000, 0)
+	estimator := chainfee.NewStaticEstimator(6000, 0)
 	feePerKw, err := estimator.EstimateFeePerKW(1)
 	if err != nil {
 		t.Fatalf("unable to query fee estimator: %v", err)
@@ -3554,8 +3555,8 @@ func TestChannelRetransmission(t *testing.T) {
 // deviates from our current fee by more 10% or more.
 func TestShouldAdjustCommitFee(t *testing.T) {
 	tests := []struct {
-		netFee       lnwallet.SatPerKWeight
-		chanFee      lnwallet.SatPerKWeight
+		netFee       chainfee.SatPerKWeight
+		chanFee      chainfee.SatPerKWeight
 		shouldAdjust bool
 	}{
 
@@ -3837,7 +3838,7 @@ func TestChannelLinkUpdateCommitFee(t *testing.T) {
 
 	// triggerFeeUpdate is a helper closure to determine whether a fee
 	// update was triggered and completed properly.
-	triggerFeeUpdate := func(feeEstimate, newFeeRate lnwallet.SatPerKWeight,
+	triggerFeeUpdate := func(feeEstimate, newFeeRate chainfee.SatPerKWeight,
 		shouldUpdate bool) {
 
 		t.Helper()
@@ -3898,7 +3899,7 @@ func TestChannelLinkUpdateCommitFee(t *testing.T) {
 	// Triggering the link to update the fee of the channel with a fee rate
 	// that exceeds its maximum fee allocation should result in a fee rate
 	// corresponding to the maximum fee allocation.
-	const maxFeeRate lnwallet.SatPerKWeight = 207182320
+	const maxFeeRate chainfee.SatPerKWeight = 207182320
 	triggerFeeUpdate(maxFeeRate+1, maxFeeRate, true)
 }
 
diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go
index 3c11c3fd6..3fb0d9b71 100644
--- a/htlcswitch/test_utils.go
+++ b/htlcswitch/test_utils.go
@@ -32,6 +32,7 @@ import (
 	"github.com/lightningnetwork/lnd/lntest/wait"
 	"github.com/lightningnetwork/lnd/lntypes"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/shachain"
 	"github.com/lightningnetwork/lnd/ticker"
@@ -286,7 +287,7 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte,
 		return nil, nil, nil, err
 	}
 
-	estimator := lnwallet.NewStaticFeeEstimator(6000, 0)
+	estimator := chainfee.NewStaticEstimator(6000, 0)
 	feePerKw, err := estimator.EstimateFeePerKW(1)
 	if err != nil {
 		return nil, nil, nil, err
@@ -1078,7 +1079,7 @@ func newHopNetwork() *hopNetwork {
 	obfuscator := NewMockObfuscator()
 
 	feeEstimator := &mockFeeEstimator{
-		byteFeeIn: make(chan lnwallet.SatPerKWeight),
+		byteFeeIn: make(chan chainfee.SatPerKWeight),
 		quit:      make(chan struct{}),
 	}
 
diff --git a/lnwallet/fee_estimator_test.go b/lnwallet/chainfee/estimator_test.go
similarity index 89%
rename from lnwallet/fee_estimator_test.go
rename to lnwallet/chainfee/estimator_test.go
index c2cfeb52d..b8b8186f9 100644
--- a/lnwallet/fee_estimator_test.go
+++ b/lnwallet/chainfee/estimator_test.go
@@ -1,4 +1,4 @@
-package lnwallet_test
+package chainfee
 
 import (
 	"bytes"
@@ -9,8 +9,6 @@ import (
 	"testing"
 
 	"github.com/btcsuite/btcutil"
-
-	"github.com/lightningnetwork/lnd/lnwallet"
 )
 
 type mockSparseConfFeeSource struct {
@@ -38,9 +36,9 @@ func TestFeeRateTypes(t *testing.T) {
 	const weight = vsize * 4
 
 	// Test the conversion from sat/kw to sat/kb.
-	for feePerKw := lnwallet.SatPerKWeight(250); feePerKw < 10000; feePerKw += 50 {
+	for feePerKw := SatPerKWeight(250); feePerKw < 10000; feePerKw += 50 {
 		feePerKB := feePerKw.FeePerKVByte()
-		if feePerKB != lnwallet.SatPerKVByte(feePerKw*4) {
+		if feePerKB != SatPerKVByte(feePerKw*4) {
 			t.Fatalf("expected %d sat/kb, got %d sat/kb when "+
 				"converting from %d sat/kw", feePerKw*4,
 				feePerKB, feePerKw)
@@ -62,9 +60,9 @@ func TestFeeRateTypes(t *testing.T) {
 	}
 
 	// Test the conversion from sat/kb to sat/kw.
-	for feePerKB := lnwallet.SatPerKVByte(1000); feePerKB < 40000; feePerKB += 1000 {
+	for feePerKB := SatPerKVByte(1000); feePerKB < 40000; feePerKB += 1000 {
 		feePerKw := feePerKB.FeePerKWeight()
-		if feePerKw != lnwallet.SatPerKWeight(feePerKB/4) {
+		if feePerKw != SatPerKWeight(feePerKB/4) {
 			t.Fatalf("expected %d sat/kw, got %d sat/kw when "+
 				"converting from %d sat/kb", feePerKB/4,
 				feePerKw, feePerKB)
@@ -91,9 +89,9 @@ func TestFeeRateTypes(t *testing.T) {
 func TestStaticFeeEstimator(t *testing.T) {
 	t.Parallel()
 
-	const feePerKw = lnwallet.FeePerKwFloor
+	const feePerKw = FeePerKwFloor
 
-	feeEstimator := lnwallet.NewStaticFeeEstimator(feePerKw, 0)
+	feeEstimator := NewStaticEstimator(feePerKw, 0)
 	if err := feeEstimator.Start(); err != nil {
 		t.Fatalf("unable to start fee estimator: %v", err)
 	}
@@ -116,7 +114,7 @@ func TestSparseConfFeeSource(t *testing.T) {
 
 	// Test that GenQueryURL returns the URL as is.
 	url := "test"
-	feeSource := lnwallet.SparseConfFeeSource{URL: url}
+	feeSource := SparseConfFeeSource{URL: url}
 	queryURL := feeSource.GenQueryURL()
 	if queryURL != url {
 		t.Fatalf("expected query URL of %v, got %v", url, queryURL)
@@ -166,7 +164,7 @@ func TestSparseConfFeeSource(t *testing.T) {
 func TestWebAPIFeeEstimator(t *testing.T) {
 	t.Parallel()
 
-	feeFloor := uint32(lnwallet.FeePerKwFloor.FeePerKVByte())
+	feeFloor := uint32(FeePerKwFloor.FeePerKVByte())
 	testCases := []struct {
 		name   string
 		target uint32
@@ -194,7 +192,7 @@ func TestWebAPIFeeEstimator(t *testing.T) {
 		fees: testFees,
 	}
 
-	estimator := lnwallet.NewWebAPIFeeEstimator(feeSource, 10)
+	estimator := NewWebAPIEstimator(feeSource, 10)
 
 	// Test that requesting a fee when no fees have been cached fails.
 	_, err := estimator.EstimateFeePerKW(5)
@@ -210,6 +208,7 @@ func TestWebAPIFeeEstimator(t *testing.T) {
 	defer estimator.Stop()
 
 	for _, tc := range testCases {
+		tc := tc
 		t.Run(tc.name, func(t *testing.T) {
 			est, err := estimator.EstimateFeePerKW(tc.target)
 			if tc.err != "" {
@@ -220,7 +219,7 @@ func TestWebAPIFeeEstimator(t *testing.T) {
 						"fail, instead got: %v", err)
 				}
 			} else {
-				exp := lnwallet.SatPerKVByte(tc.est).FeePerKWeight()
+				exp := SatPerKVByte(tc.est).FeePerKWeight()
 				if err != nil {
 					t.Fatalf("unable to estimate fee for "+
 						"%v block target, got: %v",
diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go
index ef0b5234d..665917cf4 100644
--- a/lnwallet/channel_test.go
+++ b/lnwallet/channel_test.go
@@ -19,6 +19,7 @@ import (
 	"github.com/lightningnetwork/lnd/chainntnfs"
 	"github.com/lightningnetwork/lnd/channeldb"
 	"github.com/lightningnetwork/lnd/input"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 )
 
@@ -456,8 +457,12 @@ func TestCooperativeChannelClosure(t *testing.T) {
 	aliceDeliveryScript := bobsPrivKey[:]
 	bobDeliveryScript := testHdSeed[:]
 
-	aliceFeeRate := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
-	bobFeeRate := SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw)
+	aliceFeeRate := chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	)
+	bobFeeRate := chainfee.SatPerKWeight(
+		bobChannel.channelState.LocalCommitment.FeePerKw,
+	)
 
 	// We'll store with both Alice and Bob creating a new close proposal
 	// with the same fee.
@@ -596,7 +601,9 @@ func TestForceClose(t *testing.T) {
 	// Factoring in the fee rate, Alice's amount should properly reflect
 	// that we've added two additional HTLC to the commitment transaction.
 	totalCommitWeight := input.CommitWeight + (input.HtlcWeight * 2)
-	feePerKw := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
+	feePerKw := chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	)
 	commitFee := feePerKw.FeeForWeight(totalCommitWeight)
 	expectedAmount := (aliceChannel.Capacity / 2) - htlcAmount.ToSatoshis() - commitFee
 	if aliceCommitResolution.SelfOutputSignDesc.Output.Value != int64(expectedAmount) {
@@ -1004,7 +1011,10 @@ func TestHTLCDustLimit(t *testing.T) {
 	// The amount of the HTLC should be above Alice's dust limit and below
 	// Bob's dust limit.
 	htlcSat := (btcutil.Amount(500) + htlcTimeoutFee(
-		SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)))
+		chainfee.SatPerKWeight(
+			aliceChannel.channelState.LocalCommitment.FeePerKw,
+		),
+	))
 	htlcAmount := lnwire.NewMSatFromSatoshis(htlcSat)
 
 	htlc, preimage := createHTLC(0, htlcAmount)
@@ -1102,7 +1112,7 @@ func TestHTLCSigNumber(t *testing.T) {
 	}
 
 	// Calculate two values that will be below and above Bob's dust limit.
-	estimator := NewStaticFeeEstimator(6000, 0)
+	estimator := chainfee.NewStaticEstimator(6000, 0)
 	feePerKw, err := estimator.EstimateFeePerKW(1)
 	if err != nil {
 		t.Fatalf("unable to get fee: %v", err)
@@ -1268,7 +1278,9 @@ func TestChannelBalanceDustLimit(t *testing.T) {
 	aliceBalance := aliceChannel.channelState.LocalCommitment.LocalBalance.ToSatoshis()
 	htlcSat := aliceBalance - defaultFee
 	htlcSat += htlcSuccessFee(
-		SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw),
+		chainfee.SatPerKWeight(
+			aliceChannel.channelState.LocalCommitment.FeePerKw,
+		),
 	)
 
 	htlcAmount := lnwire.NewMSatFromSatoshis(htlcSat)
@@ -1366,7 +1378,7 @@ func TestStateUpdatePersistence(t *testing.T) {
 	}
 
 	// Also add a fee update to the update logs.
-	fee := SatPerKWeight(333)
+	fee := chainfee.SatPerKWeight(333)
 	if err := aliceChannel.UpdateFee(fee); err != nil {
 		t.Fatalf("unable to send fee update")
 	}
@@ -1779,8 +1791,12 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {
 	}
 	defer cleanUp()
 
-	aliceFeeRate := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
-	bobFeeRate := SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw)
+	aliceFeeRate := chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	)
+	bobFeeRate := chainfee.SatPerKWeight(
+		bobChannel.channelState.LocalCommitment.FeePerKw,
+	)
 
 	setDustLimit := func(dustVal btcutil.Amount) {
 		aliceChannel.channelState.LocalChanCfg.DustLimit = dustVal
@@ -1946,7 +1962,7 @@ func TestUpdateFeeAdjustments(t *testing.T) {
 
 	// We'll first try to increase the fee rate 5x, this should be able to
 	// be committed without any issue.
-	newFee := SatPerKWeight(baseFeeRate * 5)
+	newFee := chainfee.SatPerKWeight(baseFeeRate * 5)
 
 	if err := aliceChannel.UpdateFee(newFee); err != nil {
 		t.Fatalf("unable to alice update fee: %v", err)
@@ -1964,7 +1980,7 @@ func TestUpdateFeeAdjustments(t *testing.T) {
 	// We'll now attempt to increase the fee rate 1,000,000x of the base
 	// fee.  This should result in an error as Alice won't be able to pay
 	// this new fee rate.
-	newFee = SatPerKWeight(baseFeeRate * 1000000)
+	newFee = chainfee.SatPerKWeight(baseFeeRate * 1000000)
 	if err := aliceChannel.UpdateFee(newFee); err == nil {
 		t.Fatalf("alice should reject the fee rate")
 	}
@@ -1972,7 +1988,7 @@ func TestUpdateFeeAdjustments(t *testing.T) {
 	// Finally, we'll attempt to adjust the fee down and use a fee which is
 	// smaller than the initial base fee rate. The fee application and
 	// state transition should proceed without issue.
-	newFee = SatPerKWeight(baseFeeRate / 10)
+	newFee = chainfee.SatPerKWeight(baseFeeRate / 10)
 	if err := aliceChannel.UpdateFee(newFee); err != nil {
 		t.Fatalf("unable to alice update fee: %v", err)
 	}
@@ -2048,7 +2064,7 @@ func TestUpdateFeeConcurrentSig(t *testing.T) {
 	}
 
 	// Simulate Alice sending update fee message to bob.
-	fee := SatPerKWeight(333)
+	fee := chainfee.SatPerKWeight(333)
 	if err := aliceChannel.UpdateFee(fee); err != nil {
 		t.Fatalf("unable to send fee update")
 	}
@@ -2084,7 +2100,7 @@ func TestUpdateFeeConcurrentSig(t *testing.T) {
 		t.Fatalf("bob unable to process alice's new commitment: %v", err)
 	}
 
-	if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) == fee {
+	if chainfee.SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) == fee {
 		t.Fatalf("bob's feePerKw was unexpectedly locked in")
 	}
 
@@ -2095,7 +2111,7 @@ func TestUpdateFeeConcurrentSig(t *testing.T) {
 		t.Fatalf("unable to generate bob revocation: %v", err)
 	}
 
-	if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != fee {
+	if chainfee.SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != fee {
 		t.Fatalf("bob's feePerKw was not locked in")
 	}
 }
@@ -2134,7 +2150,7 @@ func TestUpdateFeeSenderCommits(t *testing.T) {
 	}
 
 	// Simulate Alice sending update fee message to bob.
-	fee := SatPerKWeight(333)
+	fee := chainfee.SatPerKWeight(333)
 	aliceChannel.UpdateFee(fee)
 	bobChannel.ReceiveUpdateFee(fee)
 
@@ -2154,7 +2170,9 @@ func TestUpdateFeeSenderCommits(t *testing.T) {
 		t.Fatalf("bob unable to process alice's new commitment: %v", err)
 	}
 
-	if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) == fee {
+	if chainfee.SatPerKWeight(
+		bobChannel.channelState.LocalCommitment.FeePerKw,
+	) == fee {
 		t.Fatalf("bob's feePerKw was unexpectedly locked in")
 	}
 
@@ -2165,7 +2183,9 @@ func TestUpdateFeeSenderCommits(t *testing.T) {
 		t.Fatalf("unable to generate bob revocation: %v", err)
 	}
 
-	if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != fee {
+	if chainfee.SatPerKWeight(
+		bobChannel.channelState.LocalCommitment.FeePerKw,
+	) != fee {
 		t.Fatalf("bob's feePerKw was not locked in")
 	}
 
@@ -2191,7 +2211,9 @@ func TestUpdateFeeSenderCommits(t *testing.T) {
 		t.Fatalf("alice unable to process bob's new commitment: %v", err)
 	}
 
-	if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) == fee {
+	if chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	) == fee {
 		t.Fatalf("alice's feePerKw was unexpectedly locked in")
 	}
 
@@ -2202,7 +2224,9 @@ func TestUpdateFeeSenderCommits(t *testing.T) {
 		t.Fatalf("unable to revoke alice channel: %v", err)
 	}
 
-	if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) != fee {
+	if chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	) != fee {
 		t.Fatalf("alice's feePerKw was not locked in")
 	}
 
@@ -2248,7 +2272,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) {
 	}
 
 	// Simulate Alice sending update fee message to bob
-	fee := SatPerKWeight(333)
+	fee := chainfee.SatPerKWeight(333)
 	aliceChannel.UpdateFee(fee)
 	bobChannel.ReceiveUpdateFee(fee)
 
@@ -2296,7 +2320,9 @@ func TestUpdateFeeReceiverCommits(t *testing.T) {
 		t.Fatalf("alice unable to process bob's new commitment: %v", err)
 	}
 
-	if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) == fee {
+	if chainfee.SatPerKWeight(
+		bobChannel.channelState.LocalCommitment.FeePerKw,
+	) == fee {
 		t.Fatalf("bob's feePerKw was unexpectedly locked in")
 	}
 
@@ -2308,7 +2334,9 @@ func TestUpdateFeeReceiverCommits(t *testing.T) {
 		t.Fatalf("unable to revoke alice channel: %v", err)
 	}
 
-	if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != fee {
+	if chainfee.SatPerKWeight(
+		bobChannel.channelState.LocalCommitment.FeePerKw,
+	) != fee {
 		t.Fatalf("bob's feePerKw was not locked in")
 	}
 
@@ -2333,7 +2361,9 @@ func TestUpdateFeeReceiverCommits(t *testing.T) {
 		t.Fatalf("alice unable to process bob's new commitment: %v", err)
 	}
 
-	if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) == fee {
+	if chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	) == fee {
 		t.Fatalf("alice's feePerKw was unexpectedly locked in")
 	}
 
@@ -2344,7 +2374,9 @@ func TestUpdateFeeReceiverCommits(t *testing.T) {
 		t.Fatalf("unable to generate bob revocation: %v", err)
 	}
 
-	if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) != fee {
+	if chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	) != fee {
 		t.Fatalf("Alice's feePerKw was not locked in")
 	}
 
@@ -2372,7 +2404,7 @@ func TestUpdateFeeReceiverSendsUpdate(t *testing.T) {
 
 	// Since Alice is the channel initiator, she should fail when receiving
 	// fee update
-	fee := SatPerKWeight(333)
+	fee := chainfee.SatPerKWeight(333)
 	err = aliceChannel.ReceiveUpdateFee(fee)
 	if err == nil {
 		t.Fatalf("expected alice to fail receiving fee update")
@@ -2400,9 +2432,9 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
 	defer cleanUp()
 
 	// Simulate Alice sending update fee message to bob.
-	fee1 := SatPerKWeight(333)
-	fee2 := SatPerKWeight(333)
-	fee := SatPerKWeight(333)
+	fee1 := chainfee.SatPerKWeight(333)
+	fee2 := chainfee.SatPerKWeight(333)
+	fee := chainfee.SatPerKWeight(333)
 	aliceChannel.UpdateFee(fee1)
 	aliceChannel.UpdateFee(fee2)
 	aliceChannel.UpdateFee(fee)
@@ -2427,15 +2459,17 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
 		t.Fatalf("bob unable to process alice's new commitment: %v", err)
 	}
 
-	if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) == fee {
+	if chainfee.SatPerKWeight(
+		bobChannel.channelState.LocalCommitment.FeePerKw,
+	) == fee {
 		t.Fatalf("bob's feePerKw was unexpectedly locked in")
 	}
 
 	// Alice sending more fee updates now should not mess up the old fee
 	// they both committed to.
-	fee3 := SatPerKWeight(444)
-	fee4 := SatPerKWeight(555)
-	fee5 := SatPerKWeight(666)
+	fee3 := chainfee.SatPerKWeight(444)
+	fee4 := chainfee.SatPerKWeight(555)
+	fee5 := chainfee.SatPerKWeight(666)
 	aliceChannel.UpdateFee(fee3)
 	aliceChannel.UpdateFee(fee4)
 	aliceChannel.UpdateFee(fee5)
@@ -2450,7 +2484,9 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
 		t.Fatalf("unable to generate bob revocation: %v", err)
 	}
 
-	if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != fee {
+	if chainfee.SatPerKWeight(
+		bobChannel.channelState.LocalCommitment.FeePerKw,
+	) != fee {
 		t.Fatalf("bob's feePerKw was not locked in")
 	}
 
@@ -2475,7 +2511,9 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
 		t.Fatalf("alice unable to process bob's new commitment: %v", err)
 	}
 
-	if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) == fee {
+	if chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	) == fee {
 		t.Fatalf("alice's feePerKw was unexpectedly locked in")
 	}
 
@@ -2486,7 +2524,9 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) {
 		t.Fatalf("unable to revoke alice channel: %v", err)
 	}
 
-	if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) != fee {
+	if chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	) != fee {
 		t.Fatalf("alice's feePerKw was not locked in")
 	}
 
@@ -3869,7 +3909,9 @@ func TestFeeUpdateRejectInsaneFee(t *testing.T) {
 
 	// Next, we'll try to add a fee rate to Alice which is 1,000,000x her
 	// starting fee rate.
-	startingFeeRate := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
+	startingFeeRate := chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	)
 	newFeeRate := startingFeeRate * 1000000
 
 	// Both Alice and Bob should reject this new fee rate as it is far too
@@ -3895,7 +3937,9 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) {
 
 	// First, we'll fetch the current fee rate present within the
 	// commitment transactions.
-	startingFeeRate := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
+	startingFeeRate := chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	)
 
 	// Next, we'll start a commitment update, with Alice sending a new
 	// update to double the fee rate of the commitment.
@@ -4034,10 +4078,14 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) {
 	}
 
 	// Both parties should now have the latest fee rate locked-in.
-	if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) != newFeeRate {
+	if chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	) != newFeeRate {
 		t.Fatalf("alice's feePerKw was not locked in")
 	}
-	if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != newFeeRate {
+	if chainfee.SatPerKWeight(
+		bobChannel.channelState.LocalCommitment.FeePerKw,
+	) != newFeeRate {
 		t.Fatalf("bob's feePerKw was not locked in")
 	}
 
@@ -4118,7 +4166,7 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) {
 
 	// First, we'll fetch the current fee rate present within the
 	// commitment transactions.
-	startingFeeRate := SatPerKWeight(
+	startingFeeRate := chainfee.SatPerKWeight(
 		aliceChannel.channelState.LocalCommitment.FeePerKw,
 	)
 	newFeeRate := startingFeeRate
@@ -4247,10 +4295,14 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) {
 	}
 
 	// Both parties should now have the latest fee rate locked-in.
-	if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) != newFeeRate {
+	if chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	) != newFeeRate {
 		t.Fatalf("alice's feePerKw was not locked in")
 	}
-	if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != newFeeRate {
+	if chainfee.SatPerKWeight(
+		bobChannel.channelState.LocalCommitment.FeePerKw,
+	) != newFeeRate {
 		t.Fatalf("bob's feePerKw was not locked in")
 	}
 
@@ -4272,10 +4324,14 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) {
 	assertLogItems(0, numHTLCs+1)
 
 	// ...and the final fee rate locked in.
-	if SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw) != newFeeRate {
+	if chainfee.SatPerKWeight(
+		aliceChannel.channelState.LocalCommitment.FeePerKw,
+	) != newFeeRate {
 		t.Fatalf("alice's feePerKw was not locked in")
 	}
-	if SatPerKWeight(bobChannel.channelState.LocalCommitment.FeePerKw) != newFeeRate {
+	if chainfee.SatPerKWeight(
+		bobChannel.channelState.LocalCommitment.FeePerKw,
+	) != newFeeRate {
 		t.Fatalf("bob's feePerKw was not locked in")
 	}
 }
@@ -6624,7 +6680,9 @@ func TestChannelMaxFeeRate(t *testing.T) {
 	}
 	defer cleanUp()
 
-	assertMaxFeeRate := func(maxAlloc float64, expFeeRate SatPerKWeight) {
+	assertMaxFeeRate := func(maxAlloc float64,
+		expFeeRate chainfee.SatPerKWeight) {
+
 		maxFeeRate := aliceChannel.MaxFeeRate(maxAlloc)
 		if maxFeeRate != expFeeRate {
 			t.Fatalf("expected max fee rate of %v with max "+
@@ -6636,5 +6694,5 @@ func TestChannelMaxFeeRate(t *testing.T) {
 	assertMaxFeeRate(1.0, 690607734)
 	assertMaxFeeRate(0.001, 690607)
 	assertMaxFeeRate(0.000001, 690)
-	assertMaxFeeRate(0.0000001, FeePerKwFloor)
+	assertMaxFeeRate(0.0000001, chainfee.FeePerKwFloor)
 }
diff --git a/lnwallet/interface_test.go b/lnwallet/interface_test.go
index 04af443fa..7ba6e6de4 100644
--- a/lnwallet/interface_test.go
+++ b/lnwallet/interface_test.go
@@ -40,6 +40,7 @@ import (
 	"github.com/lightningnetwork/lnd/keychain"
 	"github.com/lightningnetwork/lnd/lnwallet"
 	"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 )
 
@@ -166,7 +167,7 @@ func newPkScript(t *testing.T, w *lnwallet.LightningWallet,
 // parties to send on-chain funds to each other.
 func sendCoins(t *testing.T, miner *rpctest.Harness,
 	sender, receiver *lnwallet.LightningWallet, output *wire.TxOut,
-	feeRate lnwallet.SatPerKWeight) *wire.MsgTx {
+	feeRate chainfee.SatPerKWeight) *wire.MsgTx { //nolint:unparam
 
 	t.Helper()
 
@@ -330,7 +331,7 @@ func createTestWallet(tempTestDir string, miningNode *rpctest.Harness,
 		WalletController: wc,
 		Signer:           signer,
 		ChainIO:          bio,
-		FeeEstimator:     lnwallet.NewStaticFeeEstimator(2500, 0),
+		FeeEstimator:     chainfee.NewStaticEstimator(2500, 0),
 		DefaultConstraints: channeldb.ChannelConstraints{
 			DustLimit:        500,
 			MaxPendingAmount: lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin) * 100,
@@ -723,7 +724,7 @@ func testReservationInitiatorBalanceBelowDustCancel(miner *rpctest.Harness,
 		t.Fatalf("unable to create amt: %v", err)
 	}
 
-	feePerKw := lnwallet.SatPerKWeight(
+	feePerKw := chainfee.SatPerKWeight(
 		numBTC * numBTC * btcutil.SatoshiPerBitcoin,
 	)
 	req := &lnwallet.InitFundingReserveMsg{
@@ -2151,7 +2152,7 @@ func testChangeOutputSpendConfirmation(r *rpctest.Harness,
 	//
 	// TODO(wilmer): replace this once SendOutputs easily supports sending
 	// all funds in one transaction.
-	txFeeRate := lnwallet.SatPerKWeight(2500)
+	txFeeRate := chainfee.SatPerKWeight(2500)
 	txFee := btcutil.Amount(14380)
 	output := &wire.TxOut{
 		Value:    int64(aliceBalance - txFee),
@@ -2247,7 +2248,7 @@ func testLastUnusedAddr(miner *rpctest.Harness,
 		if err != nil {
 			t.Fatalf("unable to convert addr to script: %v", err)
 		}
-		feeRate := lnwallet.SatPerKWeight(2500)
+		feeRate := chainfee.SatPerKWeight(2500)
 		output := &wire.TxOut{
 			Value:    1000000,
 			PkScript: addrScript,
@@ -2281,7 +2282,7 @@ func testCreateSimpleTx(r *rpctest.Harness, w *lnwallet.LightningWallet,
 	// The test cases we will run through for all backends.
 	testCases := []struct {
 		outVals []int64
-		feeRate lnwallet.SatPerKWeight
+		feeRate chainfee.SatPerKWeight
 		valid   bool
 	}{
 		{
diff --git a/lnwallet/test_utils.go b/lnwallet/test_utils.go
index efb30ac1d..0aee8aa2f 100644
--- a/lnwallet/test_utils.go
+++ b/lnwallet/test_utils.go
@@ -18,6 +18,7 @@ import (
 	"github.com/lightningnetwork/lnd/channeldb"
 	"github.com/lightningnetwork/lnd/input"
 	"github.com/lightningnetwork/lnd/keychain"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/shachain"
 )
@@ -233,7 +234,7 @@ func CreateTestChannels(tweaklessCommits bool) (
 		return nil, nil, nil, err
 	}
 
-	estimator := NewStaticFeeEstimator(6000, 0)
+	estimator := chainfee.NewStaticEstimator(6000, 0)
 	feePerKw, err := estimator.EstimateFeePerKW(1)
 	if err != nil {
 		return nil, nil, nil, err
diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go
index ed4c533db..035a721fc 100644
--- a/lnwallet/transactions_test.go
+++ b/lnwallet/transactions_test.go
@@ -17,6 +17,7 @@ import (
 	"github.com/lightningnetwork/lnd/channeldb"
 	"github.com/lightningnetwork/lnd/input"
 	"github.com/lightningnetwork/lnd/keychain"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/shachain"
 )
@@ -800,7 +801,7 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
 			height:       test.commitment.CommitHeight,
 			ourBalance:   test.commitment.LocalBalance,
 			theirBalance: test.commitment.RemoteBalance,
-			feePerKw:     SatPerKWeight(test.commitment.FeePerKw),
+			feePerKw:     chainfee.SatPerKWeight(test.commitment.FeePerKw),
 			dustLimit:    tc.dustLimit,
 			isOurs:       true,
 		}
@@ -843,7 +844,7 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
 		// Generate second-level HTLC transactions for HTLCs in
 		// commitment tx.
 		htlcResolutions, err := extractHtlcResolutions(
-			SatPerKWeight(test.commitment.FeePerKw), true, signer,
+			chainfee.SatPerKWeight(test.commitment.FeePerKw), true, signer,
 			htlcs, keys, channel.localChanCfg, channel.remoteChanCfg,
 			commitTx.TxHash(),
 		)
diff --git a/lnwallet/wallet_test.go b/lnwallet/wallet_test.go
index f9a6c0d3a..903f5e4d9 100644
--- a/lnwallet/wallet_test.go
+++ b/lnwallet/wallet_test.go
@@ -5,12 +5,15 @@ import (
 
 	"github.com/btcsuite/btcutil"
 	"github.com/lightningnetwork/lnd/input"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 )
 
 // fundingFee is a helper method that returns the fee estimate used for a tx
 // with the given number of inputs and the optional change output. This matches
 // the estimate done by the wallet.
-func fundingFee(feeRate SatPerKWeight, numInput int, change bool) btcutil.Amount {
+func fundingFee(feeRate chainfee.SatPerKWeight, numInput int, // nolint:unparam
+	change bool) btcutil.Amount {
+
 	var weightEstimate input.TxWeightEstimator
 
 	// All inputs.
@@ -39,7 +42,7 @@ func fundingFee(feeRate SatPerKWeight, numInput int, change bool) btcutil.Amount
 func TestCoinSelect(t *testing.T) {
 	t.Parallel()
 
-	const feeRate = SatPerKWeight(100)
+	const feeRate = chainfee.SatPerKWeight(100)
 	const dust = btcutil.Amount(100)
 
 	type testCase struct {
@@ -185,7 +188,7 @@ func TestCoinSelect(t *testing.T) {
 func TestCoinSelectSubtractFees(t *testing.T) {
 	t.Parallel()
 
-	const feeRate = SatPerKWeight(100)
+	const feeRate = chainfee.SatPerKWeight(100)
 	const dustLimit = btcutil.Amount(1000)
 	const dust = btcutil.Amount(100)
 
diff --git a/peer_test.go b/peer_test.go
index 9db7e7f36..424405fc6 100644
--- a/peer_test.go
+++ b/peer_test.go
@@ -10,7 +10,7 @@ import (
 	"github.com/btcsuite/btcutil"
 	"github.com/lightningnetwork/lnd/chainntnfs"
 	"github.com/lightningnetwork/lnd/htlcswitch"
-	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 )
 
@@ -156,7 +156,7 @@ func TestPeerChannelClosureAcceptFeeInitiator(t *testing.T) {
 			dummyDeliveryScript),
 	}
 
-	estimator := lnwallet.NewStaticFeeEstimator(12500, 0)
+	estimator := chainfee.NewStaticEstimator(12500, 0)
 	feePerKw, err := estimator.EstimateFeePerKW(1)
 	if err != nil {
 		t.Fatalf("unable to query fee estimator: %v", err)
@@ -446,7 +446,7 @@ func TestPeerChannelClosureFeeNegotiationsInitiator(t *testing.T) {
 		msg: respShutdown,
 	}
 
-	estimator := lnwallet.NewStaticFeeEstimator(12500, 0)
+	estimator := chainfee.NewStaticEstimator(12500, 0)
 	initiatorIdealFeeRate, err := estimator.EstimateFeePerKW(1)
 	if err != nil {
 		t.Fatalf("unable to query fee estimator: %v", err)
diff --git a/sweep/fee_estimator_mock_test.go b/sweep/fee_estimator_mock_test.go
index b0510f368..4ca89f0c5 100644
--- a/sweep/fee_estimator_mock_test.go
+++ b/sweep/fee_estimator_mock_test.go
@@ -3,38 +3,38 @@ package sweep
 import (
 	"sync"
 
-	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 )
 
 // mockFeeEstimator implements a mock fee estimator. It closely resembles
 // lnwallet.StaticFeeEstimator with the addition that fees can be changed for
 // testing purposes in a thread safe manner.
 type mockFeeEstimator struct {
-	feePerKW lnwallet.SatPerKWeight
+	feePerKW chainfee.SatPerKWeight
 
-	relayFee lnwallet.SatPerKWeight
+	relayFee chainfee.SatPerKWeight
 
-	blocksToFee map[uint32]lnwallet.SatPerKWeight
+	blocksToFee map[uint32]chainfee.SatPerKWeight
 
 	// A closure that when set is used instead of the
 	// mockFeeEstimator.EstimateFeePerKW method.
-	estimateFeePerKW func(numBlocks uint32) (lnwallet.SatPerKWeight, error)
+	estimateFeePerKW func(numBlocks uint32) (chainfee.SatPerKWeight, error)
 
 	lock sync.Mutex
 }
 
 func newMockFeeEstimator(feePerKW,
-	relayFee lnwallet.SatPerKWeight) *mockFeeEstimator {
+	relayFee chainfee.SatPerKWeight) *mockFeeEstimator {
 
 	return &mockFeeEstimator{
 		feePerKW:    feePerKW,
 		relayFee:    relayFee,
-		blocksToFee: make(map[uint32]lnwallet.SatPerKWeight),
+		blocksToFee: make(map[uint32]chainfee.SatPerKWeight),
 	}
 }
 
 func (e *mockFeeEstimator) updateFees(feePerKW,
-	relayFee lnwallet.SatPerKWeight) {
+	relayFee chainfee.SatPerKWeight) {
 
 	e.lock.Lock()
 	defer e.lock.Unlock()
@@ -44,7 +44,7 @@ func (e *mockFeeEstimator) updateFees(feePerKW,
 }
 
 func (e *mockFeeEstimator) EstimateFeePerKW(numBlocks uint32) (
-	lnwallet.SatPerKWeight, error) {
+	chainfee.SatPerKWeight, error) {
 
 	e.lock.Lock()
 	defer e.lock.Unlock()
@@ -60,7 +60,7 @@ func (e *mockFeeEstimator) EstimateFeePerKW(numBlocks uint32) (
 	return e.feePerKW, nil
 }
 
-func (e *mockFeeEstimator) RelayFeePerKW() lnwallet.SatPerKWeight {
+func (e *mockFeeEstimator) RelayFeePerKW() chainfee.SatPerKWeight {
 	e.lock.Lock()
 	defer e.lock.Unlock()
 
@@ -75,4 +75,4 @@ func (e *mockFeeEstimator) Stop() error {
 	return nil
 }
 
-var _ lnwallet.FeeEstimator = (*mockFeeEstimator)(nil)
+var _ chainfee.Estimator = (*mockFeeEstimator)(nil)
diff --git a/sweep/sweeper_test.go b/sweep/sweeper_test.go
index 623b11f94..69c92daa8 100644
--- a/sweep/sweeper_test.go
+++ b/sweep/sweeper_test.go
@@ -15,6 +15,7 @@ import (
 	"github.com/lightningnetwork/lnd/input"
 	"github.com/lightningnetwork/lnd/keychain"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 )
 
 var (
@@ -99,7 +100,7 @@ func createSweeperTestContext(t *testing.T) *sweeperTestContext {
 
 	backend := newMockBackend(notifier)
 
-	estimator := newMockFeeEstimator(10000, lnwallet.FeePerKwFloor)
+	estimator := newMockFeeEstimator(10000, chainfee.FeePerKwFloor)
 
 	publishChan := make(chan wire.MsgTx, 2)
 	ctx := &sweeperTestContext{
@@ -314,7 +315,7 @@ func assertTxSweepsInputs(t *testing.T, sweepTx *wire.MsgTx,
 // NOTE: This assumes that transactions only have one output, as this is the
 // only type of transaction the UtxoSweeper can create at the moment.
 func assertTxFeeRate(t *testing.T, tx *wire.MsgTx,
-	expectedFeeRate lnwallet.SatPerKWeight, inputs ...input.Input) {
+	expectedFeeRate chainfee.SatPerKWeight, inputs ...input.Input) {
 
 	t.Helper()
 
@@ -994,11 +995,11 @@ func TestDifferentFeePreferences(t *testing.T) {
 	// this to ensure the sweeper can broadcast distinct transactions for
 	// each sweep with a different fee preference.
 	lowFeePref := FeePreference{ConfTarget: 12}
-	lowFeeRate := lnwallet.SatPerKWeight(5000)
+	lowFeeRate := chainfee.SatPerKWeight(5000)
 	ctx.estimator.blocksToFee[lowFeePref.ConfTarget] = lowFeeRate
 
 	highFeePref := FeePreference{ConfTarget: 6}
-	highFeeRate := lnwallet.SatPerKWeight(10000)
+	highFeeRate := chainfee.SatPerKWeight(10000)
 	ctx.estimator.blocksToFee[highFeePref.ConfTarget] = highFeeRate
 
 	input1 := spendableInputs[0]
@@ -1116,7 +1117,7 @@ func TestBumpFeeRBF(t *testing.T) {
 	ctx := createSweeperTestContext(t)
 
 	lowFeePref := FeePreference{ConfTarget: 144}
-	lowFeeRate := lnwallet.FeePerKwFloor
+	lowFeeRate := chainfee.FeePerKwFloor
 	ctx.estimator.blocksToFee[lowFeePref.ConfTarget] = lowFeeRate
 
 	// We'll first try to bump the fee of an output currently unknown to the
diff --git a/sweep/walletsweep_test.go b/sweep/walletsweep_test.go
index 0b96e00b9..acd99c6a5 100644
--- a/sweep/walletsweep_test.go
+++ b/sweep/walletsweep_test.go
@@ -10,6 +10,7 @@ import (
 	"github.com/btcsuite/btcd/wire"
 	"github.com/btcsuite/btcutil"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 )
 
 // TestDetermineFeePerKw tests that given a fee preference, the
@@ -17,8 +18,8 @@ import (
 func TestDetermineFeePerKw(t *testing.T) {
 	t.Parallel()
 
-	defaultFee := lnwallet.SatPerKWeight(999)
-	relayFee := lnwallet.SatPerKWeight(300)
+	defaultFee := chainfee.SatPerKWeight(999)
+	relayFee := chainfee.SatPerKWeight(300)
 
 	feeEstimator := newMockFeeEstimator(defaultFee, relayFee)
 
@@ -35,7 +36,7 @@ func TestDetermineFeePerKw(t *testing.T) {
 
 		// fee is the value the DetermineFeePerKw should return given
 		// the FeePreference above
-		fee lnwallet.SatPerKWeight
+		fee chainfee.SatPerKWeight
 
 		// fail determines if this test case should fail or not.
 		fail bool
@@ -43,9 +44,9 @@ func TestDetermineFeePerKw(t *testing.T) {
 		// A fee rate below the fee rate floor should output the floor.
 		{
 			feePref: FeePreference{
-				FeeRate: lnwallet.SatPerKWeight(99),
+				FeeRate: chainfee.SatPerKWeight(99),
 			},
-			fee: lnwallet.FeePerKwFloor,
+			fee: chainfee.FeePerKwFloor,
 		},
 
 		// A fee rate above the floor, should pass through and return
diff --git a/test_utils.go b/test_utils.go
index 671bc0f46..610cfed63 100644
--- a/test_utils.go
+++ b/test_utils.go
@@ -22,6 +22,7 @@ import (
 	"github.com/lightningnetwork/lnd/input"
 	"github.com/lightningnetwork/lnd/keychain"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/netann"
 	"github.com/lightningnetwork/lnd/shachain"
@@ -214,7 +215,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier,
 		return nil, nil, nil, nil, err
 	}
 
-	estimator := lnwallet.NewStaticFeeEstimator(12500, 0)
+	estimator := chainfee.NewStaticEstimator(12500, 0)
 	feePerKw, err := estimator.EstimateFeePerKW(1)
 	if err != nil {
 		return nil, nil, nil, nil, err
diff --git a/tlv/bench_test.go b/tlv/bench_test.go
index f71a7eb61..132ef784f 100644
--- a/tlv/bench_test.go
+++ b/tlv/bench_test.go
@@ -6,7 +6,7 @@ import (
 	"io/ioutil"
 	"testing"
 
-	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/tlv"
 	"github.com/lightningnetwork/lnd/watchtower/blob"
 	"github.com/lightningnetwork/lnd/watchtower/wtwire"
@@ -19,7 +19,7 @@ type CreateSessionTLV struct {
 	MaxUpdates   uint16
 	RewardBase   uint32
 	RewardRate   uint32
-	SweepFeeRate lnwallet.SatPerKWeight
+	SweepFeeRate chainfee.SatPerKWeight
 
 	tlvStream *tlv.Stream
 }
@@ -48,24 +48,24 @@ func DBlobType(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
 
 // ESatPerKW is an encoder for lnwallet.SatPerKWeight.
 func ESatPerKW(w io.Writer, val interface{}, buf *[8]byte) error {
-	if v, ok := val.(*lnwallet.SatPerKWeight); ok {
+	if v, ok := val.(*chainfee.SatPerKWeight); ok {
 		return tlv.EUint64(w, uint64(*v), buf)
 	}
-	return tlv.NewTypeForEncodingErr(val, "lnwallet.SatPerKWeight")
+	return tlv.NewTypeForEncodingErr(val, "chainfee.SatPerKWeight")
 }
 
 // DSatPerKW is an decoder for lnwallet.SatPerKWeight.
 func DSatPerKW(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
-	if v, ok := val.(*lnwallet.SatPerKWeight); ok {
+	if v, ok := val.(*chainfee.SatPerKWeight); ok {
 		var sat uint64
 		err := tlv.DUint64(r, &sat, buf, l)
 		if err != nil {
 			return err
 		}
-		*v = lnwallet.SatPerKWeight(sat)
+		*v = chainfee.SatPerKWeight(sat)
 		return nil
 	}
-	return tlv.NewTypeForDecodingErr(val, "lnwallet.SatPerKWeight", l, 8)
+	return tlv.NewTypeForDecodingErr(val, "chainfee.SatPerKWeight", l, 8)
 }
 
 // NewCreateSessionTLV initializes a new CreateSessionTLV message.
diff --git a/watchtower/wtclient/backup_task_internal_test.go b/watchtower/wtclient/backup_task_internal_test.go
index cff6f2b86..d845631ce 100644
--- a/watchtower/wtclient/backup_task_internal_test.go
+++ b/watchtower/wtclient/backup_task_internal_test.go
@@ -16,6 +16,7 @@ import (
 	"github.com/lightningnetwork/lnd/input"
 	"github.com/lightningnetwork/lnd/keychain"
 	"github.com/lightningnetwork/lnd/lnwallet"
+	"github.com/lightningnetwork/lnd/lnwallet/chainfee"
 	"github.com/lightningnetwork/lnd/lnwire"
 	"github.com/lightningnetwork/lnd/watchtower/blob"
 	"github.com/lightningnetwork/lnd/watchtower/wtdb"
@@ -86,7 +87,7 @@ func genTaskTest(
 	toLocalAmt int64,
 	toRemoteAmt int64,
 	blobType blob.Type,
-	sweepFeeRate lnwallet.SatPerKWeight,
+	sweepFeeRate chainfee.SatPerKWeight,
 	rewardScript []byte,
 	expSweepAmt int64,
 	expRewardAmt int64,