BumpFee
BumpFee is an endpoint that allows users to interact with lnd's sweeper directly. It takes an outpoint from an unconfirmed transaction and sends it to the sweeper for potential fee bumping. Depending on whether the outpoint has been registered in the sweeper (an existing input, e.g., an anchor output) or not (a new input, e.g., an unconfirmed wallet utxo), this will either be an RBF or CPFP attempt.
When receiving an input, lnd’s sweeper needs to understand its time sensitivity to make economical fee bumps - internally a fee function is created using the deadline and budget to guide the process. When the deadline is approaching, the fee function will increase the fee rate and perform an RBF.
When a force close happens, all the outputs from the force closing
transaction will be registered in the sweeper. The sweeper will then handle
the creation, publish, and fee bumping of the sweeping transactions.
Everytime a new block comes in, unless the sweeping transaction is
confirmed, an RBF is attempted. To interfere with this automatic process,
users can use BumpFee to specify customized fee rate, budget, deadline, and
whether the sweep should happen immediately. It's recommended to call
ListSweeps
to understand the shape of the existing sweeping transaction
first - depending on the number of inputs in this transaction, the RBF
requirements can be quite different.
This RPC also serves useful when wanting to perform a Child-Pays-For-Parent (CPFP), where the child transaction pays for its parent's fee. This can be done by specifying an outpoint within the low fee transaction that is under the control of the wallet.
Source: walletrpc/walletkit.proto
gRPC
rpc BumpFee (BumpFeeRequest) returns (BumpFeeResponse);
REST
HTTP Method | Path |
---|---|
POST | /v2/wallet/bumpfee |
Code Samples
- gRPC
- REST
- Shell
- Javascript
- Python
const fs = require('fs');
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const GRPC_HOST = 'localhost:10009'
const MACAROON_PATH = 'LND_DIR/data/chain/bitcoin/regtest/admin.macaroon'
const TLS_PATH = 'LND_DIR/tls.cert'
const loaderOptions = {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
};
const packageDefinition = protoLoader.loadSync(['lightning.proto', 'walletrpc/walletkit.proto'], loaderOptions);
const walletrpc = grpc.loadPackageDefinition(packageDefinition).walletrpc;
process.env.GRPC_SSL_CIPHER_SUITES = 'HIGH+ECDSA';
const tlsCert = fs.readFileSync(TLS_PATH);
const sslCreds = grpc.credentials.createSsl(tlsCert);
const macaroon = fs.readFileSync(MACAROON_PATH).toString('hex');
const macaroonCreds = grpc.credentials.createFromMetadataGenerator(function(args, callback) {
let metadata = new grpc.Metadata();
metadata.add('macaroon', macaroon);
callback(null, metadata);
});
let creds = grpc.credentials.combineChannelCredentials(sslCreds, macaroonCreds);
let client = new walletrpc.WalletKit(GRPC_HOST, creds);
let request = {
outpoint: <OutPoint>,
target_conf: <uint32>,
sat_per_byte: <uint32>,
force: <bool>,
sat_per_vbyte: <uint64>,
immediate: <bool>,
budget: <uint64>,
};
client.bumpFee(request, function(err, response) {
console.log(response);
});
// Console output:
// {
// "status": <string>,
// }
import codecs, grpc, os
# Generate the following 2 modules by compiling the walletrpc/walletkit.proto with the grpcio-tools.
# See https://github.com/lightningnetwork/lnd/blob/master/docs/grpc/python.md for instructions.
import walletkit_pb2 as walletrpc, walletkit_pb2_grpc as walletkitstub
GRPC_HOST = 'localhost:10009'
MACAROON_PATH = 'LND_DIR/data/chain/bitcoin/regtest/admin.macaroon'
TLS_PATH = 'LND_DIR/tls.cert'
# create macaroon credentials
macaroon = codecs.encode(open(MACAROON_PATH, 'rb').read(), 'hex')
def metadata_callback(context, callback):
callback([('macaroon', macaroon)], None)
auth_creds = grpc.metadata_call_credentials(metadata_callback)
# create SSL credentials
os.environ['GRPC_SSL_CIPHER_SUITES'] = 'HIGH+ECDSA'
cert = open(TLS_PATH, 'rb').read()
ssl_creds = grpc.ssl_channel_credentials(cert)
# combine macaroon and SSL credentials
combined_creds = grpc.composite_channel_credentials(ssl_creds, auth_creds)
# make the request
channel = grpc.secure_channel(GRPC_HOST, combined_creds)
stub = walletkitstub.WalletKitStub(channel)
request = walletrpc.BumpFeeRequest(
outpoint=<OutPoint>,
target_conf=<uint32>,
sat_per_byte=<uint32>,
force=<bool>,
sat_per_vbyte=<uint64>,
immediate=<bool>,
budget=<uint64>,
)
response = stub.BumpFee(request)
print(response)
# {
# "status": <string>,
# }
- Javascript
- Python
const fs = require('fs');
const request = require('request');
const REST_HOST = 'localhost:8080'
const MACAROON_PATH = 'LND_DIR/data/chain/bitcoin/regtest/admin.macaroon'
let requestBody = {
outpoint: <object>, // <OutPoint>
target_conf: <integer>, // <uint32>
sat_per_byte: <integer>, // <uint32>
force: <boolean>, // <bool>
sat_per_vbyte: <string>, // <uint64>
immediate: <boolean>, // <bool>
budget: <string>, // <uint64>
};
let options = {
url: `https://${REST_HOST}/v2/wallet/bumpfee`,
// Work-around for self-signed certificates.
rejectUnauthorized: false,
json: true,
headers: {
'Grpc-Metadata-macaroon': fs.readFileSync(MACAROON_PATH).toString('hex'),
},
form: JSON.stringify(requestBody),
}
request.post(options, function(error, response, body) {
console.log(body);
});
// Console output:
// {
// "status": <string>, // <string>
// }
import base64, codecs, json, requests
REST_HOST = 'localhost:8080'
MACAROON_PATH = 'LND_DIR/data/chain/bitcoin/regtest/admin.macaroon'
TLS_PATH = 'LND_DIR/tls.cert'
url = f'https://{REST_HOST}/v2/wallet/bumpfee'
macaroon = codecs.encode(open(MACAROON_PATH, 'rb').read(), 'hex')
headers = {'Grpc-Metadata-macaroon': macaroon}
data = {
'outpoint': <OutPoint>,
'target_conf': <uint32>,
'sat_per_byte': <uint32>,
'force': <bool>,
'sat_per_vbyte': <uint64>,
'immediate': <bool>,
'budget': <uint64>,
}
r = requests.post(url, headers=headers, data=json.dumps(data), verify=TLS_PATH)
print(r.json())
# {
# "status": <string>,
# }
$ lncli wallet bumpfee --help
NAME:
lncli wallet bumpfee - Bumps the fee of an arbitrary input/transaction.
USAGE:
lncli wallet bumpfee [command options] outpoint
DESCRIPTION:
BumpFee is an endpoint that allows users to interact with lnd's sweeper
directly. It takes an outpoint from an unconfirmed transaction and
sends it to the sweeper for potential fee bumping. Depending on whether
the outpoint has been registered in the sweeper (an existing input,
e.g., an anchor output) or not (a new input, e.g., an unconfirmed
wallet utxo), this will either be an RBF or CPFP attempt.
When receiving an input, lnd’s sweeper needs to understand its time
sensitivity to make economical fee bumps - internally a fee function is
created using the deadline and budget to guide the process. When the
deadline is approaching, the fee function will increase the fee rate
and perform an RBF.
When a force close happens, all the outputs from the force closing
transaction will be registered in the sweeper. The sweeper will then
handle the creation, publish, and fee bumping of the sweeping
transactions. Everytime a new block comes in, unless the sweeping
transaction is confirmed, an RBF is attempted. To interfere with this
automatic process, users can use BumpFee to specify customized fee
rate, budget, deadline, and whether the sweep should happen
immediately. It's recommended to call listsweeps to understand the
shape of the existing sweeping transaction first - depending on the
number of inputs in this transaction, the RBF requirements can be quite
different.
This RPC also serves useful when wanting to perform a
Child-Pays-For-Parent (CPFP), where the child transaction pays for its
parent's fee. This can be done by specifying an outpoint within the low
fee transaction that is under the control of the wallet.
OPTIONS:
--conf_target value The deadline in number of blocks that the input should be spent within.
When not set, for new inputs, the default value (1008) is used; for
exiting inputs, their current values will be retained. (default: 0)
--sat_per_vbyte value The starting fee rate, expressed in sat/vbyte, that will be used to
spend the input with initially. This value will be used by the
sweeper's fee function as its starting fee rate. When not set, the
sweeper will use the estimated fee rate using the target_conf as the
starting fee rate. (default: 0)
--immediate Whether this input will be swept immediately. When set to true, the
sweeper will sweep this input without waiting for the next batch.
--budget value The max amount in sats that can be used as the fees. Setting this value
greater than the input's value may result in CPFP - one or more wallet
utxos will be used to pay the fees specified by the budget. If not set,
for new inputs, by default 50% of the input's value will be treated as
the budget for fee bumping; for existing inputs, their current budgets
will be retained. (default: 0)
Messages
walletrpc.BumpFeeRequest
Source: walletrpc/walletkit.proto
Field | gRPC Type | REST Type | REST Placement |
---|---|---|---|
outpoint | OutPoint | object | body |
target_conf | uint32 | integer | body |
sat_per_byte deprecated | uint32 | integer | body |
force deprecated | bool | boolean | body |
sat_per_vbyte | uint64 | string | body |
immediate | bool | boolean | body |
budget | uint64 | string | body |
walletrpc.BumpFeeResponse
Source: walletrpc/walletkit.proto
Field | gRPC Type | REST Type |
---|---|---|
status | string | string |
Nested Messages
lnrpc.OutPoint
Field | gRPC Type | REST Type |
---|---|---|
txid_bytes | bytes | string |
txid_str | string | string |
output_index | uint32 | integer |