OpenChannel
OpenChannel attempts to open a singly funded channel specified in the request to a remote peer. Users are able to specify a target number of blocks that the funding transaction should be confirmed in, or a manual fee rate to us for the funding transaction. If neither are specified, then a lax block confirmation target is used. Each OpenStatusUpdate will return the pending channel ID of the in-progress channel. Depending on the arguments specified in the OpenChannelRequest, this pending channel ID can then be used to manually progress the channel funding flow.
Source: lightning.proto
gRPC
info
This is a server-streaming RPC
rpc OpenChannel (OpenChannelRequest) returns (stream OpenStatusUpdate);
REST
HTTP Method | Path |
---|---|
POST | /v1/channels/stream |
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 = {
sat_per_vbyte: <uint64>,
node_pubkey: <bytes>,
node_pubkey_string: <string>,
local_funding_amount: <int64>,
push_sat: <int64>,
target_conf: <int32>,
sat_per_byte: <int64>,
private: <bool>,
min_htlc_msat: <int64>,
remote_csv_delay: <uint32>,
min_confs: <int32>,
spend_unconfirmed: <bool>,
close_address: <string>,
funding_shim: <FundingShim>,
remote_max_value_in_flight_msat: <uint64>,
remote_max_htlcs: <uint32>,
max_local_csv: <uint32>,
commitment_type: <CommitmentType>,
zero_conf: <bool>,
scid_alias: <bool>,
base_fee: <uint64>,
fee_rate: <uint64>,
use_base_fee: <bool>,
use_fee_rate: <bool>,
remote_chan_reserve_sat: <uint64>,
fund_max: <bool>,
memo: <string>,
outpoints: <OutPoint>,
};
let call = client.openChannel(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:
// {
// "chan_pending": <PendingUpdate>,
// "chan_open": <ChannelOpenUpdate>,
// "psbt_fund": <ReadyForPsbtFunding>,
// "pending_chan_id": <bytes>,
// }
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.OpenChannelRequest(
sat_per_vbyte=<uint64>,
node_pubkey=<bytes>,
node_pubkey_string=<string>,
local_funding_amount=<int64>,
push_sat=<int64>,
target_conf=<int32>,
sat_per_byte=<int64>,
private=<bool>,
min_htlc_msat=<int64>,
remote_csv_delay=<uint32>,
min_confs=<int32>,
spend_unconfirmed=<bool>,
close_address=<string>,
funding_shim=<FundingShim>,
remote_max_value_in_flight_msat=<uint64>,
remote_max_htlcs=<uint32>,
max_local_csv=<uint32>,
commitment_type=<CommitmentType>,
zero_conf=<bool>,
scid_alias=<bool>,
base_fee=<uint64>,
fee_rate=<uint64>,
use_base_fee=<bool>,
use_fee_rate=<bool>,
remote_chan_reserve_sat=<uint64>,
fund_max=<bool>,
memo=<string>,
outpoints=<OutPoint>,
)
for response in stub.OpenChannel(request):
print(response)
# {
# "chan_pending": <PendingUpdate>,
# "chan_open": <ChannelOpenUpdate>,
# "psbt_fund": <ReadyForPsbtFunding>,
# "pending_chan_id": <bytes>,
# }
- 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 = {
sat_per_vbyte: <string>, // <uint64>
node_pubkey: <string>, // <bytes> (base64 encoded)
node_pubkey_string: <string>, // <string>
local_funding_amount: <string>, // <int64>
push_sat: <string>, // <int64>
target_conf: <integer>, // <int32>
sat_per_byte: <string>, // <int64>
private: <boolean>, // <bool>
min_htlc_msat: <string>, // <int64>
remote_csv_delay: <integer>, // <uint32>
min_confs: <integer>, // <int32>
spend_unconfirmed: <boolean>, // <bool>
close_address: <string>, // <string>
funding_shim: <object>, // <FundingShim>
remote_max_value_in_flight_msat: <string>, // <uint64>
remote_max_htlcs: <integer>, // <uint32>
max_local_csv: <integer>, // <uint32>
commitment_type: <string>, // <CommitmentType>
zero_conf: <boolean>, // <bool>
scid_alias: <boolean>, // <bool>
base_fee: <string>, // <uint64>
fee_rate: <string>, // <uint64>
use_base_fee: <boolean>, // <bool>
use_fee_rate: <boolean>, // <bool>
remote_chan_reserve_sat: <string>, // <uint64>
fund_max: <boolean>, // <bool>
memo: <string>, // <string>
outpoints: <array>, // <OutPoint>
};
let options = {
url: `https://${REST_HOST}/v1/channels/stream`,
// 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:
// {
// "chan_pending": <object>, // <PendingUpdate>
// "chan_open": <object>, // <ChannelOpenUpdate>
// "psbt_fund": <object>, // <ReadyForPsbtFunding>
// "pending_chan_id": <string>, // <bytes>
// }
// --------------------------
// 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/stream?method=POST`, {
// Work-around for self-signed certificates.
rejectUnauthorized: false,
headers: {
'Grpc-Metadata-Macaroon': fs.readFileSync(MACAROON_PATH).toString('hex'),
},
});
let requestBody = {
sat_per_vbyte: <uint64>, // <uint64>
node_pubkey: <bytes>, // <bytes> (base64 encoded)
node_pubkey_string: <string>, // <string>
local_funding_amount: <int64>, // <int64>
push_sat: <int64>, // <int64>
target_conf: <int32>, // <int32>
sat_per_byte: <int64>, // <int64>
private: <bool>, // <bool>
min_htlc_msat: <int64>, // <int64>
remote_csv_delay: <uint32>, // <uint32>
min_confs: <int32>, // <int32>
spend_unconfirmed: <bool>, // <bool>
close_address: <string>, // <string>
funding_shim: <FundingShim>, // <FundingShim>
remote_max_value_in_flight_msat: <uint64>, // <uint64>
remote_max_htlcs: <uint32>, // <uint32>
max_local_csv: <uint32>, // <uint32>
commitment_type: <CommitmentType>, // <CommitmentType>
zero_conf: <bool>, // <bool>
scid_alias: <bool>, // <bool>
base_fee: <uint64>, // <uint64>
fee_rate: <uint64>, // <uint64>
use_base_fee: <bool>, // <bool>
use_fee_rate: <bool>, // <bool>
remote_chan_reserve_sat: <uint64>, // <uint64>
fund_max: <bool>, // <bool>
memo: <string>, // <string>
outpoints: <OutPoint>, // <OutPoint>
};
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:
// {
// "chan_pending": <object>, // <PendingUpdate>
// "chan_open": <object>, // <ChannelOpenUpdate>
// "psbt_fund": <object>, // <ReadyForPsbtFunding>
// "pending_chan_id": <string>, // <bytes>
// }
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/stream'
macaroon = codecs.encode(open(MACAROON_PATH, 'rb').read(), 'hex')
headers = {'Grpc-Metadata-macaroon': macaroon}
data = {
'sat_per_vbyte': <uint64>,
'node_pubkey': base64.b64encode(<bytes>),
'node_pubkey_string': <string>,
'local_funding_amount': <int64>,
'push_sat': <int64>,
'target_conf': <int32>,
'sat_per_byte': <int64>,
'private': <bool>,
'min_htlc_msat': <int64>,
'remote_csv_delay': <uint32>,
'min_confs': <int32>,
'spend_unconfirmed': <bool>,
'close_address': <string>,
'funding_shim': <FundingShim>,
'remote_max_value_in_flight_msat': <uint64>,
'remote_max_htlcs': <uint32>,
'max_local_csv': <uint32>,
'commitment_type': <CommitmentType>,
'zero_conf': <bool>,
'scid_alias': <bool>,
'base_fee': <uint64>,
'fee_rate': <uint64>,
'use_base_fee': <bool>,
'use_fee_rate': <bool>,
'remote_chan_reserve_sat': <uint64>,
'fund_max': <bool>,
'memo': <string>,
'outpoints': <OutPoint>,
}
r = requests.post(url, headers=headers, stream=True, data=json.dumps(data), verify=TLS_PATH)
for raw_response in r.iter_lines():
json_response = json.loads(raw_response)
print(json_response)
# {
# "chan_pending": <PendingUpdate>,
# "chan_open": <ChannelOpenUpdate>,
# "psbt_fund": <ReadyForPsbtFunding>,
# "pending_chan_id": <bytes>,
# }
$ lncli openchannel --help
NAME:
lncli openchannel - Open a channel to a node or an existing peer.
USAGE:
lncli openchannel [command options] node-key local-amt push-amt
CATEGORY:
Channels
DESCRIPTION:
Attempt to open a new channel to an existing peer with the key node-key
optionally blocking until the channel is 'open'.
One can also connect to a node before opening a new channel to it by
setting its host:port via the --connect argument. For this to work,
the node_key must be provided, rather than the peer_id. This is
optional.
The channel will be initialized with local-amt satoshis locally and
push-amt satoshis for the remote node. Note that the push-amt is
deducted from the specified local-amt which implies that the local-amt
must be greater than the push-amt. Also note that specifying push-amt
means you give that amount to the remote node as part of the channel
opening. Once the channel is open, a channelPoint (txid:vout) of the
funding output is returned.
If the remote peer supports the option upfront shutdown feature bit
(query listpeers to see their supported feature bits), an address to
enforce payout of funds on cooperative close can optionally be provided.
Note that if you set this value, you will not be able to cooperatively
close out to another address.
One can manually set the fee to be used for the funding transaction via
either the --conf_target or --sat_per_vbyte arguments. This is
optional.
One can also specify a short string memo to record some useful
information about the channel using the --memo argument. This is stored
locally only, and is purely for reference. It has no bearing on the
channel's operation. Max allowed length is 500 characters.
OPTIONS:
--node_key value the identity public key of the target node/peer serialized in compressed format
--connect value (optional) the host:port of the target node
--local_amt value the number of satoshis the wallet should commit to the channel (default: 0)
--fundmax if set, the wallet will attempt to commit the maximum possible local amount to the channel. This must not be set at the same time as local_amt
--utxo value a utxo specified as outpoint(tx:idx) which will be used to fund a channel. This flag can be repeatedly used to fund a channel with a selection of utxos. The selected funds can either be entirely spent by specifying the fundmax flag or partially by selecting a fraction of the sum of the outpoints in local_amt
--base_fee_msat value the base fee in milli-satoshis that will be charged for each forwarded HTLC, regardless of payment size (default: 0)
--fee_rate_ppm value the fee rate ppm (parts per million) that will be charged proportionally based on the value of each forwarded HTLC, the lowest possible rate is 0 with a granularity of 0.000001 (millionths) (default: 0)
--push_amt value the number of satoshis to give the remote side as part of the initial commitment state, this is equivalent to first opening a channel and sending the remote party funds, but done all in one step (default: 0)
--block block and wait until the channel is fully open
--conf_target value (optional) the number of blocks that the transaction *should* confirm in, will be used for fee estimation (default: 0)
--sat_per_vbyte value (optional) a manual fee expressed in sat/vbyte that should be used when crafting the transaction (default: 0)
--private make the channel private, such that it won't be announced to the greater network, and nodes other than the two channel endpoints must be explicitly told about it to be able to route through it
--min_htlc_msat value (optional) the minimum value we will require for incoming HTLCs on the channel (default: 0)
--remote_csv_delay value (optional) the number of blocks we will require our channel counterparty to wait before accessing its funds in case of unilateral close. If this is not set, we will scale the value according to the channel size (default: 0)
--max_local_csv value (optional) the maximum number of blocks that we will allow the remote peer to require we wait before accessing our funds in the case of a unilateral close. (default: 0)
--min_confs value (optional) the minimum number of confirmations each one of your outputs used for the funding transaction must satisfy (default: 1)
--close_address value (optional) an address to enforce payout of our funds to on cooperative close. Note that if this value is set on channel open, you will *not* be able to cooperatively close to a different address.
--psbt start an interactive mode that initiates funding through a partially signed bitcoin transaction (PSBT), allowing the channel funds to be added and signed from a hardware or other offline device.
--base_psbt value when using the interactive PSBT mode to open a new channel, use this base64 encoded PSBT as a base and add the new channel output to it instead of creating a new, empty one.
--no_publish when using the interactive PSBT mode to open multiple channels in a batch, this flag instructs lnd to not publish the full batch transaction just yet. For safety reasons this flag should be set for each of the batch's transactions except the very last
--remote_max_value_in_flight_msat value (optional) the maximum value in msat that can be pending within the channel at any given time (default: 0)
--channel_type value (optional) the type of channel to propose to the remote peer ("tweakless", "anchors", "taproot")
--zero_conf (optional) whether a zero-conf channel open should be attempted.
--scid_alias (optional) whether a scid-alias channel type should be negotiated.
--remote_reserve_sats value (optional) the minimum number of satoshis we require the remote node to keep as a direct payment. If not specified, a default of 1% of the channel capacity will be used. (default: 0)
--memo value (optional) a note-to-self containing some useful
information about the channel. This is stored
locally only, and is purely for reference. It
has no bearing on the channel's operation. Max
allowed length is 500 characters
Messages
lnrpc.OpenChannelRequest
Source: lightning.proto
Field | gRPC Type | REST Type | REST Placement |
---|---|---|---|
sat_per_vbyte | uint64 | string | body |
node_pubkey | bytes | string | body |
node_pubkey_string deprecated | string | string | body |
local_funding_amount | int64 | string | body |
push_sat | int64 | string | body |
target_conf | int32 | integer | body |
sat_per_byte deprecated | int64 | string | body |
private | bool | boolean | body |
min_htlc_msat | int64 | string | body |
remote_csv_delay | uint32 | integer | body |
min_confs | int32 | integer | body |
spend_unconfirmed | bool | boolean | body |
close_address | string | string | body |
funding_shim | FundingShim | object | body |
remote_max_value_in_flight_msat | uint64 | string | body |
remote_max_htlcs | uint32 | integer | body |
max_local_csv | uint32 | integer | body |
commitment_type | CommitmentType | string | body |
zero_conf | bool | boolean | body |
scid_alias | bool | boolean | body |
base_fee | uint64 | string | body |
fee_rate | uint64 | string | body |
use_base_fee | bool | boolean | body |
use_fee_rate | bool | boolean | body |
remote_chan_reserve_sat | uint64 | string | body |
fund_max | bool | boolean | body |
memo | string | string | body |
outpoints | OutPoint[] | array | body |
lnrpc.OpenStatusUpdate
Source: lightning.proto
Field | gRPC Type | REST Type |
---|---|---|
chan_pending | PendingUpdate | object |
chan_open | ChannelOpenUpdate | object |
psbt_fund | ReadyForPsbtFunding | object |
pending_chan_id | bytes | string |
Nested Messages
lnrpc.ChannelOpenUpdate
Field | gRPC Type | REST Type |
---|---|---|
channel_point | ChannelPoint | object |
lnrpc.ChannelPoint
Field | gRPC Type | REST Type |
---|---|---|
funding_txid_bytes | bytes | string |
funding_txid_str | string | string |
output_index | uint32 | integer |
lnrpc.ChanPointShim
Field | gRPC Type | REST Type |
---|---|---|
amt | int64 | string |
chan_point | ChannelPoint | object |
local_key | KeyDescriptor | object |
remote_key | bytes | string |
pending_chan_id | bytes | string |
thaw_height | uint32 | integer |
musig2 | bool | boolean |
lnrpc.FundingShim
Field | gRPC Type | REST Type |
---|---|---|
chan_point_shim | ChanPointShim | object |
psbt_shim | PsbtShim | object |
lnrpc.KeyDescriptor
Field | gRPC Type | REST Type |
---|---|---|
raw_key_bytes | bytes | string |
key_loc | KeyLocator | object |
lnrpc.KeyLocator
Field | gRPC Type | REST Type |
---|---|---|
key_family | int32 | integer |
key_index | int32 | integer |
lnrpc.OutPoint
Field | gRPC Type | REST Type |
---|---|---|
txid_bytes | bytes | string |
txid_str | string | string |
output_index | uint32 | integer |
lnrpc.PendingUpdate
Field | gRPC Type | REST Type |
---|---|---|
txid | bytes | string |
output_index | uint32 | integer |
lnrpc.PsbtShim
Field | gRPC Type | REST Type |
---|---|---|
pending_chan_id | bytes | string |
base_psbt | bytes | string |
no_publish | bool | boolean |
lnrpc.ReadyForPsbtFunding
Field | gRPC Type | REST Type |
---|---|---|
funding_address | string | string |
funding_amount | int64 | string |
psbt | bytes | string |
Enums
lnrpc.CommitmentType
Name | Number |
---|---|
UNKNOWN_COMMITMENT_TYPE | 0 |
LEGACY | 1 |
STATIC_REMOTE_KEY | 2 |
ANCHORS | 3 |
SCRIPT_ENFORCED_LEASE | 4 |
SIMPLE_TAPROOT | 5 |
SIMPLE_TAPROOT_OVERLAY | 6 |