lightning 10.9.2 → 10.10.1
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 +10 -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_messages/close_channel_request.js +2 -2
- 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/offchain/get_connected_watchtowers.js +3 -3
- package/lnd_methods/onchain/close_channel.js +24 -3
- package/lnd_methods/onchain/get_chain_fee_estimate.js +4 -15
- package/lnd_methods/onchain/get_pending_sweeps.js +81 -0
- package/lnd_methods/onchain/index.js +4 -0
- package/lnd_methods/onchain/open_channel.js +4 -1
- package/lnd_methods/onchain/request_batched_fee_increase.js +108 -0
- package/lnd_methods/onchain/request_chain_fee_increase.js +3 -2
- package/lnd_methods/onchain/send_to_chain_address.js +14 -3
- package/lnd_methods/onchain/send_to_chain_addresses.js +14 -3
- 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_messages/test_close_channel_request.js +2 -2
- package/test/lnd_methods/macaroon/test_handle_rpc_request_update.js +1 -1
- package/test/lnd_methods/offchain/test_get_connected_watchtowers.js +2 -2
- package/test/lnd_methods/onchain/test_get_chain_fee_estimate.js +0 -41
- 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_methods/onchain/test_send_to_chain_address.js +27 -44
- package/test/lnd_methods/onchain/test_send_to_chain_addresses.js +25 -42
- package/test/lnd_responses/test_rpc_sweep_as_sweep.js +135 -0
|
@@ -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
|
+
};
|
|
@@ -54,7 +54,7 @@ module.exports = (args, cbk) => {
|
|
|
54
54
|
feeRate: ['validate', ({}, cbk) => {
|
|
55
55
|
// Exit early when the fee rate is specified
|
|
56
56
|
if (!!args.fee_tokens_per_vbyte) {
|
|
57
|
-
return cbk(null, {
|
|
57
|
+
return cbk(null, {sat_per_vbyte: args.fee_tokens_per_vbyte});
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
// Exit early when the confirmation target is specified
|
|
@@ -69,11 +69,12 @@ module.exports = (args, cbk) => {
|
|
|
69
69
|
request: ['feeRate', ({feeRate}, cbk) => {
|
|
70
70
|
return args.lnd[type][method]({
|
|
71
71
|
force: true,
|
|
72
|
+
immediate: true,
|
|
72
73
|
outpoint: {
|
|
73
74
|
output_index: args.transaction_vout,
|
|
74
75
|
txid_str: args.transaction_id,
|
|
75
76
|
},
|
|
76
|
-
|
|
77
|
+
sat_per_vbyte: feeRate.sat_per_vbyte,
|
|
77
78
|
target_conf: feeRate.target_conf,
|
|
78
79
|
},
|
|
79
80
|
(err, res) => {
|
|
@@ -3,6 +3,7 @@ const {returnResult} = require('asyncjs-util');
|
|
|
3
3
|
|
|
4
4
|
const {isLnd} = require('./../../lnd_requests');
|
|
5
5
|
|
|
6
|
+
const defaultConfTarget = 6;
|
|
6
7
|
const initialConfirmationCount = 0;
|
|
7
8
|
const {isArray} = Array;
|
|
8
9
|
const {isInteger} = Number;
|
|
@@ -83,18 +84,28 @@ module.exports = (args, cbk) => {
|
|
|
83
84
|
return cbk();
|
|
84
85
|
},
|
|
85
86
|
|
|
87
|
+
// Determine what the confirmations to confirm should be
|
|
88
|
+
targetConf: ['validate', ({}, cbk) => {
|
|
89
|
+
// Exit early when there is a chain fee rate specified
|
|
90
|
+
if (!!args.fee_tokens_per_vbyte) {
|
|
91
|
+
return cbk();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return cbk(null, args.target_confirmations || defaultConfTarget);
|
|
95
|
+
}],
|
|
96
|
+
|
|
86
97
|
// Send coins
|
|
87
|
-
send: ['
|
|
98
|
+
send: ['targetConf', ({targetConf}, cbk) => {
|
|
88
99
|
return args.lnd.default.sendCoins({
|
|
89
100
|
addr: args.address,
|
|
90
101
|
amount: args.tokens || undefined,
|
|
91
102
|
coin_selection_strategy: strategy(args.utxo_selection),
|
|
92
103
|
min_confs: args.utxo_confirmations || undefined,
|
|
93
104
|
label: args.description || undefined,
|
|
94
|
-
|
|
105
|
+
sat_per_vbyte: args.fee_tokens_per_vbyte || undefined,
|
|
95
106
|
send_all: args.is_send_all || undefined,
|
|
96
107
|
spend_unconfirmed: args.utxo_confirmations === unconfirmedConfCount,
|
|
97
|
-
target_conf:
|
|
108
|
+
target_conf: targetConf,
|
|
98
109
|
},
|
|
99
110
|
(err, res) => {
|
|
100
111
|
if (!!err && err.details === lowBalanceErr) {
|
|
@@ -3,6 +3,7 @@ const {returnResult} = require('asyncjs-util');
|
|
|
3
3
|
|
|
4
4
|
const {isLnd} = require('./../../lnd_requests');
|
|
5
5
|
|
|
6
|
+
const defaultConfTarget = 6;
|
|
6
7
|
const initialConfirmationCount = 0;
|
|
7
8
|
const {isArray} = Array;
|
|
8
9
|
const method = 'sendMany';
|
|
@@ -74,7 +75,17 @@ module.exports = (args, cbk) => {
|
|
|
74
75
|
return cbk();
|
|
75
76
|
},
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
// Determine what the confirmations to confirm should be
|
|
79
|
+
targetConf: ['validate', ({}, cbk) => {
|
|
80
|
+
// Exit early when there is a chain fee rate specified
|
|
81
|
+
if (!!args.fee_tokens_per_vbyte) {
|
|
82
|
+
return cbk();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return cbk(null, args.target_confirmations || defaultConfTarget);
|
|
86
|
+
}],
|
|
87
|
+
|
|
88
|
+
send: ['targetConf', ({targetConf}, cbk) => {
|
|
78
89
|
const AddrToAmount = {};
|
|
79
90
|
|
|
80
91
|
args.send_to
|
|
@@ -85,9 +96,9 @@ module.exports = (args, cbk) => {
|
|
|
85
96
|
coin_selection_strategy: strategy(args.utxo_selection),
|
|
86
97
|
label: args.description || undefined,
|
|
87
98
|
min_confs: args.utxo_confirmations || undefined,
|
|
88
|
-
|
|
99
|
+
sat_per_vbyte: args.fee_tokens_per_vbyte || undefined,
|
|
89
100
|
spend_unconfirmed: args.utxo_confirmations === unconfirmedConfCount,
|
|
90
|
-
target_conf:
|
|
101
|
+
target_conf: targetConf,
|
|
91
102
|
};
|
|
92
103
|
|
|
93
104
|
return args.lnd.default.sendMany(send, (err, res) => {
|
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.1"
|
|
57
57
|
}
|
|
@@ -12,7 +12,7 @@ const makeArgs = overrides => {
|
|
|
12
12
|
},
|
|
13
13
|
delivery_address: 'delivery_address',
|
|
14
14
|
force: true,
|
|
15
|
-
|
|
15
|
+
sat_per_vbyte: '1',
|
|
16
16
|
target_conf: 1,
|
|
17
17
|
};
|
|
18
18
|
|
|
@@ -47,7 +47,7 @@ const tests = [
|
|
|
47
47
|
args: makeArgs({
|
|
48
48
|
delivery_address: '',
|
|
49
49
|
force: false,
|
|
50
|
-
|
|
50
|
+
sat_per_vbyte: '0',
|
|
51
51
|
target_conf: 0,
|
|
52
52
|
}),
|
|
53
53
|
description: 'Defaults are selected',
|
|
@@ -28,7 +28,7 @@ const makeTower = overrides => {
|
|
|
28
28
|
max_backups: 1,
|
|
29
29
|
num_backups: 1,
|
|
30
30
|
num_pending_backups: 1,
|
|
31
|
-
|
|
31
|
+
sweep_sat_per_vbyte: 1,
|
|
32
32
|
}],
|
|
33
33
|
};
|
|
34
34
|
|
|
@@ -60,7 +60,7 @@ const makeLnd = args => {
|
|
|
60
60
|
return cbk(null, args.policyRes);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
return cbk(null, {max_updates: 1,
|
|
63
|
+
return cbk(null, {max_updates: 1, sweep_sat_per_vbyte: 1});
|
|
64
64
|
},
|
|
65
65
|
stats: ({}, cbk) => {
|
|
66
66
|
if (!!args.statsErr) {
|
|
@@ -57,52 +57,12 @@ const tests = [
|
|
|
57
57
|
description: 'Fee sat is expected in estimate fee response',
|
|
58
58
|
error: [503, 'ExpectedChainFeeInResponseToChainFeeEstimate'],
|
|
59
59
|
},
|
|
60
|
-
{
|
|
61
|
-
args: {
|
|
62
|
-
lnd: {default: {estimateFee: ({}, cbk) => cbk(null, {fee_sat: '1'})}},
|
|
63
|
-
send_to: [{address: 'address', tokens: 1}],
|
|
64
|
-
},
|
|
65
|
-
description: 'Fee rate is expected in estimate fee response',
|
|
66
|
-
error: [503, 'ExpectedFeeRateValueInChainFeeEstimateQuery'],
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
args: {
|
|
70
|
-
lnd: {
|
|
71
|
-
default: {
|
|
72
|
-
estimateFee: ({}, cbk) => cbk(null, {
|
|
73
|
-
fee_sat: '1',
|
|
74
|
-
feerate_sat_per_byte: '1',
|
|
75
|
-
}),
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
send_to: [{address: 'address', tokens: 1}],
|
|
79
|
-
},
|
|
80
|
-
description: 'Fee rate and fee are given in chain response',
|
|
81
|
-
expected: {fee: 1, tokens_per_vbyte: 1},
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
args: {
|
|
85
|
-
lnd: {
|
|
86
|
-
default: {
|
|
87
|
-
estimateFee: ({}, cbk) => cbk(null, {
|
|
88
|
-
fee_sat: '1',
|
|
89
|
-
feerate_sat_per_byte: '1',
|
|
90
|
-
}),
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
send_to: [{address: 'address', tokens: 1}],
|
|
94
|
-
utxo_confirmations: 0,
|
|
95
|
-
},
|
|
96
|
-
description: 'Passing 0 UTXO confirmations is supported',
|
|
97
|
-
expected: {fee: 1, tokens_per_vbyte: 1},
|
|
98
|
-
},
|
|
99
60
|
{
|
|
100
61
|
args: {
|
|
101
62
|
lnd: {
|
|
102
63
|
default: {
|
|
103
64
|
estimateFee: ({}, cbk) => cbk(null, {
|
|
104
65
|
fee_sat: '1',
|
|
105
|
-
feerate_sat_per_byte: '1',
|
|
106
66
|
sat_per_vbyte: '2',
|
|
107
67
|
}),
|
|
108
68
|
},
|
|
@@ -119,7 +79,6 @@ const tests = [
|
|
|
119
79
|
default: {
|
|
120
80
|
estimateFee: ({}, cbk) => cbk(null, {
|
|
121
81
|
fee_sat: '1',
|
|
122
|
-
feerate_sat_per_byte: '1',
|
|
123
82
|
sat_per_vbyte: '2',
|
|
124
83
|
}),
|
|
125
84
|
},
|
|
@@ -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
|
+
});
|