lightning 9.9.1 → 9.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/unit-test.yml +2 -2
- package/CHANGELOG.md +8 -0
- package/grpc/protos/lightning.proto +75 -0
- package/lnd_methods/info/get_route_to_destination.js +1 -1
- package/lnd_methods/invoices/create_hodl_invoice.js +29 -1
- package/lnd_methods/invoices/create_invoice.js +29 -1
- package/lnd_methods/onchain/open_channel.js +36 -5
- package/package.json +6 -5
- package/test/lnd_methods/onchain/test_open_channel.js +15 -0
|
@@ -11,10 +11,10 @@ jobs:
|
|
|
11
11
|
strategy:
|
|
12
12
|
matrix:
|
|
13
13
|
os: [ubuntu-latest]
|
|
14
|
-
node: ['
|
|
14
|
+
node: ['16', '18', '20']
|
|
15
15
|
steps:
|
|
16
16
|
- uses: actions/checkout@v2
|
|
17
17
|
- uses: actions/setup-node@v2
|
|
18
18
|
- run: npm install
|
|
19
19
|
- name: Run unit tests
|
|
20
|
-
run: npm
|
|
20
|
+
run: npm run unit-tests
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## 9.11.0
|
|
4
|
+
|
|
5
|
+
- `openChannel`: Add `inputs` to select inputs for channel open funding
|
|
6
|
+
|
|
7
|
+
## 9.10.0
|
|
8
|
+
|
|
9
|
+
- `createInvoice`, `createHodlInvoice`: Add `routes` to customize the hop hints
|
|
10
|
+
|
|
3
11
|
## 9.9.1
|
|
4
12
|
|
|
5
13
|
- `openChannel`: Add `is_trusted_funding` to support skipping confirmation wait
|
|
@@ -2128,6 +2128,76 @@ message BatchOpenChannel {
|
|
|
2128
2128
|
the remote peer supports explicit channel negotiation.
|
|
2129
2129
|
*/
|
|
2130
2130
|
CommitmentType commitment_type = 9;
|
|
2131
|
+
|
|
2132
|
+
/*
|
|
2133
|
+
The maximum amount of coins in millisatoshi that can be pending within
|
|
2134
|
+
the channel. It only applies to the remote party.
|
|
2135
|
+
*/
|
|
2136
|
+
uint64 remote_max_value_in_flight_msat = 10;
|
|
2137
|
+
|
|
2138
|
+
/*
|
|
2139
|
+
The maximum number of concurrent HTLCs we will allow the remote party to add
|
|
2140
|
+
to the commitment transaction.
|
|
2141
|
+
*/
|
|
2142
|
+
uint32 remote_max_htlcs = 11;
|
|
2143
|
+
|
|
2144
|
+
/*
|
|
2145
|
+
Max local csv is the maximum csv delay we will allow for our own commitment
|
|
2146
|
+
transaction.
|
|
2147
|
+
*/
|
|
2148
|
+
uint32 max_local_csv = 12;
|
|
2149
|
+
|
|
2150
|
+
/*
|
|
2151
|
+
If this is true, then a zero-conf channel open will be attempted.
|
|
2152
|
+
*/
|
|
2153
|
+
bool zero_conf = 13;
|
|
2154
|
+
|
|
2155
|
+
/*
|
|
2156
|
+
If this is true, then an option-scid-alias channel-type open will be
|
|
2157
|
+
attempted.
|
|
2158
|
+
*/
|
|
2159
|
+
bool scid_alias = 14;
|
|
2160
|
+
|
|
2161
|
+
/*
|
|
2162
|
+
The base fee charged regardless of the number of milli-satoshis sent.
|
|
2163
|
+
*/
|
|
2164
|
+
uint64 base_fee = 15;
|
|
2165
|
+
|
|
2166
|
+
/*
|
|
2167
|
+
The fee rate in ppm (parts per million) that will be charged in
|
|
2168
|
+
proportion of the value of each forwarded HTLC.
|
|
2169
|
+
*/
|
|
2170
|
+
uint64 fee_rate = 16;
|
|
2171
|
+
|
|
2172
|
+
/*
|
|
2173
|
+
If use_base_fee is true the open channel announcement will update the
|
|
2174
|
+
channel base fee with the value specified in base_fee. In the case of
|
|
2175
|
+
a base_fee of 0 use_base_fee is needed downstream to distinguish whether
|
|
2176
|
+
to use the default base fee value specified in the config or 0.
|
|
2177
|
+
*/
|
|
2178
|
+
bool use_base_fee = 17;
|
|
2179
|
+
|
|
2180
|
+
/*
|
|
2181
|
+
If use_fee_rate is true the open channel announcement will update the
|
|
2182
|
+
channel fee rate with the value specified in fee_rate. In the case of
|
|
2183
|
+
a fee_rate of 0 use_fee_rate is needed downstream to distinguish whether
|
|
2184
|
+
to use the default fee rate value specified in the config or 0.
|
|
2185
|
+
*/
|
|
2186
|
+
bool use_fee_rate = 18;
|
|
2187
|
+
|
|
2188
|
+
/*
|
|
2189
|
+
The number of satoshis we require the remote peer to reserve. This value,
|
|
2190
|
+
if specified, must be above the dust limit and below 20% of the channel
|
|
2191
|
+
capacity.
|
|
2192
|
+
*/
|
|
2193
|
+
uint64 remote_chan_reserve_sat = 19;
|
|
2194
|
+
|
|
2195
|
+
/*
|
|
2196
|
+
An optional note-to-self to go along with the channel containing some
|
|
2197
|
+
useful information. This is only ever stored locally and in no way impacts
|
|
2198
|
+
the channel's operation.
|
|
2199
|
+
*/
|
|
2200
|
+
string memo = 20;
|
|
2131
2201
|
}
|
|
2132
2202
|
|
|
2133
2203
|
message BatchOpenChannelResponse {
|
|
@@ -2290,6 +2360,11 @@ message OpenChannelRequest {
|
|
|
2290
2360
|
the channel's operation.
|
|
2291
2361
|
*/
|
|
2292
2362
|
string memo = 27;
|
|
2363
|
+
|
|
2364
|
+
/*
|
|
2365
|
+
A list of selected outpoints that are allocated for channel funding.
|
|
2366
|
+
*/
|
|
2367
|
+
repeated OutPoint outpoints = 28;
|
|
2293
2368
|
}
|
|
2294
2369
|
message OpenStatusUpdate {
|
|
2295
2370
|
oneof update {
|
|
@@ -7,6 +7,7 @@ const {returnResult} = require('asyncjs-util');
|
|
|
7
7
|
|
|
8
8
|
const {createChainAddress} = require('./../address');
|
|
9
9
|
const {isLnd} = require('./../../lnd_requests');
|
|
10
|
+
const {routeHintFromRoute} = require('./../../lnd_requests');
|
|
10
11
|
|
|
11
12
|
const hexAsBuffer = hex => !!hex ? Buffer.from(hex, 'hex') : undefined;
|
|
12
13
|
const {isArray} = Array;
|
|
@@ -41,6 +42,13 @@ const type = 'invoices';
|
|
|
41
42
|
[is_including_private_channels]: <Invoice Includes Private Channels Bool>
|
|
42
43
|
lnd: <Authenticated LND API Object>
|
|
43
44
|
[mtokens]: <Millitokens String>
|
|
45
|
+
[routes]: [[{
|
|
46
|
+
[base_fee_mtokens]: <Base Routing Fee In Millitokens String>
|
|
47
|
+
[channel]: <Standard Format Channel Id String>
|
|
48
|
+
[cltv_delta]: <CLTV Blocks Delta Number>
|
|
49
|
+
[fee_rate]: <Fee Rate In Millitokens Per Million Number>
|
|
50
|
+
public_key: <Forward Edge Public Key Hex String>
|
|
51
|
+
}]]
|
|
44
52
|
[tokens]: <Tokens Number>
|
|
45
53
|
}
|
|
46
54
|
|
|
@@ -65,6 +73,10 @@ module.exports = (args, cbk) => {
|
|
|
65
73
|
return cbk([400, 'ExpectedInvoicesLndToCreateHodlInvoice']);
|
|
66
74
|
}
|
|
67
75
|
|
|
76
|
+
if (!!args.routes && !isArray(args.routes)) {
|
|
77
|
+
return cbk([400, 'ExpectedArrayOfHopHintPathsForRoutes']);
|
|
78
|
+
}
|
|
79
|
+
|
|
68
80
|
return cbk();
|
|
69
81
|
},
|
|
70
82
|
|
|
@@ -80,6 +92,20 @@ module.exports = (args, cbk) => {
|
|
|
80
92
|
return createChainAddress({format, lnd: args.lnd}, cbk);
|
|
81
93
|
}],
|
|
82
94
|
|
|
95
|
+
// Determine the route hints
|
|
96
|
+
hints: ['validate', ({}, cbk) => {
|
|
97
|
+
// Exit early when there are no route hints for the invoice
|
|
98
|
+
if (!args.routes) {
|
|
99
|
+
return cbk();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const hints = args.routes.map(route => {
|
|
103
|
+
return {hop_hints: routeHintFromRoute({route}).hops};
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
return cbk(null, hints);
|
|
107
|
+
}],
|
|
108
|
+
|
|
83
109
|
// Generate id if needed
|
|
84
110
|
invoiceId: ['validate', ({}, cbk) => {
|
|
85
111
|
if (!!args.id) {
|
|
@@ -97,8 +123,9 @@ module.exports = (args, cbk) => {
|
|
|
97
123
|
// Add invoice
|
|
98
124
|
addInvoice: [
|
|
99
125
|
'addAddress',
|
|
126
|
+
'hints',
|
|
100
127
|
'invoiceId',
|
|
101
|
-
({addAddress, invoiceId}, cbk) =>
|
|
128
|
+
({addAddress, hints, invoiceId}, cbk) =>
|
|
102
129
|
{
|
|
103
130
|
const fallbackAddress = !addAddress ? undefined : addAddress.address;
|
|
104
131
|
const createdAt = new Date();
|
|
@@ -117,6 +144,7 @@ module.exports = (args, cbk) => {
|
|
|
117
144
|
hash: Buffer.from(invoiceId.id, 'hex'),
|
|
118
145
|
memo: args.description,
|
|
119
146
|
private: !!args.is_including_private_channels,
|
|
147
|
+
route_hints: hints || undefined,
|
|
120
148
|
value: args.tokens || undefined,
|
|
121
149
|
value_msat: args.mtokens || undefined,
|
|
122
150
|
},
|
|
@@ -6,6 +6,7 @@ const {createChainAddress} = require('./../address');
|
|
|
6
6
|
const getInvoice = require('./get_invoice');
|
|
7
7
|
const {isLnd} = require('./../../lnd_requests');
|
|
8
8
|
const {mtokensAmount} = require('./../../bolt00');
|
|
9
|
+
const {routeHintFromRoute} = require('./../../lnd_requests');
|
|
9
10
|
|
|
10
11
|
const defaultExpirySec = 60 * 60 * 3;
|
|
11
12
|
const hexAsBuffer = hex => !!hex ? Buffer.from(hex, 'hex') : undefined;
|
|
@@ -36,6 +37,13 @@ const type = 'default';
|
|
|
36
37
|
lnd: <Authenticated LND API Object>
|
|
37
38
|
[secret]: <Payment Preimage Hex String>
|
|
38
39
|
[mtokens]: <Millitokens String>
|
|
40
|
+
[routes]: [[{
|
|
41
|
+
[base_fee_mtokens]: <Base Routing Fee In Millitokens String>
|
|
42
|
+
[channel]: <Standard Format Channel Id String>
|
|
43
|
+
[cltv_delta]: <CLTV Blocks Delta Number>
|
|
44
|
+
[fee_rate]: <Fee Rate In Millitokens Per Million Number>
|
|
45
|
+
public_key: <Forward Edge Public Key Hex String>
|
|
46
|
+
}]]
|
|
39
47
|
[tokens]: <Tokens Number>
|
|
40
48
|
}
|
|
41
49
|
|
|
@@ -86,6 +94,10 @@ module.exports = (args, cbk) => {
|
|
|
86
94
|
}
|
|
87
95
|
}
|
|
88
96
|
|
|
97
|
+
if (!!args.routes && !isArray(args.routes)) {
|
|
98
|
+
return cbk([400, 'ExpectedArrayOfHopHintPathsForRoutes']);
|
|
99
|
+
}
|
|
100
|
+
|
|
89
101
|
return cbk();
|
|
90
102
|
},
|
|
91
103
|
|
|
@@ -101,6 +113,20 @@ module.exports = (args, cbk) => {
|
|
|
101
113
|
return createChainAddress({format, lnd: args.lnd}, cbk);
|
|
102
114
|
}],
|
|
103
115
|
|
|
116
|
+
// Determine the route hints
|
|
117
|
+
hints: ['validate', ({}, cbk) => {
|
|
118
|
+
// Exit early when there are no route hints for the invoice
|
|
119
|
+
if (!args.routes) {
|
|
120
|
+
return cbk();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const hints = args.routes.map(route => {
|
|
124
|
+
return {hop_hints: routeHintFromRoute({route}).hops};
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return cbk(null, hints);
|
|
128
|
+
}],
|
|
129
|
+
|
|
104
130
|
// Determine the value of the invoice
|
|
105
131
|
mtokens: ['validate', ({}, cbk) => {
|
|
106
132
|
// Exit early when there are no mtokens
|
|
@@ -119,9 +145,10 @@ module.exports = (args, cbk) => {
|
|
|
119
145
|
// Add invoice
|
|
120
146
|
addInvoice: [
|
|
121
147
|
'addAddress',
|
|
148
|
+
'hints',
|
|
122
149
|
'mtokens',
|
|
123
150
|
'preimage',
|
|
124
|
-
({addAddress, mtokens, preimage}, cbk) =>
|
|
151
|
+
({addAddress, hints, mtokens, preimage}, cbk) =>
|
|
125
152
|
{
|
|
126
153
|
const fallbackAddress = !addAddress ? String() : addAddress.address;
|
|
127
154
|
const createdAt = new Date();
|
|
@@ -137,6 +164,7 @@ module.exports = (args, cbk) => {
|
|
|
137
164
|
memo: args.description,
|
|
138
165
|
private: !!args.is_including_private_channels,
|
|
139
166
|
r_preimage: preimage || undefined,
|
|
167
|
+
route_hints: hints || undefined,
|
|
140
168
|
value_msat: mtokens,
|
|
141
169
|
},
|
|
142
170
|
(err, response) => {
|
|
@@ -8,11 +8,11 @@ const anchors = 'ANCHORS';
|
|
|
8
8
|
const defaultMinConfs = 1;
|
|
9
9
|
const defaultMinHtlcMtokens = '1';
|
|
10
10
|
const errMemoLength = /^provided memo \(.*\) is of length \d*, exceeds (\d*)$/;
|
|
11
|
+
const {isArray} = Array;
|
|
11
12
|
const minChannelTokens = 20000;
|
|
12
13
|
const method = 'openChannel';
|
|
13
14
|
const type = 'default';
|
|
14
15
|
|
|
15
|
-
|
|
16
16
|
/** Open a new channel.
|
|
17
17
|
|
|
18
18
|
The capacity of the channel is set with local_tokens
|
|
@@ -23,6 +23,10 @@ const type = 'default';
|
|
|
23
23
|
|
|
24
24
|
External funding requires LND compiled with `walletrpc` build tag
|
|
25
25
|
|
|
26
|
+
`is_trusted_funding` is not supported on LND 0.15.0 and below and requires
|
|
27
|
+
`--protocol.option-scid-alias` and `--protocol.zero-conf` set on both sides
|
|
28
|
+
as well as a channel open request listener to accept the trusted funding.
|
|
29
|
+
|
|
26
30
|
`base_fee_mtokens` is not supported on LND 0.15.5 and below
|
|
27
31
|
`fee_rate` is not supported on LND 0.15.5 and below
|
|
28
32
|
|
|
@@ -30,9 +34,7 @@ const type = 'default';
|
|
|
30
34
|
|
|
31
35
|
`description` is not supported on LND 0.16.4 and below
|
|
32
36
|
|
|
33
|
-
`
|
|
34
|
-
`--protocol.option-scid-alias` and `--protocol.zero-conf` set on both sides
|
|
35
|
-
as well as a channel open request listener to accept the trusted funding.
|
|
37
|
+
`inputs` is not supported on LND 0.16.4 and below
|
|
36
38
|
|
|
37
39
|
{
|
|
38
40
|
[base_fee_mtokens]: <Routing Base Fee Millitokens Charged String>
|
|
@@ -41,6 +43,10 @@ const type = 'default';
|
|
|
41
43
|
[description]: <Immutable Channel Description String>
|
|
42
44
|
[fee_rate]: <Routing Fee Rate In Millitokens Per Million Number>
|
|
43
45
|
[give_tokens]: <Tokens to Gift To Partner Number> // Defaults to zero
|
|
46
|
+
[inputs]: [{
|
|
47
|
+
transaction_id: <Fund With Unspent Transaction Id Hex String>
|
|
48
|
+
transaction_vout: <Fund With Unspent Transaction Output Index Number>
|
|
49
|
+
}]
|
|
44
50
|
[is_max_funding]: <Use Maximal Chain Funds For Local Funding Bool>
|
|
45
51
|
[is_private]: <Channel is Private Bool> // Defaults to false
|
|
46
52
|
[is_trusted_funding]: <Accept Funding as Trusted Bool>
|
|
@@ -76,6 +82,10 @@ module.exports = (args, cbk) => {
|
|
|
76
82
|
return cbk([400, 'ExpectedLargerChannelSizeForChannelOpen']);
|
|
77
83
|
}
|
|
78
84
|
|
|
85
|
+
if (!!args.inputs && !isArray(args.inputs)) {
|
|
86
|
+
return cbk([400, 'ExpectedArrayOfTransactionOutpointsAsInputs']);
|
|
87
|
+
}
|
|
88
|
+
|
|
79
89
|
if (!args.partner_public_key) {
|
|
80
90
|
return cbk([400, 'ExpectedPartnerPublicKeyForChannelOpen']);
|
|
81
91
|
}
|
|
@@ -106,8 +116,28 @@ module.exports = (args, cbk) => {
|
|
|
106
116
|
return cbk(null, args.min_confirmations);
|
|
107
117
|
}],
|
|
108
118
|
|
|
119
|
+
// Determine which inputs should be used to fund the channel
|
|
120
|
+
outpoints: ['validate', ({}, cbk) => {
|
|
121
|
+
// Exit early when there are no specific UTXOs to spend
|
|
122
|
+
if (!args.inputs) {
|
|
123
|
+
return cbk();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const utxos = args.inputs.map(input => ({
|
|
127
|
+
output_index: input.transaction_vout,
|
|
128
|
+
txid_str: input.transaction_id,
|
|
129
|
+
}));
|
|
130
|
+
|
|
131
|
+
return cbk(null, utxos);
|
|
132
|
+
}],
|
|
133
|
+
|
|
109
134
|
// Open the channel
|
|
110
|
-
openChannel: [
|
|
135
|
+
openChannel: [
|
|
136
|
+
'connect',
|
|
137
|
+
'minConfs',
|
|
138
|
+
'outpoints',
|
|
139
|
+
({minConfs, outpoints}, cbk) =>
|
|
140
|
+
{
|
|
111
141
|
let isAnnounced = false;
|
|
112
142
|
|
|
113
143
|
const options = {
|
|
@@ -120,6 +150,7 @@ module.exports = (args, cbk) => {
|
|
|
120
150
|
min_confs: minConfs,
|
|
121
151
|
min_htlc_msat: args.min_htlc_mtokens || defaultMinHtlcMtokens,
|
|
122
152
|
node_pubkey: Buffer.from(args.partner_public_key, 'hex'),
|
|
153
|
+
outpoints: outpoints || undefined,
|
|
123
154
|
private: !!args.is_private,
|
|
124
155
|
remote_csv_delay: args.partner_csv_delay || undefined,
|
|
125
156
|
spend_unconfirmed: !minConfs,
|
package/package.json
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
"url": "https://github.com/alexbosworth/lightning/issues"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@grpc/grpc-js": "1.
|
|
10
|
+
"@grpc/grpc-js": "1.9.0",
|
|
11
11
|
"@grpc/proto-loader": "0.7.8",
|
|
12
12
|
"@types/express": "4.17.17",
|
|
13
|
-
"@types/node": "20.4.
|
|
13
|
+
"@types/node": "20.4.6",
|
|
14
14
|
"@types/request": "2.48.8",
|
|
15
15
|
"@types/ws": "8.5.5",
|
|
16
16
|
"async": "3.2.4",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"invoices": "3.0.0",
|
|
27
27
|
"psbt": "3.0.0",
|
|
28
28
|
"tiny-secp256k1": "2.2.3",
|
|
29
|
-
"type-fest": "4.
|
|
29
|
+
"type-fest": "4.1.0"
|
|
30
30
|
},
|
|
31
31
|
"description": "Lightning Network client library",
|
|
32
32
|
"devDependencies": {
|
|
@@ -52,11 +52,12 @@
|
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
54
|
"test": "npx nyc@15.1.0 node --experimental-test-coverage --test && npm run test:types",
|
|
55
|
-
"test:types": "tsd"
|
|
55
|
+
"test:types": "tsd",
|
|
56
|
+
"unit-tests": "node --test && npm run test:types"
|
|
56
57
|
},
|
|
57
58
|
"tsd": {
|
|
58
59
|
"directory": "test/typescript"
|
|
59
60
|
},
|
|
60
61
|
"types": "index.d.ts",
|
|
61
|
-
"version": "9.
|
|
62
|
+
"version": "9.11.0"
|
|
62
63
|
}
|
|
@@ -121,6 +121,11 @@ const tests = [
|
|
|
121
121
|
description: 'A public key is required',
|
|
122
122
|
error: [400, 'ExpectedPartnerPublicKeyForChannelOpen'],
|
|
123
123
|
},
|
|
124
|
+
{
|
|
125
|
+
args: makeArgs({inputs: 'inputs'}),
|
|
126
|
+
description: 'A channel is opened with a tx id set',
|
|
127
|
+
error: [400, 'ExpectedArrayOfTransactionOutpointsAsInputs'],
|
|
128
|
+
},
|
|
124
129
|
{
|
|
125
130
|
args: makeArgs({
|
|
126
131
|
public_key: Buffer.alloc(33).toString('hex'),
|
|
@@ -129,6 +134,16 @@ const tests = [
|
|
|
129
134
|
description: 'A peer is connected before opening',
|
|
130
135
|
expected: {transaction_id: '04030201', transaction_vout: 0},
|
|
131
136
|
},
|
|
137
|
+
{
|
|
138
|
+
args: makeArgs({
|
|
139
|
+
inputs: [{
|
|
140
|
+
transaction_id: Buffer.alloc(32).toString('hex'),
|
|
141
|
+
transaction_vout: 0,
|
|
142
|
+
}],
|
|
143
|
+
}),
|
|
144
|
+
description: 'A channel is opened with a tx id set',
|
|
145
|
+
expected: {transaction_id: '04030201', transaction_vout: 0},
|
|
146
|
+
},
|
|
132
147
|
{
|
|
133
148
|
args: makeArgs({}),
|
|
134
149
|
description: 'A channel is opened',
|