CloseChannel
CloseChannel attempts to close an active channel identified by its channel outpoint (ChannelPoint). The actions of this method can additionally be augmented to attempt a force close after a timeout period in the case of an inactive peer. If a non-force close (cooperative closure) is requested, then the user can specify either a target number of blocks until the closure transaction is confirmed, or a manual fee rate. If neither are specified, then a default lax, block confirmation target is used.
Source: lightning.proto
gRPC
info
This is a server-streaming RPC
rpc CloseChannel (CloseChannelRequest) returns (stream CloseStatusUpdate);
REST
HTTP Method | Path |
---|---|
DELETE | /v1/channels/{channel_point.funding_txid_str}/{channel_point.output_index} |
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', loaderOptions);
const lnrpc = grpc.loadPackageDefinition(packageDefinition).lnrpc;
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 lnrpc.Lightning(GRPC_HOST, creds);
let request = {
channel_point: <ChannelPoint>,
force: <bool>,
target_conf: <int32>,
sat_per_byte: <int64>,
delivery_address: <string>,
sat_per_vbyte: <uint64>,
max_fee_per_vbyte: <uint64>,
};
let call = client.closeChannel(request);
call.on('data', function(response) {
// A response was received from the server.
console.log(response);
});
call.on('status', function(status) {
// The current status of the stream.
});
call.on('end', function() {
// The server has closed the stream.
});
// Console output:
// {
// "close_pending": <PendingUpdate>,
// "chan_close": <ChannelCloseUpdate>,
// }
import codecs, grpc, os
# Generate the following 2 modules by compiling the lightning.proto with the grpcio-tools.
# See https://github.com/lightningnetwork/lnd/blob/master/docs/grpc/python.md for instructions.
import lightning_pb2 as lnrpc, lightning_pb2_grpc as lightningstub
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 = lightningstub.LightningStub(channel)
request = lnrpc.CloseChannelRequest(
channel_point=<ChannelPoint>,
force=<bool>,
target_conf=<int32>,
sat_per_byte=<int64>,
delivery_address=<string>,
sat_per_vbyte=<uint64>,
max_fee_per_vbyte=<uint64>,
)
for response in stub.CloseChannel(request):
print(response)
# {
# "close_pending": <PendingUpdate>,
# "chan_close": <ChannelCloseUpdate>,
# }
- 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 options = {
url: `https://${REST_HOST}/v1/channels/{channel_point.funding_txid_str}/{channel_point.output_index}`,
// Work-around for self-signed certificates.
rejectUnauthorized: false,
json: true,
headers: {
'Grpc-Metadata-macaroon': fs.readFileSync(MACAROON_PATH).toString('hex'),
},
}
request.delete(options, function(error, response, body) {
console.log(body);
});
// Console output:
// {
// "close_pending": <object>, // <PendingUpdate>
// "chan_close": <object>, // <ChannelCloseUpdate>
// }
// --------------------------
// Example with websockets:
// --------------------------
const WebSocket = require('ws');
const fs = require('fs');
const REST_HOST = 'localhost:8080'
const MACAROON_PATH = 'LND_DIR/data/chain/bitcoin/regtest/admin.macaroon'
let ws = new WebSocket(`wss://${REST_HOST}/v1/channels/{channel_point.funding_txid_str}/{channel_point.output_index}?method=DELETE`, {
// Work-around for self-signed certificates.
rejectUnauthorized: false,
headers: {
'Grpc-Metadata-Macaroon': fs.readFileSync(MACAROON_PATH).toString('hex'),
},
});
let requestBody = {
channel_point: <ChannelPoint>, // <ChannelPoint>
force: <bool>, // <bool>
target_conf: <int32>, // <int32>
sat_per_byte: <int64>, // <int64>
delivery_address: <string>, // <string>
sat_per_vbyte: <uint64>, // <uint64>
max_fee_per_vbyte: <uint64>, // <uint64>
};
ws.on('open', function() {
ws.send(JSON.stringify(requestBody));
});
ws.on('error', function(err) {
console.log('Error: ' + err);
});
ws.on('message', function(body) {
console.log(body);
});
// Console output:
// {
// "close_pending": <object>, // <PendingUpdate>
// "chan_close": <object>, // <ChannelCloseUpdate>
// }
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}/v1/channels/{channel_point.funding_txid_str}/{channel_point.output_index}'
macaroon = codecs.encode(open(MACAROON_PATH, 'rb').read(), 'hex')
headers = {'Grpc-Metadata-macaroon': macaroon}
r = requests.delete(url, headers=headers, stream=True, verify=TLS_PATH)
for raw_response in r.iter_lines():
json_response = json.loads(raw_response)
print(json_response)
# {
# "close_pending": <PendingUpdate>,
# "chan_close": <ChannelCloseUpdate>,
# }
$ lncli closechannel --help
NAME:
lncli closechannel - Close an existing channel.
USAGE:
lncli closechannel [command options] funding_txid [output_index]
CATEGORY:
Channels
DESCRIPTION:
Close an existing channel. The channel can be closed either cooperatively,
or unilaterally (--force).
A unilateral channel closure means that the latest commitment
transaction will be broadcast to the network. As a result, any settled
funds will be time locked for a few blocks before they can be spent.
In the case of a cooperative closure, one can manually set the fee to
be used for the closing transaction via either the --conf_target or
--sat_per_vbyte arguments. This will be the starting value used during
fee negotiation. This is optional.
In the case of a cooperative closure, one can manually set the address
to deliver funds to upon closure. This is optional, and may only be used
if an upfront shutdown address has not already been set. If neither are
set the funds will be delivered to a new wallet address.
To view which funding_txids/output_indexes can be used for a channel close,
see the channel_point values within the listchannels command output.
The format for a channel_point is 'funding_txid:output_index'.
OPTIONS:
--funding_txid value the txid of the channel's funding transaction
--output_index value the output index for the funding output of the funding transaction (default: 0)
--chan_point value (optional) the channel point. If set, funding_txid and output_index flags and positional arguments will be ignored
--force attempt an uncooperative closure
--block block until the channel is closed
--conf_target value (optional) the number of blocks that the transaction *should* confirm in, will be used for fee estimation. If not set, then the conf-target value set in the main lnd config will be used. (default: 0)
--sat_per_vbyte value (optional) a manual fee expressed in sat/vbyte that should be used when crafting the transaction (default: 0)
--delivery_addr value (optional) an address to deliver funds upon cooperative channel closing, may only be used if an upfront shutdown address is not already set
Messages
lnrpc.CloseChannelRequest
Source: lightning.proto
Field | gRPC Type | REST Type | REST Placement |
---|---|---|---|
channel_point | ChannelPoint | object | mixed |
force | bool | boolean | query |
target_conf | int32 | integer | query |
sat_per_byte | int64 | string | query |
delivery_address | string | string | query |
sat_per_vbyte | uint64 | string | query |
max_fee_per_vbyte | uint64 | string | query |
lnrpc.CloseStatusUpdate
Source: lightning.proto
Field | gRPC Type | REST Type |
---|---|---|
close_pending | PendingUpdate | object |
chan_close | ChannelCloseUpdate | object |
Nested Messages
lnrpc.ChannelPoint
Field | gRPC Type | REST Type |
---|---|---|
funding_txid_bytes | bytes | string |
funding_txid_str | string | string |
output_index | uint32 | integer |
lnrpc.PendingUpdate
Field | gRPC Type | REST Type |
---|---|---|
txid | bytes | string |
output_index | uint32 | integer |
lnrpc.ChannelCloseUpdate
Field | gRPC Type | REST Type |
---|---|---|
closing_txid | bytes | string |
success | bool | boolean |