lightning 10.11.1 → 10.13.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/CHANGELOG.md +9 -0
- package/README.md +2 -0
- package/grpc/protos/lightning.proto +13 -2
- package/index.js +2 -0
- package/lnd_methods/index.js +2 -0
- package/lnd_methods/info/subscribe_to_graph.d.ts +4 -0
- package/lnd_methods/info/subscribe_to_graph.js +5 -0
- package/lnd_methods/macaroon/methods.json +4 -0
- package/lnd_methods/offchain/update_routing_fees.js +23 -3
- package/lnd_methods/onchain/create_funded_psbt.js +167 -0
- package/lnd_methods/onchain/index.js +2 -0
- package/lnd_responses/rpc_channel_update_as_update.js +9 -0
- package/package.json +4 -4
- package/test/lnd_methods/info/test_subscribe_to_graph.js +2 -0
- package/test/lnd_methods/offchain/test_update_routing_fees.js +16 -0
- package/test/lnd_methods/onchain/test_create_funded_psbt.js +130 -0
- package/test/lnd_responses/test_rpc_channel_update_as_update.js +17 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## 10.13.0
|
|
4
|
+
|
|
5
|
+
- `subscribeToGraph`: Add support for `inbound_base_discount_mtokens` and
|
|
6
|
+
`inbound_rate_discount`
|
|
7
|
+
|
|
8
|
+
## 10.12.0
|
|
9
|
+
|
|
10
|
+
- `createFundedPsbt`: Add method to create a funded PSBT given inputs/outputs
|
|
11
|
+
|
|
3
12
|
## 10.11.1
|
|
4
13
|
|
|
5
14
|
- `getChannel`, `getNetworkGraph`, `getNode`: Add
|
package/README.md
CHANGED
|
@@ -103,6 +103,8 @@ variables set:
|
|
|
103
103
|
new watchtower.
|
|
104
104
|
- [createChainAddress](https://github.com/alexbosworth/ln-service#createchainaddress): Generate
|
|
105
105
|
a chain address to receive on-chain funds.
|
|
106
|
+
- [createFundedPsbt](https://github.com/alexbosworth/ln-service#createfundedpsbt):
|
|
107
|
+
Create a funded PSBT given inputs and outputs
|
|
106
108
|
- [createHodlInvoice](https://github.com/alexbosworth/ln-service#createhodlinvoice): Make a new
|
|
107
109
|
off-chain invoice that will not automatically accept payment.
|
|
108
110
|
- [createInvoice](https://github.com/alexbosworth/ln-service#createinvoice): Make a new off-chain
|
|
@@ -4369,6 +4369,16 @@ message FeeReportResponse {
|
|
|
4369
4369
|
uint64 month_fee_sum = 4;
|
|
4370
4370
|
}
|
|
4371
4371
|
|
|
4372
|
+
message InboundFee {
|
|
4373
|
+
// The inbound base fee charged regardless of the number of milli-satoshis
|
|
4374
|
+
// received in the channel. By default, only negative values are accepted.
|
|
4375
|
+
int32 base_fee_msat = 1;
|
|
4376
|
+
|
|
4377
|
+
// The effective inbound fee rate in micro-satoshis (parts per million).
|
|
4378
|
+
// By default, only negative values are accepted.
|
|
4379
|
+
int32 fee_rate_ppm = 2;
|
|
4380
|
+
}
|
|
4381
|
+
|
|
4372
4382
|
message PolicyUpdateRequest {
|
|
4373
4383
|
oneof scope {
|
|
4374
4384
|
// If set, then this update applies to all currently active channels.
|
|
@@ -4402,8 +4412,9 @@ message PolicyUpdateRequest {
|
|
|
4402
4412
|
// If true, min_htlc_msat is applied.
|
|
4403
4413
|
bool min_htlc_msat_specified = 8;
|
|
4404
4414
|
|
|
4405
|
-
|
|
4406
|
-
|
|
4415
|
+
// Optional inbound fee. If unset, the previously set value will be
|
|
4416
|
+
// retained [EXPERIMENTAL].
|
|
4417
|
+
InboundFee inbound_fee = 10;
|
|
4407
4418
|
}
|
|
4408
4419
|
|
|
4409
4420
|
enum UpdateFailure {
|
package/index.js
CHANGED
|
@@ -10,6 +10,7 @@ const {changePassword} = require('./lnd_methods');
|
|
|
10
10
|
const {closeChannel} = require('./lnd_methods');
|
|
11
11
|
const {connectWatchtower} = require('./lnd_methods');
|
|
12
12
|
const {createChainAddress} = require('./lnd_methods');
|
|
13
|
+
const {createFundedPsbt} = require('./lnd_methods');
|
|
13
14
|
const {createHodlInvoice} = require('./lnd_methods');
|
|
14
15
|
const {createInvoice} = require('./lnd_methods');
|
|
15
16
|
const {createSeed} = require('./lnd_methods');
|
|
@@ -169,6 +170,7 @@ module.exports = {
|
|
|
169
170
|
closeChannel,
|
|
170
171
|
connectWatchtower,
|
|
171
172
|
createChainAddress,
|
|
173
|
+
createFundedPsbt,
|
|
172
174
|
createHodlInvoice,
|
|
173
175
|
createInvoice,
|
|
174
176
|
createSeed,
|
package/lnd_methods/index.js
CHANGED
|
@@ -9,6 +9,7 @@ const {changePassword} = require('./unauthenticated');
|
|
|
9
9
|
const {closeChannel} = require('./onchain');
|
|
10
10
|
const {connectWatchtower} = require('./offchain');
|
|
11
11
|
const {createChainAddress} = require('./address');
|
|
12
|
+
const {createFundedPsbt} = require('./onchain');
|
|
12
13
|
const {createHodlInvoice} = require('./invoices');
|
|
13
14
|
const {createInvoice} = require('./invoices');
|
|
14
15
|
const {createSeed} = require('./unauthenticated');
|
|
@@ -167,6 +168,7 @@ module.exports = {
|
|
|
167
168
|
closeChannel,
|
|
168
169
|
connectWatchtower,
|
|
169
170
|
createChainAddress,
|
|
171
|
+
createFundedPsbt,
|
|
170
172
|
createHodlInvoice,
|
|
171
173
|
createInvoice,
|
|
172
174
|
createSeed,
|
|
@@ -19,6 +19,10 @@ export type SubscribeToGraphChannelUpdatedEvent = {
|
|
|
19
19
|
min_htlc_mtokens: string;
|
|
20
20
|
/** Announcing Public Key, Target Public Key */
|
|
21
21
|
public_keys: [string, string];
|
|
22
|
+
/** Source Base Fee Reduction String */
|
|
23
|
+
inbound_base_discount_mtokens: string;
|
|
24
|
+
/** Source Per Million Rate Reduction Number */
|
|
25
|
+
inbound_rate_discount: number;
|
|
22
26
|
/** Channel Transaction Id */
|
|
23
27
|
transaction_id: string;
|
|
24
28
|
/** Channel Transaction Output Index */
|
|
@@ -18,6 +18,9 @@ const type = 'default';
|
|
|
18
18
|
|
|
19
19
|
Requires `info:read` permission
|
|
20
20
|
|
|
21
|
+
`inbound_base_discount_mtokens` is not supported on LND 0.17.5 and below
|
|
22
|
+
`inbound_rate_discount` is not supported on LND 0.17.5 and below
|
|
23
|
+
|
|
21
24
|
{
|
|
22
25
|
lnd: <Authenticated LND API Object>
|
|
23
26
|
}
|
|
@@ -45,6 +48,8 @@ const type = 'default';
|
|
|
45
48
|
cltv_delta: <Channel CLTV Delta Number>
|
|
46
49
|
fee_rate: <Channel Fee Rate In Millitokens Per Million Number>
|
|
47
50
|
id: <Standard Format Channel Id String>
|
|
51
|
+
inbound_base_discount_mtokens: <Source Specific Base Fee Reduction String>
|
|
52
|
+
inbound_rate_discount: <Source Specific Per Million Rate Reduction Number>
|
|
48
53
|
is_disabled: <Channel Is Disabled Bool>
|
|
49
54
|
[max_htlc_mtokens]: <Channel Maximum HTLC Millitokens String>
|
|
50
55
|
min_htlc_mtokens: <Channel Minimum HTLC Millitokens String>
|
|
@@ -90,8 +90,29 @@ module.exports = (args, cbk) => {
|
|
|
90
90
|
return cbk(null, tokensAsMtokens(args.base_fee_tokens));
|
|
91
91
|
}],
|
|
92
92
|
|
|
93
|
+
// Determine the inbound fee discount policy
|
|
94
|
+
inboundFee: ['validate', ({}, cbk) => {
|
|
95
|
+
const inboundBase = args.inbound_base_discount_mtokens;
|
|
96
|
+
const inboundRate = args.inbound_rate_discount;
|
|
97
|
+
|
|
98
|
+
// Exit early when there is no inbound policy defined
|
|
99
|
+
if (inboundBase === undefined && inboundRate === undefined) {
|
|
100
|
+
return cbk();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Convert discounts into the surcharges format
|
|
104
|
+
return cbk(null, {
|
|
105
|
+
base_fee_msat: surcharge(inboundBase),
|
|
106
|
+
fee_rate_ppm: surcharge(inboundRate)
|
|
107
|
+
});
|
|
108
|
+
}],
|
|
109
|
+
|
|
93
110
|
// Set the routing fee policy
|
|
94
|
-
updateFees: [
|
|
111
|
+
updateFees: [
|
|
112
|
+
'baseFeeMillitokens',
|
|
113
|
+
'inboundFee',
|
|
114
|
+
({baseFeeMillitokens, inboundFee}, cbk) =>
|
|
115
|
+
{
|
|
95
116
|
const id = args.transaction_id || undefined;
|
|
96
117
|
const rate = args.fee_rate === undefined ? defaultRate : args.fee_rate;
|
|
97
118
|
const vout = args.transaction_vout;
|
|
@@ -108,8 +129,7 @@ module.exports = (args, cbk) => {
|
|
|
108
129
|
chan_point: !isGlobal ? chan : undefined,
|
|
109
130
|
fee_rate: rate / feeRatio,
|
|
110
131
|
global: isGlobal || undefined,
|
|
111
|
-
|
|
112
|
-
inbound_fee_rate_ppm: surcharge(args.inbound_rate_discount),
|
|
132
|
+
inbound_fee: inboundFee,
|
|
113
133
|
max_htlc_msat: args.max_htlc_mtokens || undefined,
|
|
114
134
|
min_htlc_msat: args.min_htlc_mtokens || undefined,
|
|
115
135
|
min_htlc_msat_specified: !!args.min_htlc_mtokens,
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
const asyncAuto = require('async/auto');
|
|
2
|
+
const {createPsbt} = require('psbt');
|
|
3
|
+
const {returnResult} = require('asyncjs-util');
|
|
4
|
+
|
|
5
|
+
const {isLnd} = require('./../../lnd_requests');
|
|
6
|
+
|
|
7
|
+
const bufferAsHex = buffer => buffer.toString('hex');
|
|
8
|
+
const defaultChangeType = 'CHANGE_ADDRESS_TYPE_P2TR';
|
|
9
|
+
const defaultConfirmationTarget = 6;
|
|
10
|
+
const errorUnsupported = 'transaction template missing, need to specify either PSBT or raw TX template';
|
|
11
|
+
const hexAsBuffer = hex => Buffer.from(hex, 'hex');
|
|
12
|
+
const indexNotFound = -1;
|
|
13
|
+
const {isBuffer} = Buffer;
|
|
14
|
+
const method = 'fundPsbt';
|
|
15
|
+
const strategy = type => !type ? undefined : `STRATEGY_${type.toUpperCase()}`;
|
|
16
|
+
const type = 'wallet';
|
|
17
|
+
const unconfirmedConfirmationsCount = 0;
|
|
18
|
+
|
|
19
|
+
/** Create an unsigned funded PSBT given inputs or outputs
|
|
20
|
+
|
|
21
|
+
When specifying local inputs, they must be locked before using
|
|
22
|
+
|
|
23
|
+
`utxo_selection` methods: 'largest', 'random'
|
|
24
|
+
|
|
25
|
+
Requires `onchain:write` permission
|
|
26
|
+
|
|
27
|
+
Requires LND built with `walletrpc` tag
|
|
28
|
+
|
|
29
|
+
This method is not supported on LND 0.17.5 or below
|
|
30
|
+
|
|
31
|
+
{
|
|
32
|
+
[fee_tokens_per_vbyte]: <Chain Fee Tokens Per Virtual Byte Number>
|
|
33
|
+
[inputs]: [{
|
|
34
|
+
[sequence]: <Sequence Number>
|
|
35
|
+
transaction_id: <Unspent Transaction Id Hex String>
|
|
36
|
+
transaction_vout: <Unspent Transaction Output Index Number>
|
|
37
|
+
}]
|
|
38
|
+
lnd: <Authenticated LND API Object>
|
|
39
|
+
[min_confirmations]: <Select Inputs With Minimum Confirmations Number>
|
|
40
|
+
[outputs]: [{
|
|
41
|
+
[is_change]: <Use This Output For Change Bool>
|
|
42
|
+
script: <Output Script Hex String>
|
|
43
|
+
tokens: <Send Tokens Tokens Number>
|
|
44
|
+
}]
|
|
45
|
+
[target_confirmations]: <Blocks To Wait for Confirmation Number>
|
|
46
|
+
[timelock]: <Spendable Lock Time on Transaction Number>
|
|
47
|
+
[utxo_selection]: <Select Inputs Using Selection Methodology Type String>
|
|
48
|
+
[version]: <Transaction Version Number>
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@returns via cbk or Promise
|
|
52
|
+
{
|
|
53
|
+
psbt: <Unsigned PSBT Hex String>
|
|
54
|
+
}
|
|
55
|
+
*/
|
|
56
|
+
module.exports = (args, cbk) => {
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
return asyncAuto({
|
|
59
|
+
// Check arguments
|
|
60
|
+
validate: cbk => {
|
|
61
|
+
if (!isLnd({method, type, lnd: args.lnd})) {
|
|
62
|
+
return cbk([400, 'ExpectedAuthenticatedLndToCreateFundedPsbt']);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return cbk();
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
// Determine the change type
|
|
69
|
+
change: ['validate', ({}, cbk) => {
|
|
70
|
+
const changeIndex = (args.outputs || []).findIndex(n => !!n.is_change);
|
|
71
|
+
|
|
72
|
+
// Exit early when there is no change defined
|
|
73
|
+
if (changeIndex !== indexNotFound) {
|
|
74
|
+
return cbk(null, {existing_output_index: changeIndex});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// When there is no change output specified, add a change output
|
|
78
|
+
return cbk(null, {add: true});
|
|
79
|
+
}],
|
|
80
|
+
|
|
81
|
+
// Determine the fee setting for the funded PSBT
|
|
82
|
+
fee: ['validate', ({}, cbk) => {
|
|
83
|
+
// Exit early when the fee is directly specified
|
|
84
|
+
if (!!args.fee_tokens_per_vbyte) {
|
|
85
|
+
return cbk(null, {fee_tokens_per_vbyte: args.fee_tokens_per_vbyte});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Exit early when the confirmation target is directly specified
|
|
89
|
+
if (!!args.target_confirmations) {
|
|
90
|
+
return cbk(null, {target_confirmations: args.target_confirmations});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Use the default confirmations target when there's no preference
|
|
94
|
+
return cbk(null, {target_confirmations: defaultConfirmationTarget});
|
|
95
|
+
}],
|
|
96
|
+
|
|
97
|
+
// Construct the PSBT that is needed for coin select type funding
|
|
98
|
+
funding: ['validate', ({}, cbk) => {
|
|
99
|
+
const {psbt} = createPsbt({
|
|
100
|
+
outputs: args.outputs || [],
|
|
101
|
+
timelock: args.timelock,
|
|
102
|
+
utxos: (args.inputs || []).map(input => ({
|
|
103
|
+
id: input.transaction_id,
|
|
104
|
+
sequence: input.sequence,
|
|
105
|
+
vout: input.transaction_vout,
|
|
106
|
+
})),
|
|
107
|
+
version: args.version,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return cbk(null, hexAsBuffer(psbt));
|
|
111
|
+
}],
|
|
112
|
+
|
|
113
|
+
// Determine the minimum confirmations for UTXOs to select
|
|
114
|
+
minConfs: ['validate', ({}, cbk) => {
|
|
115
|
+
// Exit early when using unconfirmed UTXOs is explicitly specified
|
|
116
|
+
if (args.min_confirmations === unconfirmedConfirmationsCount) {
|
|
117
|
+
return cbk(null, unconfirmedConfirmationsCount);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return cbk(null, args.min_confirmations || undefined);
|
|
121
|
+
}],
|
|
122
|
+
|
|
123
|
+
// Create the funded PSBT using the coin select strategy
|
|
124
|
+
fund: [
|
|
125
|
+
'change',
|
|
126
|
+
'fee',
|
|
127
|
+
'funding',
|
|
128
|
+
'minConfs',
|
|
129
|
+
({change, fee, funding, minConfs}, cbk) =>
|
|
130
|
+
{
|
|
131
|
+
return args.lnd[type][method]({
|
|
132
|
+
change_type: defaultChangeType,
|
|
133
|
+
coin_select: {
|
|
134
|
+
add: change.add,
|
|
135
|
+
psbt: funding,
|
|
136
|
+
existing_output_index: change.existing_output_index,
|
|
137
|
+
},
|
|
138
|
+
coin_selection_strategy: strategy(args.utxo_selection),
|
|
139
|
+
min_confs: minConfs,
|
|
140
|
+
sat_per_vbyte: fee.fee_tokens_per_vbyte,
|
|
141
|
+
spend_unconfirmed: minConfs === unconfirmedConfirmationsCount,
|
|
142
|
+
target_conf: fee.target_confirmations,
|
|
143
|
+
},
|
|
144
|
+
(err, res) => {
|
|
145
|
+
if (!!err && err.details === errorUnsupported) {
|
|
146
|
+
return cbk([501, 'CreateFundedPsbtMethodNotSupported']);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!!err) {
|
|
150
|
+
return cbk([503, 'UnexpectedErrorCreatingFundedPsbt', {err}]);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!res) {
|
|
154
|
+
return cbk([503, 'ExpectedResultWhenCreatingFundedPsbt']);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!isBuffer(res.funded_psbt)) {
|
|
158
|
+
return cbk([503, 'ExpectedFundedTransactionPsbtToBeCreated']);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return cbk(null, {psbt: bufferAsHex(res.funded_psbt)});
|
|
162
|
+
});
|
|
163
|
+
}],
|
|
164
|
+
},
|
|
165
|
+
returnResult({reject, resolve, of: 'fund'}, cbk));
|
|
166
|
+
});
|
|
167
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const broadcastChainTransaction = require('./broadcast_chain_transaction');
|
|
2
2
|
const cancelPendingChannel = require('./cancel_pending_channel');
|
|
3
3
|
const closeChannel = require('./close_channel');
|
|
4
|
+
const createFundedPsbt = require('./create_funded_psbt');
|
|
4
5
|
const deleteChainTransaction = require('./delete_chain_transaction');
|
|
5
6
|
const fundPendingChannels = require('./fund_pending_channels');
|
|
6
7
|
const fundPsbt = require('./fund_psbt');
|
|
@@ -44,6 +45,7 @@ module.exports = {
|
|
|
44
45
|
broadcastChainTransaction,
|
|
45
46
|
cancelPendingChannel,
|
|
46
47
|
closeChannel,
|
|
48
|
+
createFundedPsbt,
|
|
47
49
|
deleteChainTransaction,
|
|
48
50
|
fundPendingChannels,
|
|
49
51
|
fundPsbt,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const {chanFormat} = require('bolt07');
|
|
2
2
|
|
|
3
|
+
const asDiscount = fee => !fee ? 0 : -fee;
|
|
3
4
|
const bufferAsHex = buffer => buffer.toString('hex');
|
|
4
5
|
const emptyTxId = Buffer.alloc(32);
|
|
5
6
|
const {isBuffer} = Buffer;
|
|
@@ -20,6 +21,8 @@ const now = () => new Date().toISOString();
|
|
|
20
21
|
disabled: <Forwarding is Disabled Bool>
|
|
21
22
|
fee_base_msat: <Forwarding Base Fee Millitokens String>
|
|
22
23
|
fee_rate_milli_msat: <Forwarding Fee Rate Per Million String>
|
|
24
|
+
inbound_fee_base_msat: <Inbound Fee Base Number>
|
|
25
|
+
inbound_fee_rate_milli_msat: <Inbound Fee Base Number>
|
|
23
26
|
max_htlc_msat: <Maximum HTLC Size Millitokens String>
|
|
24
27
|
min_htlc: <Minimum HTLC Size Millitokens String>
|
|
25
28
|
time_lock_delta: <Forwarding CLTV Delta Number>
|
|
@@ -36,6 +39,8 @@ const now = () => new Date().toISOString();
|
|
|
36
39
|
cltv_delta: <Channel CLTV Delta Number>
|
|
37
40
|
fee_rate: <Channel Fee Rate In Millitokens Per Million Number>
|
|
38
41
|
id: <Standard Format Channel Id String>
|
|
42
|
+
inbound_base_discount_mtokens: <Source Fee Discount Millitokens String>
|
|
43
|
+
inbound_rate_discount: <Source Based PPM Fee Discount Number>
|
|
39
44
|
is_disabled: <Channel Is Disabled Bool>
|
|
40
45
|
[max_htlc_mtokens]: <Channel Maximum HTLC Millitokens String>
|
|
41
46
|
min_htlc_mtokens: <Channel Minimum HTLC Millitokens String>
|
|
@@ -112,6 +117,8 @@ module.exports = update => {
|
|
|
112
117
|
throw new Error('ExpectedValidChannelId');
|
|
113
118
|
}
|
|
114
119
|
|
|
120
|
+
const inBase = asDiscount(update.routing_policy.inbound_fee_base_msat);
|
|
121
|
+
const inRate = asDiscount(update.routing_policy.inbound_fee_rate_milli_msat);
|
|
115
122
|
const maxHtlc = update.routing_policy.max_htlc_msat;
|
|
116
123
|
const transactionId = update.chan_point.funding_txid_bytes.reverse();
|
|
117
124
|
|
|
@@ -123,6 +130,8 @@ module.exports = update => {
|
|
|
123
130
|
cltv_delta: update.routing_policy.time_lock_delta,
|
|
124
131
|
fee_rate: Number(update.routing_policy.fee_rate_milli_msat),
|
|
125
132
|
id: chanFormat({number: update.chan_id}).channel,
|
|
133
|
+
inbound_base_discount_mtokens: inBase.toString(),
|
|
134
|
+
inbound_rate_discount: inRate,
|
|
126
135
|
is_disabled: update.routing_policy.disabled,
|
|
127
136
|
max_htlc_mtokens: maxHtlc !== Number().toString() ? maxHtlc : undefined,
|
|
128
137
|
min_htlc_mtokens: update.routing_policy.min_htlc,
|
package/package.json
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
"url": "https://github.com/alexbosworth/lightning/issues"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@grpc/grpc-js": "1.10.
|
|
10
|
+
"@grpc/grpc-js": "1.10.8",
|
|
11
11
|
"@grpc/proto-loader": "0.7.13",
|
|
12
|
-
"@types/node": "20.12.
|
|
12
|
+
"@types/node": "20.12.13",
|
|
13
13
|
"@types/request": "2.48.12",
|
|
14
14
|
"@types/ws": "8.5.10",
|
|
15
15
|
"async": "3.2.5",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"invoices": "3.0.0",
|
|
23
23
|
"psbt": "3.0.0",
|
|
24
24
|
"tiny-secp256k1": "2.2.3",
|
|
25
|
-
"type-fest": "4.18.
|
|
25
|
+
"type-fest": "4.18.3"
|
|
26
26
|
},
|
|
27
27
|
"description": "Lightning Network client library",
|
|
28
28
|
"devDependencies": {
|
|
@@ -53,5 +53,5 @@
|
|
|
53
53
|
"directory": "test/typescript"
|
|
54
54
|
},
|
|
55
55
|
"types": "index.d.ts",
|
|
56
|
-
"version": "10.
|
|
56
|
+
"version": "10.13.0"
|
|
57
57
|
}
|
|
@@ -163,6 +163,22 @@ const tests = [
|
|
|
163
163
|
},
|
|
164
164
|
description: 'A local channel policy is updated',
|
|
165
165
|
},
|
|
166
|
+
{
|
|
167
|
+
args: {
|
|
168
|
+
inbound_base_discount_mtokens: '1',
|
|
169
|
+
lnd: makeLnd({
|
|
170
|
+
policy: {
|
|
171
|
+
base_fee_msat: '1000',
|
|
172
|
+
chan_point: undefined,
|
|
173
|
+
fee_rate: 0.000001,
|
|
174
|
+
global: true,
|
|
175
|
+
max_htlc_msat: undefined,
|
|
176
|
+
time_lock_delta: 144,
|
|
177
|
+
},
|
|
178
|
+
}),
|
|
179
|
+
description: 'Set a base discount',
|
|
180
|
+
},
|
|
181
|
+
},
|
|
166
182
|
];
|
|
167
183
|
|
|
168
184
|
tests.forEach(({args, description, error, expected}) => {
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
const {deepStrictEqual} = require('node:assert').strict;
|
|
2
|
+
const {rejects} = require('node:assert').strict;
|
|
3
|
+
const test = require('node:test');
|
|
4
|
+
|
|
5
|
+
const {createFundedPsbt} = require('./../../../lnd_methods');
|
|
6
|
+
|
|
7
|
+
const psbt = '70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000';
|
|
8
|
+
const unsupported = {details: 'transaction template missing, need to specify either PSBT or raw TX template'};
|
|
9
|
+
|
|
10
|
+
const makeLnd = overrides => {
|
|
11
|
+
const res = {
|
|
12
|
+
change_output_index: 0,
|
|
13
|
+
funded_psbt: Buffer.from(psbt, 'hex'),
|
|
14
|
+
locked_utxos: [{
|
|
15
|
+
expiration: 1,
|
|
16
|
+
id: Buffer.alloc(32),
|
|
17
|
+
outpoint: {
|
|
18
|
+
output_index: 0,
|
|
19
|
+
txid_bytes: Buffer.from('75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858', 'hex').reverse(),
|
|
20
|
+
},
|
|
21
|
+
}],
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
Object.keys(overrides).forEach(k => res[k] = overrides[k]);
|
|
25
|
+
|
|
26
|
+
return {wallet: {fundPsbt: (args, cbk) => cbk(null, res)}};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const makeArgs = overrides => {
|
|
30
|
+
const args = {
|
|
31
|
+
lnd: makeLnd({}),
|
|
32
|
+
outputs: [{script: '00', tokens: 1}],
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
Object.keys(overrides).forEach(key => args[key] = overrides[key]);
|
|
36
|
+
|
|
37
|
+
return args;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const makeExpected = overrides => {
|
|
41
|
+
const expected = {
|
|
42
|
+
psbt: '70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000',
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
Object.keys(overrides).forEach(k => expected[k] = overrides[k]);
|
|
46
|
+
|
|
47
|
+
return expected;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const tests = [
|
|
51
|
+
{
|
|
52
|
+
args: makeArgs({lnd: undefined}),
|
|
53
|
+
description: 'An LND object is required',
|
|
54
|
+
error: [400, 'ExpectedAuthenticatedLndToCreateFundedPsbt'],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
args: makeArgs({lnd: {wallet: {fundPsbt: ({}, cbk) => cbk(unsupported)}}}),
|
|
58
|
+
description: 'Unsupported error is passed back',
|
|
59
|
+
error: [501, 'CreateFundedPsbtMethodNotSupported'],
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
args: makeArgs({lnd: {wallet: {fundPsbt: ({}, cbk) => cbk('err')}}}),
|
|
63
|
+
description: 'Errors funding are passed back',
|
|
64
|
+
error: [503, 'UnexpectedErrorCreatingFundedPsbt', {err: 'err'}],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
args: makeArgs({lnd: {wallet: {fundPsbt: ({}, cbk) => cbk()}}}),
|
|
68
|
+
description: 'A response is expected',
|
|
69
|
+
error: [503, 'ExpectedResultWhenCreatingFundedPsbt'],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
args: makeArgs({lnd: makeLnd({funded_psbt: undefined})}),
|
|
73
|
+
description: 'A funded PSBT is expected in the response',
|
|
74
|
+
error: [503, 'ExpectedFundedTransactionPsbtToBeCreated'],
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
args: makeArgs({}),
|
|
78
|
+
description: 'PSBT funding is executed',
|
|
79
|
+
expected: makeExpected({}),
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
args: makeArgs({min_confirmations: 0}),
|
|
83
|
+
description: 'PSBT funding is executed with min confs specified',
|
|
84
|
+
expected: makeExpected({}),
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
args: makeArgs({fee_tokens_per_vbyte: 1, outputs: undefined}),
|
|
88
|
+
description: 'PSBT funding can specify fee rate',
|
|
89
|
+
expected: makeExpected({}),
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
args: makeArgs({target_confirmations: 1}),
|
|
93
|
+
description: 'PSBT funding can specify conf target',
|
|
94
|
+
expected: makeExpected({}),
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
args: makeArgs({
|
|
98
|
+
inputs: [{
|
|
99
|
+
transaction_id: Buffer.alloc(32).toString('hex'),
|
|
100
|
+
transaction_vout: 0,
|
|
101
|
+
}],
|
|
102
|
+
}),
|
|
103
|
+
description: 'Inputs can be specified',
|
|
104
|
+
expected: makeExpected({}),
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
args: makeArgs({outputs: [{is_change: true, script: '00', tokens: 1}]}),
|
|
108
|
+
description: 'Outputs can be specified',
|
|
109
|
+
expected: makeExpected({}),
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
args: makeArgs({utxo_selection: 'largest'}),
|
|
113
|
+
description: 'PSBT funding can select largest coins',
|
|
114
|
+
expected: makeExpected({}),
|
|
115
|
+
},
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
tests.forEach(({args, description, error, expected}) => {
|
|
119
|
+
return test(description, async () => {
|
|
120
|
+
if (!!error) {
|
|
121
|
+
await rejects(createFundedPsbt(args), error, 'Got error');
|
|
122
|
+
} else {
|
|
123
|
+
const got = await createFundedPsbt(args);
|
|
124
|
+
|
|
125
|
+
deepStrictEqual(got, expected, 'Got expected result');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return;
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -9,6 +9,8 @@ const makeRoutingPolicy = overrides => {
|
|
|
9
9
|
disabled: false,
|
|
10
10
|
fee_base_msat: '1',
|
|
11
11
|
fee_rate_milli_msat: '1',
|
|
12
|
+
inbound_fee_base_msat: 0,
|
|
13
|
+
inbound_fee_rate_milli_msat: 0,
|
|
12
14
|
max_htlc_msat: '1',
|
|
13
15
|
min_htlc: '1',
|
|
14
16
|
time_lock_delta: 1,
|
|
@@ -44,6 +46,8 @@ const makeExpected = overrides => {
|
|
|
44
46
|
cltv_delta: 1,
|
|
45
47
|
fee_rate: 1,
|
|
46
48
|
id: '0x0x1',
|
|
49
|
+
inbound_base_discount_mtokens: '0',
|
|
50
|
+
inbound_rate_discount: 0,
|
|
47
51
|
is_disabled: false,
|
|
48
52
|
max_htlc_mtokens: '1',
|
|
49
53
|
min_htlc_mtokens: '1',
|
|
@@ -156,6 +160,19 @@ const tests = [
|
|
|
156
160
|
description: 'RPC channel update is mapped to update',
|
|
157
161
|
expected: makeExpected({}),
|
|
158
162
|
},
|
|
163
|
+
{
|
|
164
|
+
args: makeArgs({
|
|
165
|
+
routing_policy: makeRoutingPolicy({
|
|
166
|
+
inbound_fee_base_msat: -1,
|
|
167
|
+
inbound_fee_rate_milli_msat: -1,
|
|
168
|
+
}),
|
|
169
|
+
}),
|
|
170
|
+
description: 'RPC channel with inbound rates is mapped',
|
|
171
|
+
expected: makeExpected({
|
|
172
|
+
inbound_base_discount_mtokens: '1',
|
|
173
|
+
inbound_rate_discount: 1,
|
|
174
|
+
}),
|
|
175
|
+
},
|
|
159
176
|
{
|
|
160
177
|
args: makeArgs({
|
|
161
178
|
capacity: '0',
|