lightning 10.9.2 → 10.10.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 +5 -0
- package/README.md +4 -0
- package/grpc/protos/lightning.proto +6 -0
- package/grpc/protos/walletkit.proto +84 -37
- package/index.js +4 -0
- package/lnd_methods/index.js +4 -0
- package/lnd_methods/macaroon/methods.json +9 -0
- package/lnd_methods/offchain/delete_payments.js +1 -1
- package/lnd_methods/onchain/get_pending_sweeps.js +81 -0
- package/lnd_methods/onchain/index.js +4 -0
- package/lnd_methods/onchain/request_batched_fee_increase.js +108 -0
- package/lnd_methods/onchain/request_chain_fee_increase.js +1 -0
- package/lnd_responses/index.js +2 -0
- package/lnd_responses/rpc_sweep_as_sweep.js +96 -0
- package/package.json +6 -6
- package/test/lnd_methods/onchain/test_get_pending_sweeps.js +92 -0
- package/test/lnd_methods/onchain/test_request_batched_fee_increase.js +111 -0
- package/test/lnd_responses/test_rpc_sweep_as_sweep.js +135 -0
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -220,6 +220,8 @@ variables set:
|
|
|
220
220
|
details of opening or closing channels.
|
|
221
221
|
- [getPendingPayments](https://github.com/alexbosworth/ln-service#getpendingpayments): List out
|
|
222
222
|
past pending payments.
|
|
223
|
+
- [getPendingSweeps](https://github.com/alexbosworth/ln-service#getpendingsweeps):
|
|
224
|
+
List out queued outpoints that are being swept
|
|
223
225
|
- [getPublicKey](https://github.com/alexbosworth/ln-service#getpublickey): Derive a public key at
|
|
224
226
|
a given index.
|
|
225
227
|
- [getRouteConfidence](https://github.com/alexbosworth/ln-service#getrouteconfidence): Check a
|
|
@@ -277,6 +279,8 @@ variables set:
|
|
|
277
279
|
Remove a LN p2p network socket from the node advertisement
|
|
278
280
|
- [removePeer](https://github.com/alexbosworth/ln-service#removepeer): Disconnect from a
|
|
279
281
|
connected peer.
|
|
282
|
+
- [requestBatchedFeeIncrease](https://github.com/alexbosworth/ln-service#requestbatchedfeeincrease):
|
|
283
|
+
Ask for a batched CPFP chain fee rate increase on a pending confirm UTXO
|
|
280
284
|
- [requestChainFeeIncrease](https://github.com/alexbosworth/ln-service#requestchainfeeincrease):
|
|
281
285
|
Ask for a CPFP chain fee rate increase on a pending confirm UTXO.
|
|
282
286
|
- [revokeAccess](https://github.com/alexbosworth/ln-service#revokeaccess): Remove the access
|
|
@@ -4231,6 +4231,10 @@ message DeleteAllPaymentsRequest {
|
|
|
4231
4231
|
Only delete failed HTLCs from payments, not the payment itself.
|
|
4232
4232
|
*/
|
|
4233
4233
|
bool failed_htlcs_only = 2;
|
|
4234
|
+
|
|
4235
|
+
// Delete all payments. NOTE: Using this option requires careful
|
|
4236
|
+
// consideration as it is a destructive operation.
|
|
4237
|
+
bool all_payments = 3;
|
|
4234
4238
|
}
|
|
4235
4239
|
|
|
4236
4240
|
message DeletePaymentResponse {
|
|
@@ -4307,6 +4311,8 @@ enum FeatureBit {
|
|
|
4307
4311
|
ANCHORS_OPT = 21;
|
|
4308
4312
|
ANCHORS_ZERO_FEE_HTLC_REQ = 22;
|
|
4309
4313
|
ANCHORS_ZERO_FEE_HTLC_OPT = 23;
|
|
4314
|
+
ROUTE_BLINDING_REQUIRED = 24;
|
|
4315
|
+
ROUTE_BLINDING_OPTIONAL = 25;
|
|
4310
4316
|
AMP_REQ = 30;
|
|
4311
4317
|
AMP_OPT = 31;
|
|
4312
4318
|
}
|
|
@@ -242,31 +242,34 @@ service WalletKit {
|
|
|
242
242
|
rpc PendingSweeps (PendingSweepsRequest) returns (PendingSweepsResponse);
|
|
243
243
|
|
|
244
244
|
/* lncli: `wallet bumpfee`
|
|
245
|
-
BumpFee
|
|
246
|
-
takes
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
245
|
+
BumpFee is an endpoint that allows users to interact with lnd's sweeper
|
|
246
|
+
directly. It takes an outpoint from an unconfirmed transaction and sends it
|
|
247
|
+
to the sweeper for potential fee bumping. Depending on whether the outpoint
|
|
248
|
+
has been registered in the sweeper (an existing input, e.g., an anchor
|
|
249
|
+
output) or not (a new input, e.g., an unconfirmed wallet utxo), this will
|
|
250
|
+
either be an RBF or CPFP attempt.
|
|
251
|
+
|
|
252
|
+
When receiving an input, lnd’s sweeper needs to understand its time
|
|
253
|
+
sensitivity to make economical fee bumps - internally a fee function is
|
|
254
|
+
created using the deadline and budget to guide the process. When the
|
|
255
|
+
deadline is approaching, the fee function will increase the fee rate and
|
|
256
|
+
perform an RBF.
|
|
257
|
+
|
|
258
|
+
When a force close happens, all the outputs from the force closing
|
|
259
|
+
transaction will be registered in the sweeper. The sweeper will then handle
|
|
260
|
+
the creation, publish, and fee bumping of the sweeping transactions.
|
|
261
|
+
Everytime a new block comes in, unless the sweeping transaction is
|
|
262
|
+
confirmed, an RBF is attempted. To interfere with this automatic process,
|
|
263
|
+
users can use BumpFee to specify customized fee rate, budget, deadline, and
|
|
264
|
+
whether the sweep should happen immediately. It's recommended to call
|
|
265
|
+
`ListSweeps` to understand the shape of the existing sweeping transaction
|
|
266
|
+
first - depending on the number of inputs in this transaction, the RBF
|
|
267
|
+
requirements can be quite different.
|
|
257
268
|
|
|
258
269
|
This RPC also serves useful when wanting to perform a Child-Pays-For-Parent
|
|
259
270
|
(CPFP), where the child transaction pays for its parent's fee. This can be
|
|
260
271
|
done by specifying an outpoint within the low fee transaction that is under
|
|
261
272
|
the control of the wallet.
|
|
262
|
-
|
|
263
|
-
The fee preference can be expressed either as a specific fee rate or a delta
|
|
264
|
-
of blocks in which the output should be swept on-chain within. If a fee
|
|
265
|
-
preference is not explicitly specified, then an error is returned.
|
|
266
|
-
|
|
267
|
-
Note that this RPC currently doesn't perform any validation checks on the
|
|
268
|
-
fee preference being provided. For now, the responsibility of ensuring that
|
|
269
|
-
the new fee preference is sufficient is delegated to the user.
|
|
270
273
|
*/
|
|
271
274
|
rpc BumpFee (BumpFeeRequest) returns (BumpFeeResponse);
|
|
272
275
|
|
|
@@ -280,7 +283,7 @@ service WalletKit {
|
|
|
280
283
|
/* lncli: `wallet labeltx`
|
|
281
284
|
LabelTransaction adds a label to a transaction. If the transaction already
|
|
282
285
|
has a label the call will fail unless the overwrite bool is set. This will
|
|
283
|
-
overwrite the
|
|
286
|
+
overwrite the existing transaction label. Labels must not be empty, and
|
|
284
287
|
cannot exceed 500 characters.
|
|
285
288
|
*/
|
|
286
289
|
rpc LabelTransaction (LabelTransactionRequest)
|
|
@@ -1105,33 +1108,56 @@ message PendingSweep {
|
|
|
1105
1108
|
uint32 broadcast_attempts = 5;
|
|
1106
1109
|
|
|
1107
1110
|
/*
|
|
1111
|
+
Deprecated.
|
|
1108
1112
|
The next height of the chain at which we'll attempt to broadcast the
|
|
1109
1113
|
sweep transaction of the output.
|
|
1110
1114
|
*/
|
|
1111
|
-
uint32 next_broadcast_height = 6;
|
|
1115
|
+
uint32 next_broadcast_height = 6 [deprecated = true];
|
|
1112
1116
|
|
|
1113
|
-
|
|
1114
|
-
|
|
1117
|
+
/*
|
|
1118
|
+
Deprecated, use immediate.
|
|
1119
|
+
Whether this input must be force-swept. This means that it is swept
|
|
1120
|
+
immediately.
|
|
1121
|
+
*/
|
|
1122
|
+
bool force = 7 [deprecated = true];
|
|
1123
|
+
|
|
1124
|
+
/*
|
|
1125
|
+
Deprecated, use deadline.
|
|
1126
|
+
The requested confirmation target for this output, which is the deadline
|
|
1127
|
+
used by the sweeper.
|
|
1128
|
+
*/
|
|
1129
|
+
uint32 requested_conf_target = 8 [deprecated = true];
|
|
1115
1130
|
|
|
1116
1131
|
// Deprecated, use requested_sat_per_vbyte.
|
|
1117
1132
|
// The requested fee rate, expressed in sat/vbyte, for this output.
|
|
1118
1133
|
uint32 requested_sat_per_byte = 9 [deprecated = true];
|
|
1119
1134
|
|
|
1120
1135
|
/*
|
|
1121
|
-
The fee rate we'll use to sweep the output, expressed in sat/vbyte.
|
|
1122
|
-
rate is only determined once a sweeping transaction for the output
|
|
1123
|
-
created, so it's possible for this to be 0 before this.
|
|
1136
|
+
The current fee rate we'll use to sweep the output, expressed in sat/vbyte.
|
|
1137
|
+
The fee rate is only determined once a sweeping transaction for the output
|
|
1138
|
+
is created, so it's possible for this to be 0 before this.
|
|
1124
1139
|
*/
|
|
1125
1140
|
uint64 sat_per_vbyte = 10;
|
|
1126
1141
|
|
|
1127
|
-
// The requested fee rate, expressed in sat/vbyte, for this
|
|
1142
|
+
// The requested starting fee rate, expressed in sat/vbyte, for this
|
|
1143
|
+
// output. When not requested, this field will be 0.
|
|
1128
1144
|
uint64 requested_sat_per_vbyte = 11;
|
|
1129
1145
|
|
|
1130
1146
|
/*
|
|
1131
|
-
Whether this input
|
|
1132
|
-
if it has a negative yield.
|
|
1147
|
+
Whether this input will be swept immediately.
|
|
1133
1148
|
*/
|
|
1134
|
-
bool
|
|
1149
|
+
bool immediate = 12;
|
|
1150
|
+
|
|
1151
|
+
/*
|
|
1152
|
+
The budget for this sweep, expressed in satoshis. This is the maximum amount
|
|
1153
|
+
that can be spent as fees to sweep this output.
|
|
1154
|
+
*/
|
|
1155
|
+
uint64 budget = 13;
|
|
1156
|
+
|
|
1157
|
+
/*
|
|
1158
|
+
The deadline height used for this output when perform fee bumping.
|
|
1159
|
+
*/
|
|
1160
|
+
uint32 deadline_height = 14;
|
|
1135
1161
|
}
|
|
1136
1162
|
|
|
1137
1163
|
message PendingSweepsRequest {
|
|
@@ -1148,7 +1174,9 @@ message BumpFeeRequest {
|
|
|
1148
1174
|
// The input we're attempting to bump the fee of.
|
|
1149
1175
|
lnrpc.OutPoint outpoint = 1;
|
|
1150
1176
|
|
|
1151
|
-
// The
|
|
1177
|
+
// Optional. The deadline in number of blocks that the input should be spent
|
|
1178
|
+
// within. When not set, for new inputs, the default value (1008) is used;
|
|
1179
|
+
// for existing inputs, their current values will be retained.
|
|
1152
1180
|
uint32 target_conf = 2;
|
|
1153
1181
|
|
|
1154
1182
|
/*
|
|
@@ -1159,16 +1187,35 @@ message BumpFeeRequest {
|
|
|
1159
1187
|
uint32 sat_per_byte = 3 [deprecated = true];
|
|
1160
1188
|
|
|
1161
1189
|
/*
|
|
1162
|
-
|
|
1163
|
-
|
|
1190
|
+
Deprecated, use immediate.
|
|
1191
|
+
Whether this input must be force-swept. This means that it is swept
|
|
1192
|
+
immediately.
|
|
1164
1193
|
*/
|
|
1165
|
-
bool force = 4;
|
|
1194
|
+
bool force = 4 [deprecated = true];
|
|
1166
1195
|
|
|
1167
1196
|
/*
|
|
1168
|
-
The fee rate, expressed in sat/vbyte, that
|
|
1169
|
-
with.
|
|
1197
|
+
Optional. The starting fee rate, expressed in sat/vbyte, that will be used
|
|
1198
|
+
to spend the input with initially. This value will be used by the sweeper's
|
|
1199
|
+
fee function as its starting fee rate. When not set, the sweeper will use
|
|
1200
|
+
the estimated fee rate using the `target_conf` as the starting fee rate.
|
|
1170
1201
|
*/
|
|
1171
1202
|
uint64 sat_per_vbyte = 5;
|
|
1203
|
+
|
|
1204
|
+
/*
|
|
1205
|
+
Optional. Whether this input will be swept immediately. When set to true,
|
|
1206
|
+
the sweeper will sweep this input without waiting for the next batch.
|
|
1207
|
+
*/
|
|
1208
|
+
bool immediate = 6;
|
|
1209
|
+
|
|
1210
|
+
/*
|
|
1211
|
+
Optional. The max amount in sats that can be used as the fees. Setting this
|
|
1212
|
+
value greater than the input's value may result in CPFP - one or more wallet
|
|
1213
|
+
utxos will be used to pay the fees specified by the budget. If not set, for
|
|
1214
|
+
new inputs, by default 50% of the input's value will be treated as the
|
|
1215
|
+
budget for fee bumping; for existing inputs, their current budgets will be
|
|
1216
|
+
retained.
|
|
1217
|
+
*/
|
|
1218
|
+
uint64 budget = 7;
|
|
1172
1219
|
}
|
|
1173
1220
|
|
|
1174
1221
|
message BumpFeeResponse {
|
package/index.js
CHANGED
|
@@ -71,6 +71,7 @@ const {getPeers} = require('./lnd_methods');
|
|
|
71
71
|
const {getPendingChainBalance} = require('./lnd_methods');
|
|
72
72
|
const {getPendingChannels} = require('./lnd_methods');
|
|
73
73
|
const {getPendingPayments} = require('./lnd_methods');
|
|
74
|
+
const {getPendingSweeps} = require('./lnd_methods');
|
|
74
75
|
const {getPublicKey} = require('./lnd_methods');
|
|
75
76
|
const {getRouteConfidence} = require('./lnd_methods');
|
|
76
77
|
const {getRouteThroughHops} = require('./lnd_methods');
|
|
@@ -100,6 +101,7 @@ const {recoverFundsFromChannels} = require('./lnd_methods');
|
|
|
100
101
|
const {removeAdvertisedFeature} = require('./lnd_methods');
|
|
101
102
|
const {removeExternalSocket} = require('./lnd_methods');
|
|
102
103
|
const {removePeer} = require('./lnd_methods');
|
|
104
|
+
const {requestBatchedFeeIncrease} = require('./lnd_methods');
|
|
103
105
|
const {requestChainFeeIncrease} = require('./lnd_methods');
|
|
104
106
|
const {revokeAccess} = require('./lnd_methods');
|
|
105
107
|
const {sendMessageToPeer} = require('./lnd_methods');
|
|
@@ -228,6 +230,7 @@ module.exports = {
|
|
|
228
230
|
getPendingChainBalance,
|
|
229
231
|
getPendingChannels,
|
|
230
232
|
getPendingPayments,
|
|
233
|
+
getPendingSweeps,
|
|
231
234
|
getPublicKey,
|
|
232
235
|
getRouteConfidence,
|
|
233
236
|
getRouteThroughHops,
|
|
@@ -257,6 +260,7 @@ module.exports = {
|
|
|
257
260
|
removeAdvertisedFeature,
|
|
258
261
|
removeExternalSocket,
|
|
259
262
|
removePeer,
|
|
263
|
+
requestBatchedFeeIncrease,
|
|
260
264
|
requestChainFeeIncrease,
|
|
261
265
|
revokeAccess,
|
|
262
266
|
sendMessageToPeer,
|
package/lnd_methods/index.js
CHANGED
|
@@ -70,6 +70,7 @@ const {getPeers} = require('./peers');
|
|
|
70
70
|
const {getPendingChainBalance} = require('./onchain');
|
|
71
71
|
const {getPendingChannels} = require('./offchain');
|
|
72
72
|
const {getPendingPayments} = require('./offchain');
|
|
73
|
+
const {getPendingSweeps} = require('./onchain');
|
|
73
74
|
const {getPublicKey} = require('./address');
|
|
74
75
|
const {getRouteConfidence} = require('./generic');
|
|
75
76
|
const {getRouteThroughHops} = require('./offchain');
|
|
@@ -100,6 +101,7 @@ const {recoverFundsFromChannels} = require('./offchain');
|
|
|
100
101
|
const {removeAdvertisedFeature} = require('./peers');
|
|
101
102
|
const {removeExternalSocket} = require('./peers');
|
|
102
103
|
const {removePeer} = require('./peers');
|
|
104
|
+
const {requestBatchedFeeIncrease} = require('./onchain');
|
|
103
105
|
const {requestChainFeeIncrease} = require('./onchain');
|
|
104
106
|
const {revokeAccess} = require('./macaroon');
|
|
105
107
|
const {sendMessageToPeer} = require('./offchain');
|
|
@@ -226,6 +228,7 @@ module.exports = {
|
|
|
226
228
|
getPendingChainBalance,
|
|
227
229
|
getPendingChannels,
|
|
228
230
|
getPendingPayments,
|
|
231
|
+
getPendingSweeps,
|
|
229
232
|
getPublicKey,
|
|
230
233
|
getRouteConfidence,
|
|
231
234
|
getRouteThroughHops,
|
|
@@ -256,6 +259,7 @@ module.exports = {
|
|
|
256
259
|
removeAdvertisedFeature,
|
|
257
260
|
removeExternalSocket,
|
|
258
261
|
removePeer,
|
|
262
|
+
requestBatchedFeeIncrease,
|
|
259
263
|
requestChainFeeIncrease,
|
|
260
264
|
revokeAccess,
|
|
261
265
|
sendMessageToPeer,
|
|
@@ -280,6 +280,10 @@
|
|
|
280
280
|
"method": "ListPayments",
|
|
281
281
|
"type": "default"
|
|
282
282
|
},
|
|
283
|
+
"getPendingSweeps": {
|
|
284
|
+
"method": "PendingSweeps",
|
|
285
|
+
"type": "wallet"
|
|
286
|
+
},
|
|
283
287
|
"getPublicKey": {
|
|
284
288
|
"methods": ["DeriveKey", "DeriveNextKey"],
|
|
285
289
|
"type": "wallet"
|
|
@@ -400,6 +404,11 @@
|
|
|
400
404
|
"method": "DisconnectPeer",
|
|
401
405
|
"type": "default"
|
|
402
406
|
},
|
|
407
|
+
"requestBatchedFeeIncrease": {
|
|
408
|
+
"depends_on": ["getHeight"],
|
|
409
|
+
"method": "BumpFee",
|
|
410
|
+
"type": "wallet"
|
|
411
|
+
},
|
|
403
412
|
"requestChainFeeIncrease": {
|
|
404
413
|
"method": "BumpFee",
|
|
405
414
|
"type": "wallet"
|
|
@@ -30,7 +30,7 @@ module.exports = ({lnd}, cbk) => {
|
|
|
30
30
|
|
|
31
31
|
// Delete all payments
|
|
32
32
|
deletePayments: ['validate', ({}, cbk) => {
|
|
33
|
-
return lnd[type][method]({}, err => {
|
|
33
|
+
return lnd[type][method]({all_payments: true}, err => {
|
|
34
34
|
if (!!err) {
|
|
35
35
|
return cbk([503, 'UnexpectedErrorDeletingAllPayments', {err}]);
|
|
36
36
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const asyncAuto = require('async/auto');
|
|
2
|
+
const {returnResult} = require('asyncjs-util');
|
|
3
|
+
const {Transaction} = require('bitcoinjs-lib');
|
|
4
|
+
|
|
5
|
+
const {isLnd} = require('./../../lnd_requests');
|
|
6
|
+
const {rpcSweepAsSweep} = require('./../../lnd_responses');
|
|
7
|
+
|
|
8
|
+
const {fromHex} = Transaction;
|
|
9
|
+
const {isArray} = Array;
|
|
10
|
+
const method = 'pendingSweeps';
|
|
11
|
+
const notSupportedError = 'unknown service walletrpc.WalletKit';
|
|
12
|
+
const type = 'wallet';
|
|
13
|
+
|
|
14
|
+
/** Get pending self-transfer spends
|
|
15
|
+
|
|
16
|
+
Requires `onchain:read` permission
|
|
17
|
+
|
|
18
|
+
Requires LND built with `walletrpc` build tag
|
|
19
|
+
|
|
20
|
+
This method is not supported in LND 0.17.5 or below
|
|
21
|
+
|
|
22
|
+
{
|
|
23
|
+
lnd: <Authenticated LND API Object>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@returns via cbk or Promise
|
|
27
|
+
{
|
|
28
|
+
sweeps: [{
|
|
29
|
+
broadcasts_count: <Total Sweep Broadcast Attempts Count Number>
|
|
30
|
+
[current_fee_rate]: <Current Chain Fee Rate Tokens Per VByte Number>
|
|
31
|
+
[initial_fee_rate]: <Requested Chain Fee Rate Tokens per VByte Number>
|
|
32
|
+
is_batching: <Requested Waiting For Batching Bool>
|
|
33
|
+
[max_fee]: <Maximum Total Fee Tokens Allowed Number>
|
|
34
|
+
[max_height]: <Targeted Maximum Confirmation Height Number>
|
|
35
|
+
tokens: <Sweep Outpoint Tokens Value Number>
|
|
36
|
+
transaction_id: <Sweeping Outpoint Transaction Id Hex String>
|
|
37
|
+
transaction_vout: <Sweeping Outpoint Transaction Output Index Number>
|
|
38
|
+
type: <Outpoint Constraint Script Type String>
|
|
39
|
+
}]
|
|
40
|
+
}
|
|
41
|
+
*/
|
|
42
|
+
module.exports = ({lnd}, cbk) => {
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
return asyncAuto({
|
|
45
|
+
// Check arguments
|
|
46
|
+
validate: cbk => {
|
|
47
|
+
if (!isLnd({lnd, method, type})) {
|
|
48
|
+
return cbk([400, 'ExpectedLndToGetPendingSweeps']);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return cbk();
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
// Get sweep transaction ids
|
|
55
|
+
getSweeps: ['validate', ({}, cbk) => {
|
|
56
|
+
return lnd[type][method]({}, (err, res) => {
|
|
57
|
+
if (!!err) {
|
|
58
|
+
return cbk([503, 'UnexpectedGetPendingSweepsError', {err}]);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!res) {
|
|
62
|
+
return cbk([503, 'ExpectedResponseToGetPendingSweepsRequest']);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!isArray(res.pending_sweeps)) {
|
|
66
|
+
return cbk([503, 'ExpectedArrayOfPendingSweepsInSweepsResponse']);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const sweeps = res.pending_sweeps.map(rpcSweepAsSweep);
|
|
71
|
+
|
|
72
|
+
return cbk(null, {sweeps});
|
|
73
|
+
} catch (err) {
|
|
74
|
+
return cbk([503, err.message]);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}],
|
|
78
|
+
},
|
|
79
|
+
returnResult({reject, resolve, of: 'getSweeps'}, cbk));
|
|
80
|
+
});
|
|
81
|
+
};
|
|
@@ -15,6 +15,7 @@ const getChainTransactions = require('./get_chain_transactions');
|
|
|
15
15
|
const getLockedUtxos = require('./get_locked_utxos');
|
|
16
16
|
const getMasterPublicKeys = require('./get_master_public_keys');
|
|
17
17
|
const getPendingChainBalance = require('./get_pending_chain_balance');
|
|
18
|
+
const getPendingSweeps = require('./get_pending_sweeps');
|
|
18
19
|
const getSweepTransactions = require('./get_sweep_transactions');
|
|
19
20
|
const getUtxos = require('./get_utxos');
|
|
20
21
|
const lockUtxo = require('./lock_utxo');
|
|
@@ -23,6 +24,7 @@ const openChannels = require('./open_channels');
|
|
|
23
24
|
const partiallySignPsbt = require('./partially_sign_psbt');
|
|
24
25
|
const prepareForChannelProposal = require('./prepare_for_channel_proposal');
|
|
25
26
|
const proposeChannel = require('./propose_channel');
|
|
27
|
+
const requestBatchedFeeIncrease = require('./request_batched_fee_increase');
|
|
26
28
|
const requestChainFeeIncrease = require('./request_chain_fee_increase');
|
|
27
29
|
const sendToChainAddress = require('./send_to_chain_address');
|
|
28
30
|
const sendToChainAddresses = require('./send_to_chain_addresses');
|
|
@@ -56,6 +58,7 @@ module.exports = {
|
|
|
56
58
|
getLockedUtxos,
|
|
57
59
|
getMasterPublicKeys,
|
|
58
60
|
getPendingChainBalance,
|
|
61
|
+
getPendingSweeps,
|
|
59
62
|
getSweepTransactions,
|
|
60
63
|
getUtxos,
|
|
61
64
|
lockUtxo,
|
|
@@ -64,6 +67,7 @@ module.exports = {
|
|
|
64
67
|
partiallySignPsbt,
|
|
65
68
|
prepareForChannelProposal,
|
|
66
69
|
proposeChannel,
|
|
70
|
+
requestBatchedFeeIncrease,
|
|
67
71
|
requestChainFeeIncrease,
|
|
68
72
|
sendToChainAddress,
|
|
69
73
|
sendToChainAddresses,
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const asyncAuto = require('async/auto');
|
|
2
|
+
const {returnResult} = require('asyncjs-util');
|
|
3
|
+
|
|
4
|
+
const {getHeight} = require('./../generic');
|
|
5
|
+
const {isLnd} = require('./../../lnd_requests');
|
|
6
|
+
|
|
7
|
+
const defaultTargetConfirmations = 1008;
|
|
8
|
+
const isHash = n => /^[0-9A-F]{64}$/i.test(n);
|
|
9
|
+
const isNumber = n => !isNaN(n);
|
|
10
|
+
const messageExternalUtxo = 'the passed output does not belong to the wallet';
|
|
11
|
+
const method = 'bumpFee';
|
|
12
|
+
const positive = number => number > 0 ? number : 1;
|
|
13
|
+
const type = 'wallet';
|
|
14
|
+
|
|
15
|
+
/** Request batched CPFP fee bumping of an unconfirmed outpoint on a deadline
|
|
16
|
+
|
|
17
|
+
Requires `onchain:write` permission
|
|
18
|
+
|
|
19
|
+
Requires LND built with `walletrpc` build tag
|
|
20
|
+
|
|
21
|
+
This method is unsupported on LND 0.17.5 and below
|
|
22
|
+
|
|
23
|
+
{
|
|
24
|
+
lnd: <Authenticated LND API Object>
|
|
25
|
+
[max_fee]: <Maximum Tokens to Pay Into Chain Fees Number>
|
|
26
|
+
[max_height]: <Maximum Height To Reach a Confirmation Number>
|
|
27
|
+
transaction_id: <Unconfirmed UTXO Transaction Id Hex String>
|
|
28
|
+
transaction_vout: <Unconfirmed UTXO Transaction Index Number>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@returns via cbk or Promise
|
|
32
|
+
*/
|
|
33
|
+
module.exports = (args, cbk) => {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
return asyncAuto({
|
|
36
|
+
// Check arguments
|
|
37
|
+
validate: cbk => {
|
|
38
|
+
if (!isLnd({method, type, lnd: args.lnd})) {
|
|
39
|
+
return cbk([400, 'ExpectedLndToRequestChainFeeIncrease']);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!isHash(args.transaction_id)) {
|
|
43
|
+
return cbk([400, 'ExpectedTransactionIdToRequestChainFeeIncrease']);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!isNumber(args.transaction_vout)) {
|
|
47
|
+
return cbk([400, 'ExpectedTransactionOutputIndexToRequestFeeBump']);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return cbk();
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
// Get the current height to adjust max height to a conf target delta
|
|
54
|
+
getHeight: ['validate', ({}, cbk) => {
|
|
55
|
+
// Exit early when there is no max height specified
|
|
56
|
+
if (!args.max_height) {
|
|
57
|
+
return cbk();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return getHeight({lnd: args.lnd}, cbk);
|
|
61
|
+
}],
|
|
62
|
+
|
|
63
|
+
// Determine the confirmation target
|
|
64
|
+
targetConf: ['getHeight', ({getHeight}, cbk) => {
|
|
65
|
+
// Exit early when there is no max height
|
|
66
|
+
if (!getHeight) {
|
|
67
|
+
return cbk(null, defaultTargetConfirmations);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const currentBlockHeight = getHeight.current_block_height;
|
|
71
|
+
|
|
72
|
+
return cbk(null, positive(args.max_height - currentBlockHeight));
|
|
73
|
+
}],
|
|
74
|
+
|
|
75
|
+
// Make the request to submit the input to the batch sweeper
|
|
76
|
+
request: ['targetConf', ({targetConf}, cbk) => {
|
|
77
|
+
return args.lnd[type][method]({
|
|
78
|
+
budget: args.max_fee,
|
|
79
|
+
outpoint: {
|
|
80
|
+
output_index: args.transaction_vout,
|
|
81
|
+
txid_str: args.transaction_id,
|
|
82
|
+
},
|
|
83
|
+
target_conf: targetConf,
|
|
84
|
+
},
|
|
85
|
+
(err, res) => {
|
|
86
|
+
if (!!err && err.details === messageExternalUtxo) {
|
|
87
|
+
return cbk([404, 'SpecifiedUtxoNotFoundInWalletUtxos']);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (!!err) {
|
|
91
|
+
return cbk([503, 'UnexpectedErrorRequestingBatchIncrease', {err}]);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!res) {
|
|
95
|
+
return cbk([503, 'ExpectedResponseToBatchedFeeIncreaseRequest']);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (res.status === undefined) {
|
|
99
|
+
return cbk([503, 'ExpectedStatusOfBatchedFeeIncrease']);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return cbk();
|
|
103
|
+
});
|
|
104
|
+
}],
|
|
105
|
+
},
|
|
106
|
+
returnResult({reject, resolve}, cbk));
|
|
107
|
+
});
|
|
108
|
+
};
|
package/lnd_responses/index.js
CHANGED
|
@@ -38,6 +38,7 @@ const rpcPeerMessageAsMessage = require('./rpc_peer_message_as_message');
|
|
|
38
38
|
const rpcRequestUpdateAsEvent = require('./rpc_request_update_as_event');
|
|
39
39
|
const rpcResolutionAsResolution = require('./rpc_resolution_as_resolution');
|
|
40
40
|
const rpcRouteAsRoute = require('./rpc_route_as_route');
|
|
41
|
+
const rpcSweepAsSweep = require('./rpc_sweep_as_sweep');
|
|
41
42
|
const rpcTxAsTransaction = require('./rpc_tx_as_transaction');
|
|
42
43
|
const rpcUtxoAsUtxo = require('./rpc_utxo_as_utxo');
|
|
43
44
|
const rpcWalletStateAsState = require('./rpc_wallet_state_as_state');
|
|
@@ -83,6 +84,7 @@ module.exports = {
|
|
|
83
84
|
rpcRequestUpdateAsEvent,
|
|
84
85
|
rpcResolutionAsResolution,
|
|
85
86
|
rpcRouteAsRoute,
|
|
87
|
+
rpcSweepAsSweep,
|
|
86
88
|
rpcTxAsTransaction,
|
|
87
89
|
rpcUtxoAsUtxo,
|
|
88
90
|
rpcWalletStateAsState,
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const isBoolean = n => n === false || n === true;
|
|
2
|
+
const isHash = n => !!n && /^[0-9A-F]{64}$/i.test(n);
|
|
3
|
+
const isNumber = n => !isNaN(n);
|
|
4
|
+
|
|
5
|
+
/** Convert an RPC sweep into a sweep
|
|
6
|
+
|
|
7
|
+
{
|
|
8
|
+
amount_sat: <Outpoint Value Tokens Number>
|
|
9
|
+
broadcast_attempts: <Count of Past Sweep Broadcasts Number>
|
|
10
|
+
budget: <Maximum Fee Tokens to Spend On Sweeping String>
|
|
11
|
+
deadline_height: <Maximum Confirmation Height Number>
|
|
12
|
+
immediate: <Sweep Was Specified To Skip Waiting For Batching Bool>
|
|
13
|
+
outpoint: {
|
|
14
|
+
output_index: <Transaction Output Index Number>
|
|
15
|
+
txid_str: <Transaction Id Hex String>
|
|
16
|
+
}
|
|
17
|
+
requested_sat_per_vbyte: <Requested Chain Fee Rate Tokens Per VByte String>
|
|
18
|
+
sat_per_vbyte: <Current Sweeping Chain Fee Rate Tokens Per VByte String>
|
|
19
|
+
witness_type: <Witness Type String>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@throws
|
|
23
|
+
<Error>
|
|
24
|
+
|
|
25
|
+
@returns
|
|
26
|
+
{
|
|
27
|
+
broadcasts_count: <Total Sweep Broadcast Attempts Count Number>
|
|
28
|
+
[current_fee_rate]: <Current Chain Fee Rate Tokens Per VByte Number>
|
|
29
|
+
[initial_fee_rate]: <Requested Chain Fee Rate Tokens per VByte Number>
|
|
30
|
+
is_batching: <Requested Waiting For Batching Bool>
|
|
31
|
+
[max_fee]: <Maximum Total Fee Tokens Allowed Number>
|
|
32
|
+
[max_height]: <Targeted Maximum Confirmation Height Number>
|
|
33
|
+
tokens: <Sweep Outpoint Tokens Value Number>
|
|
34
|
+
transaction_id: <Sweeping Outpoint Transaction Id Hex String>
|
|
35
|
+
transaction_vout: <Sweeping Outpoint Transaction Output Index Number>
|
|
36
|
+
type: <Outpoint Constraint Script Type String>
|
|
37
|
+
}
|
|
38
|
+
*/
|
|
39
|
+
module.exports = args => {
|
|
40
|
+
if (!args) {
|
|
41
|
+
throw new Error('ExpectedSweepDetailsToDerivePendingSweep');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (args.amount_sat === undefined) {
|
|
45
|
+
throw new Error('ExpectedSweepOutpointValueAmountInPendingSweep');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!isNumber(args.broadcast_attempts)) {
|
|
49
|
+
throw new Error('ExpectedBroadcastAttemptsForSweepInPendingSweep');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!args.budget) {
|
|
53
|
+
throw new Error('ExpectedSweepBudgetAmountForSweepInPendingSweeps');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!isNumber(args.deadline_height)) {
|
|
57
|
+
throw new Error('ExpectedSweepConfirmationDeadlineHeightInPendingSweep');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!isBoolean(args.immediate)) {
|
|
61
|
+
throw new Error('ExpectedImmediateStatusOfSweepInPendingSweeps');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!args.outpoint) {
|
|
65
|
+
throw new Error('ExpectedUnspentOutpointOfSweepInPendingSweeps');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!isNumber(args.outpoint.output_index)) {
|
|
69
|
+
throw new Error('ExpectedOutputIndexOfSweepInPendingSweeps');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!isHash(args.outpoint.txid_str)) {
|
|
73
|
+
throw new Error('ExpectedOutpointTransactionIdHexStringInSweep');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!args.requested_sat_per_vbyte) {
|
|
77
|
+
throw new Error('ExpectedRequestedSatPerVByteForSweepInPendingSweeps');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!args.sat_per_vbyte) {
|
|
81
|
+
throw new Error('ExpectedSatPerVByteForSweepInPendingSweeps');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
broadcasts_count: args.broadcast_attempts,
|
|
86
|
+
current_fee_rate: Number(args.sat_per_vbyte) || undefined,
|
|
87
|
+
initial_fee_rate: Number(args.requested_sat_per_vbyte) || undefined,
|
|
88
|
+
is_batching: !args.immediate,
|
|
89
|
+
max_fee: Number(args.budget) || undefined,
|
|
90
|
+
max_height: args.deadline_height || undefined,
|
|
91
|
+
tokens: args.amount_sat,
|
|
92
|
+
transaction_id: args.outpoint.txid_str,
|
|
93
|
+
transaction_vout: args.outpoint.output_index,
|
|
94
|
+
type: args.witness_type.toLowerCase(),
|
|
95
|
+
};
|
|
96
|
+
};
|
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.
|
|
11
|
-
"@grpc/proto-loader": "0.7.
|
|
12
|
-
"@types/node": "20.12.
|
|
10
|
+
"@grpc/grpc-js": "1.10.7",
|
|
11
|
+
"@grpc/proto-loader": "0.7.13",
|
|
12
|
+
"@types/node": "20.12.8",
|
|
13
13
|
"@types/request": "2.48.12",
|
|
14
14
|
"@types/ws": "8.5.10",
|
|
15
15
|
"async": "3.2.5",
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
"bitcoinjs-lib": "6.1.5",
|
|
18
18
|
"bn.js": "5.2.1",
|
|
19
19
|
"bolt07": "1.8.4",
|
|
20
|
-
"bolt09": "2.
|
|
20
|
+
"bolt09": "2.1.0",
|
|
21
21
|
"ecpair": "2.1.0",
|
|
22
22
|
"invoices": "3.0.0",
|
|
23
23
|
"psbt": "3.0.0",
|
|
24
24
|
"tiny-secp256k1": "2.2.3",
|
|
25
|
-
"type-fest": "4.
|
|
25
|
+
"type-fest": "4.18.1"
|
|
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.10.0"
|
|
57
57
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const {strictEqual} = require('node:assert').strict;
|
|
2
|
+
const {rejects} = require('node:assert').strict;
|
|
3
|
+
const test = require('node:test');
|
|
4
|
+
|
|
5
|
+
const {getPendingSweeps} = require('./../../../lnd_methods');
|
|
6
|
+
|
|
7
|
+
const tests = [
|
|
8
|
+
{
|
|
9
|
+
args: {},
|
|
10
|
+
description: 'LND Object is required to get pending sweeps',
|
|
11
|
+
error: [400, 'ExpectedLndToGetPendingSweeps'],
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
args: {lnd: {wallet: {pendingSweeps: ({}, cbk) => cbk('err')}}},
|
|
15
|
+
description: 'Errors are passed back from method',
|
|
16
|
+
error: [503, 'UnexpectedGetPendingSweepsError', {err: 'err'}],
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
args: {lnd: {wallet: {pendingSweeps: ({}, cbk) => cbk()}}},
|
|
20
|
+
description: 'A result is expected from the method',
|
|
21
|
+
error: [503, 'ExpectedResponseToGetPendingSweepsRequest'],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
args: {lnd: {wallet: {pendingSweeps: ({}, cbk) => cbk(null, {})}}},
|
|
25
|
+
description: 'An array of sweeps is expected in response',
|
|
26
|
+
error: [503, 'ExpectedArrayOfPendingSweepsInSweepsResponse'],
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
args: {
|
|
30
|
+
lnd: {
|
|
31
|
+
wallet: {
|
|
32
|
+
pendingSweeps: ({}, cbk) => cbk(null, {pending_sweeps: [null]}),
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
description: 'An array of sweeps is expected in response',
|
|
37
|
+
error: [503, 'ExpectedSweepDetailsToDerivePendingSweep'],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
args: {
|
|
41
|
+
lnd: {
|
|
42
|
+
wallet: {
|
|
43
|
+
pendingSweeps: ({}, cbk) => cbk(null, {
|
|
44
|
+
pending_sweeps: [{
|
|
45
|
+
amount_sat: 0,
|
|
46
|
+
broadcast_attempts: 0,
|
|
47
|
+
budget: '0',
|
|
48
|
+
deadline_height: 0,
|
|
49
|
+
immediate: true,
|
|
50
|
+
outpoint: {
|
|
51
|
+
output_index: 0,
|
|
52
|
+
txid_str: Buffer.alloc(32).toString('hex'),
|
|
53
|
+
},
|
|
54
|
+
requested_sat_per_vbyte: '0',
|
|
55
|
+
sat_per_vbyte: '0',
|
|
56
|
+
witness_type: 'witness_type',
|
|
57
|
+
}],
|
|
58
|
+
}),
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
description: 'Pending sweeps are returned',
|
|
63
|
+
expected: {
|
|
64
|
+
sweeps: [{
|
|
65
|
+
broadcasts_count: 0,
|
|
66
|
+
current_fee_rate: undefined,
|
|
67
|
+
initial_fee_rate: undefined,
|
|
68
|
+
is_batching: false,
|
|
69
|
+
max_fee: undefined,
|
|
70
|
+
max_height: undefined,
|
|
71
|
+
tokens: 0,
|
|
72
|
+
transaction_id: Buffer.alloc(32).toString('hex'),
|
|
73
|
+
transaction_vout: 0,
|
|
74
|
+
type: 'witness_type',
|
|
75
|
+
}],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
tests.forEach(({args, description, error, expected}) => {
|
|
81
|
+
return test(description, async () => {
|
|
82
|
+
if (!!error) {
|
|
83
|
+
await rejects(() => getPendingSweeps(args), error, 'Got expected error');
|
|
84
|
+
} else {
|
|
85
|
+
const res = await getPendingSweeps(args);
|
|
86
|
+
|
|
87
|
+
strictEqual(res.chain_balance, expected.chain_balance, 'Got balance');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return;
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const EventEmitter = require('events');
|
|
2
|
+
const {rejects} = require('node:assert').strict;
|
|
3
|
+
const test = require('node:test');
|
|
4
|
+
|
|
5
|
+
const {requestBatchedFeeIncrease} = require('./../../../lnd_methods');
|
|
6
|
+
|
|
7
|
+
const makeLnd = overrides => {
|
|
8
|
+
const res = {status: 'status'};
|
|
9
|
+
|
|
10
|
+
Object.keys(overrides).forEach(k => res[k] = overrides[k]);
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
chain: {
|
|
14
|
+
registerBlockEpochNtfn: ({}) => {
|
|
15
|
+
const emitter = new EventEmitter();
|
|
16
|
+
|
|
17
|
+
emitter.cancel = () => {};
|
|
18
|
+
|
|
19
|
+
process.nextTick(() => emitter.emit('data', {
|
|
20
|
+
hash: Buffer.alloc(32),
|
|
21
|
+
height: 500,
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
return emitter;
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
wallet: {bumpFee: (args, cbk) => cbk(null, res)},
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const makeArgs = overrides => {
|
|
32
|
+
const args = {
|
|
33
|
+
lnd: makeLnd({}),
|
|
34
|
+
transaction_id: Buffer.alloc(32).toString('hex'),
|
|
35
|
+
transaction_vout: 0,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
Object.keys(overrides).forEach(key => args[key] = overrides[key]);
|
|
39
|
+
|
|
40
|
+
return args;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const tests = [
|
|
44
|
+
{
|
|
45
|
+
args: makeArgs({lnd: undefined}),
|
|
46
|
+
description: 'An LND object is required',
|
|
47
|
+
error: [400, 'ExpectedLndToRequestChainFeeIncrease'],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
args: makeArgs({transaction_id: undefined}),
|
|
51
|
+
description: 'A transaction id is required',
|
|
52
|
+
error: [400, 'ExpectedTransactionIdToRequestChainFeeIncrease'],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
args: makeArgs({transaction_vout: undefined}),
|
|
56
|
+
description: 'A tx output index is required',
|
|
57
|
+
error: [400, 'ExpectedTransactionOutputIndexToRequestFeeBump'],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
args: makeArgs({
|
|
61
|
+
lnd: {
|
|
62
|
+
wallet: {
|
|
63
|
+
bumpFee: ({}, cbk) => cbk({
|
|
64
|
+
details: 'the passed output does not belong to the wallet',
|
|
65
|
+
}),
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
}),
|
|
69
|
+
description: 'Unknown UTXO error is passed back',
|
|
70
|
+
error: [404, 'SpecifiedUtxoNotFoundInWalletUtxos'],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
args: makeArgs({lnd: {wallet: {bumpFee: ({}, cbk) => cbk('err')}}}),
|
|
74
|
+
description: 'Errors are passed back',
|
|
75
|
+
error: [503, 'UnexpectedErrorRequestingBatchIncrease', {err: 'err'}],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
args: makeArgs({lnd: {wallet: {bumpFee: ({}, cbk) => cbk()}}}),
|
|
79
|
+
description: 'A response is expected',
|
|
80
|
+
error: [503, 'ExpectedResponseToBatchedFeeIncreaseRequest'],
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
args: makeArgs({lnd: {wallet: {bumpFee: ({}, cbk) => cbk(null, {})}}}),
|
|
84
|
+
description: 'A response status is expected',
|
|
85
|
+
error: [503, 'ExpectedStatusOfBatchedFeeIncrease'],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
args: makeArgs({}),
|
|
89
|
+
description: 'Fee bump is requested',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
args: makeArgs({max_height: 1000}),
|
|
93
|
+
description: 'Fee bump is requested with a height',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
args: makeArgs({max_height: 2}),
|
|
97
|
+
description: 'Fee bump is requested with a low height',
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
tests.forEach(({args, description, error, expected}) => {
|
|
102
|
+
return test(description, async () => {
|
|
103
|
+
if (!!error) {
|
|
104
|
+
await rejects(requestBatchedFeeIncrease(args), error, 'Got error');
|
|
105
|
+
} else {
|
|
106
|
+
await requestBatchedFeeIncrease(args);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return;
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
const {deepEqual} = require('node:assert').strict;
|
|
2
|
+
const test = require('node:test');
|
|
3
|
+
const {throws} = require('node:assert').strict;
|
|
4
|
+
|
|
5
|
+
const {rpcSweepAsSweep} = require('./../../lnd_responses');
|
|
6
|
+
|
|
7
|
+
const makeArgs = overrides => {
|
|
8
|
+
const response = {
|
|
9
|
+
amount_sat: 0,
|
|
10
|
+
broadcast_attempts: 0,
|
|
11
|
+
budget: '0',
|
|
12
|
+
deadline_height: 0,
|
|
13
|
+
immediate: true,
|
|
14
|
+
outpoint: {
|
|
15
|
+
output_index: 0,
|
|
16
|
+
txid_str: Buffer.alloc(32).toString('hex'),
|
|
17
|
+
},
|
|
18
|
+
requested_sat_per_vbyte: '0',
|
|
19
|
+
sat_per_vbyte: '0',
|
|
20
|
+
witness_type: 'witness_type',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
Object.keys(overrides || {}).forEach(key => response[key] = overrides[key]);
|
|
24
|
+
|
|
25
|
+
return response;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
const makeExpected = overrides => {
|
|
30
|
+
const expected = {
|
|
31
|
+
broadcasts_count: 0,
|
|
32
|
+
current_fee_rate: undefined,
|
|
33
|
+
initial_fee_rate: undefined,
|
|
34
|
+
is_batching: false,
|
|
35
|
+
max_fee: undefined,
|
|
36
|
+
max_height: undefined,
|
|
37
|
+
tokens: 0,
|
|
38
|
+
transaction_id: Buffer.alloc(32).toString('hex'),
|
|
39
|
+
transaction_vout: 0,
|
|
40
|
+
type: 'witness_type',
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
Object.keys(overrides || {}).forEach(key => expected[key] = overrides[key]);
|
|
44
|
+
|
|
45
|
+
return expected;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const tests = [
|
|
49
|
+
{
|
|
50
|
+
description: 'Pending sweep details are expected',
|
|
51
|
+
error: 'ExpectedSweepDetailsToDerivePendingSweep',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
args: makeArgs({amount_sat: undefined}),
|
|
55
|
+
description: 'The sweep amount is expected',
|
|
56
|
+
error: 'ExpectedSweepOutpointValueAmountInPendingSweep',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
args: makeArgs({broadcast_attempts: undefined}),
|
|
60
|
+
description: 'The broadcasts count is expected',
|
|
61
|
+
error: 'ExpectedBroadcastAttemptsForSweepInPendingSweep',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
args: makeArgs({budget: undefined}),
|
|
65
|
+
description: 'The sweep budget is expected',
|
|
66
|
+
error: 'ExpectedSweepBudgetAmountForSweepInPendingSweeps',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
args: makeArgs({deadline_height: undefined}),
|
|
70
|
+
description: 'The target deadline is expected',
|
|
71
|
+
error: 'ExpectedSweepConfirmationDeadlineHeightInPendingSweep',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
args: makeArgs({immediate: undefined}),
|
|
75
|
+
description: 'The immediate status is expected',
|
|
76
|
+
error: 'ExpectedImmediateStatusOfSweepInPendingSweeps',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
args: makeArgs({outpoint: undefined}),
|
|
80
|
+
description: 'The outpoint being swept is expected',
|
|
81
|
+
error: 'ExpectedUnspentOutpointOfSweepInPendingSweeps',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
args: makeArgs({outpoint: {}}),
|
|
85
|
+
description: 'The outpoint vout being swept is expected',
|
|
86
|
+
error: 'ExpectedOutputIndexOfSweepInPendingSweeps',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
args: makeArgs({outpoint: {output_index: 0}}),
|
|
90
|
+
description: 'The outpoint transaction id being swept is expected',
|
|
91
|
+
error: 'ExpectedOutpointTransactionIdHexStringInSweep',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
args: makeArgs({requested_sat_per_vbyte: undefined}),
|
|
95
|
+
description: 'The requested sweeping chain fee rate is expected',
|
|
96
|
+
error: 'ExpectedRequestedSatPerVByteForSweepInPendingSweeps',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
args: makeArgs({sat_per_vbyte: undefined}),
|
|
100
|
+
description: 'The sweeping chain fee rate is expected',
|
|
101
|
+
error: 'ExpectedSatPerVByteForSweepInPendingSweeps',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
args: makeArgs({}),
|
|
105
|
+
description: 'RPC sweep is mapped to pending sweep details',
|
|
106
|
+
expected: makeExpected({}),
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
args: makeArgs({
|
|
110
|
+
budget: '1',
|
|
111
|
+
deadline_height: 1,
|
|
112
|
+
requested_sat_per_vbyte: '1',
|
|
113
|
+
sat_per_vbyte: '1',
|
|
114
|
+
}),
|
|
115
|
+
description: 'RPC sweep with all details is mapped to pending sweep ',
|
|
116
|
+
expected: makeExpected({
|
|
117
|
+
current_fee_rate: 1,
|
|
118
|
+
initial_fee_rate: 1,
|
|
119
|
+
max_fee: 1,
|
|
120
|
+
max_height: 1,
|
|
121
|
+
}),
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
tests.forEach(({args, description, error, expected}) => {
|
|
126
|
+
return test(description, (t, end) => {
|
|
127
|
+
if (!!error) {
|
|
128
|
+
throws(() => rpcSweepAsSweep(args), new Error(error), 'Got err');
|
|
129
|
+
} else {
|
|
130
|
+
deepEqual(rpcSweepAsSweep(args), expected, 'RPC sweep mapped');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return end();
|
|
134
|
+
});
|
|
135
|
+
});
|