ln-service 57.11.0 → 57.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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # Versions
2
2
 
3
+ ## 57.13.0
4
+
5
+ - `getWalletInfo`: Add support for LND 0.18.0
6
+ - `subscribeToGraph`: Add support for `inbound_base_discount_mtokens` and
7
+ `inbound_rate_discount`
8
+
9
+ ## 57.12.0
10
+
11
+ - `createFundedPsbt`: Add method to create a funded PSBT given inputs/outputs
12
+
3
13
  ## 57.11.0
4
14
 
5
15
  - `getChannel`, `getNetworkGraph`, `getNode`: Add
package/README.md CHANGED
@@ -9,6 +9,7 @@ through npm.
9
9
 
10
10
  Supported LND versions:
11
11
 
12
+ - v0.18.0-beta
12
13
  - v0.17.0-beta to v0.17.5-beta
13
14
  - v0.16.0-beta to v0.16.4-beta
14
15
  - v0.15.2-beta to v0.15.5-beta
@@ -147,6 +148,8 @@ for `unlocker` methods.
147
148
  - [closeChannel](#closechannel) - Terminate an open channel
148
149
  - [connectWatchtower](#connectwatchtower) - Connect a watchtower
149
150
  - [createChainAddress](#createchainaddress) - Get a chain address to receive at
151
+ - [createFundedPsbt](#createfundedpsbt): Create a funded PSBT given inputs and
152
+ outputs
150
153
  - [createHodlInvoice](#createhodlinvoice) - Make a HODL HTLC invoice
151
154
  - [createInvoice](#createinvoice) - Make a regular invoice
152
155
  - [createSeed](#createseed) - Generate a wallet seed for a new wallet
@@ -688,6 +691,55 @@ const format = 'p2wpkh';
688
691
  const {address} = await createChainAddress({format, lnd});
689
692
  ```
690
693
 
694
+ ### createFundedPsbt
695
+
696
+ Create an unsigned funded PSBT given inputs or outputs
697
+
698
+ When specifying local inputs, they must be locked before using
699
+
700
+ `utxo_selection` methods: 'largest', 'random'
701
+
702
+ Requires `onchain:write` permission
703
+
704
+ Requires LND built with `walletrpc` tag
705
+
706
+ This method is not supported on LND 0.17.5 or below
707
+
708
+ {
709
+ [fee_tokens_per_vbyte]: <Chain Fee Tokens Per Virtual Byte Number>
710
+ [inputs]: [{
711
+ [sequence]: <Sequence Number>
712
+ transaction_id: <Unspent Transaction Id Hex String>
713
+ transaction_vout: <Unspent Transaction Output Index Number>
714
+ }]
715
+ lnd: <Authenticated LND API Object>
716
+ [min_confirmations]: <Select Inputs With Minimum Confirmations Number>
717
+ [outputs]: [{
718
+ [is_change]: <Use This Output For Change Bool>
719
+ script: <Output Script Hex String>
720
+ tokens: <Send Tokens Tokens Number>
721
+ }]
722
+ [target_confirmations]: <Blocks To Wait for Confirmation Number>
723
+ [timelock]: <Spendable Lock Time on Transaction Number>
724
+ [utxo_selection]: <Select Inputs Using Selection Methodology Type String>
725
+ [version]: <Transaction Version Number>
726
+ }
727
+
728
+ @returns via cbk or Promise
729
+ {
730
+ psbt: <Unsigned PSBT Hex String>
731
+ }
732
+
733
+ ```node
734
+ const {createFundedPsbt} = require('ln-service');
735
+
736
+ const script = '00';
737
+ const tokens = 1e6;
738
+
739
+ // Create an unsigned PSBT that sends 1mm to an output script
740
+ const {psbt} = await createFundedPsbt({lnd, outputs: [{script, tokens}]});
741
+ ```
742
+
691
743
  ### createHodlInvoice
692
744
 
693
745
  Create HODL invoice. This invoice will not settle automatically when an
@@ -5819,6 +5871,9 @@ Subscribe to graph updates
5819
5871
 
5820
5872
  Requires `info:read` permission
5821
5873
 
5874
+ `inbound_base_discount_mtokens` is not supported on LND 0.17.5 and below
5875
+ `inbound_rate_discount` is not supported on LND 0.17.5 and below
5876
+
5822
5877
  {
5823
5878
  lnd: <Authenticated LND API Object>
5824
5879
  }
@@ -5836,6 +5891,8 @@ Requires `info:read` permission
5836
5891
  cltv_delta: <Channel CLTV Delta Number>
5837
5892
  fee_rate: <Channel Fee Rate In Millitokens Per Million Number>
5838
5893
  id: <Standard Format Channel Id String>
5894
+ inbound_base_discount_mtokens: <Source Specific Base Fee Reduction String>
5895
+ inbound_rate_discount: <Source Specific Per Million Rate Reduction Number>
5839
5896
  is_disabled: <Channel Is Disabled Bool>
5840
5897
  [max_htlc_mtokens]: <Channel Maximum HTLC Millitokens String>
5841
5898
  min_htlc_mtokens: <Channel Minimum HTLC Millitokens String>
package/index.js CHANGED
@@ -10,6 +10,7 @@ const {changePassword} = require('lightning');
10
10
  const {closeChannel} = require('lightning');
11
11
  const {connectWatchtower} = require('lightning');
12
12
  const {createChainAddress} = require('lightning');
13
+ const {createFundedPsbt} = require('lightning');
13
14
  const {createHodlInvoice} = require('lightning');
14
15
  const {createInvoice} = require('lightning');
15
16
  const {createSeed} = require('lightning');
@@ -174,6 +175,7 @@ module.exports = {
174
175
  closeChannel,
175
176
  connectWatchtower,
176
177
  createChainAddress,
178
+ createFundedPsbt,
177
179
  createHodlInvoice,
178
180
  createInvoice,
179
181
  createSeed,
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "dependencies": {
10
10
  "bolt07": "1.8.4",
11
11
  "invoices": "3.0.0",
12
- "lightning": "10.11.0",
12
+ "lightning": "10.13.1",
13
13
  "macaroon": "3.0.4"
14
14
  },
15
15
  "description": "Interaction helper for your Lightning Network daemon",
@@ -24,11 +24,11 @@
24
24
  "bn.js": "5.2.1",
25
25
  "bs58check": "3.0.1",
26
26
  "ecpair": "2.1.0",
27
- "ln-docker-daemons": "6.0.15",
27
+ "ln-docker-daemons": "6.0.17",
28
28
  "p2tr": "2.0.0",
29
29
  "portfinder": "1.0.32",
30
30
  "psbt": "3.0.0",
31
- "rimraf": "5.0.5",
31
+ "rimraf": "5.0.7",
32
32
  "secp256k1": "5.0.0",
33
33
  "tiny-secp256k1": "2.2.3",
34
34
  "uuid": "9.0.1",
@@ -52,6 +52,7 @@
52
52
  "url": "https://github.com/alexbosworth/ln-service.git"
53
53
  },
54
54
  "scripts": {
55
+ "integration-test-0.18.0": "DOCKER_LND_VERSION=v0.18.0-beta npm run test",
55
56
  "integration-test-0.17.5": "DOCKER_LND_VERSION=v0.17.5-beta npm run test",
56
57
  "integration-test-0.17.4": "DOCKER_LND_VERSION=v0.17.4-beta npm run test",
57
58
  "integration-test-0.17.3": "DOCKER_LND_VERSION=v0.17.3-beta npm run test",
@@ -71,5 +72,5 @@
71
72
  "integration-test-0.14.4": "DOCKER_LND_VERSION=v0.14.4-beta npm run test",
72
73
  "test": "echo $DOCKER_LND_VERSION && node test/runner"
73
74
  },
74
- "version": "57.11.0"
75
+ "version": "57.13.0"
75
76
  }
@@ -65,13 +65,6 @@ test(`Get chain transactions`, async () => {
65
65
  equal(tx.tokens, 5000000000, 'Got coinbase reward tokens');
66
66
  equal(!!tx.transaction, true, 'Got transaction hex');
67
67
 
68
- const onlyAfter = await getChainTransactions({
69
- lnd,
70
- after: tx.confirmation_height,
71
- });
72
-
73
- equal(onlyAfter.transactions.length, [].length, 'No txs after');
74
-
75
68
  const onlyBefore = await getChainTransactions({lnd, before: 2});
76
69
 
77
70
  equal(onlyBefore.transactions.length < 100, true, 'Got before txs');
@@ -47,6 +47,8 @@ test(`Open channels`, async () => {
47
47
  await asyncRetry({interval, times}, async () => {
48
48
  const lnds = [lnd, target.lnd, remote.lnd];
49
49
 
50
+ await generate({});
51
+
50
52
  const heights = await asyncMap(lnds, async lnd => {
51
53
  return (await getHeight({lnd})).current_block_height;
52
54
  });
@@ -106,6 +106,8 @@ test('Subscribe to channels', async t => {
106
106
  cltv_delta: policy.cltv_delta,
107
107
  fee_rate: policy.fee_rate,
108
108
  is_disabled: policy.is_disabled,
109
+ inbound_base_discount_mtokens: policy.inbound_base_discount_mtokens,
110
+ inbound_rate_discount: policy.inbound_rate_discount,
109
111
  max_htlc_mtokens: policy.max_htlc_mtokens,
110
112
  min_htlc_mtokens: policy.min_htlc_mtokens,
111
113
  public_keys: [policy.public_key, peer.public_key],
@@ -33,14 +33,24 @@ test(`Get route through hops`, async () => {
33
33
 
34
34
  const [{generate, lnd}, target, remote] = nodes;
35
35
 
36
- await target.generate({count: maturity});
37
-
38
36
  const controlToTargetChan = await setupChannel({generate, lnd, to: target});
39
37
 
40
- const targetToRemoteChan = await setupChannel({
41
- generate: target.generate,
42
- lnd: target.lnd,
43
- to: remote,
38
+ await generate({});
39
+
40
+ await asyncRetry({interval, times}, async () => {
41
+ await generate({});
42
+
43
+ await addPeer({
44
+ lnd: target.lnd,
45
+ public_key: remote.id,
46
+ socket: remote.socket,
47
+ });
48
+
49
+ const targetToRemoteChan = await setupChannel({
50
+ generate: target.generate,
51
+ lnd: target.lnd,
52
+ to: remote,
53
+ });
44
54
  });
45
55
 
46
56
  await target.generate({count: confirmationCount});
@@ -0,0 +1,141 @@
1
+ const {equal} = require('node:assert').strict;
2
+ const test = require('node:test');
3
+
4
+ const asyncRetry = require('async/retry');
5
+ const {address} = require('bitcoinjs-lib');
6
+ const {componentsOfTransaction} = require('@alexbosworth/blockchain');
7
+ const {spawnLightningCluster} = require('ln-docker-daemons');
8
+
9
+ const {broadcastChainTransaction} = require('./../../');
10
+ const {createChainAddress} = require('./../../');
11
+ const {createFundedPsbt} = require('./../../');
12
+ const {getChainTransactions} = require('./../../');
13
+ const {getUtxos} = require('./../../');
14
+ const {lockUtxo} = require('./../../');
15
+ const {signPsbt} = require('./../../');
16
+
17
+ const bufferAsHex = buffer => buffer.toString('hex');
18
+ const {concat} = Buffer;
19
+ const count = 100;
20
+ const format = 'p2tr';
21
+ const {fromBech32} = address;
22
+ const interval = retryCount => 10 * Math.pow(2, retryCount);
23
+ const OP_1 = Buffer.from([81]);
24
+ const push32 = Buffer.from([32]);
25
+ const sequence = 0;
26
+ const timelock = 1;
27
+ const times = 20;
28
+ const version = 1;
29
+
30
+ // Creating a funded PSBT should result in a funded PSBT
31
+ test(`Create funded PSBT`, async () => {
32
+ const {kill, nodes} = await spawnLightningCluster({});
33
+
34
+ const [{generate, lnd}] = nodes;
35
+
36
+ await generate({count});
37
+
38
+ try {
39
+ await createFundedPsbt({lnd});
40
+ } catch (err) {
41
+ if (!Array.isArray(err)) {
42
+ await kill({});
43
+
44
+ equal(err, null, 'Expected array error');
45
+
46
+ return;
47
+ }
48
+
49
+ const [code, message] = err;
50
+
51
+ // LND 0.17.5 and before do not support the create funded PSBT method
52
+ if (code === 501) {
53
+ await kill({});
54
+
55
+ equal(message, 'CreateFundedPsbtMethodNotSupported', 'Unsupported');
56
+
57
+ return;
58
+ }
59
+ }
60
+
61
+ try {
62
+ const {address} = await createChainAddress({format, lnd});
63
+ const {utxos} = await getUtxos({lnd});
64
+
65
+ const outputScriptElements = [OP_1, push32, fromBech32(address).data];
66
+ const [utxo] = utxos;
67
+
68
+ const output = bufferAsHex(concat(outputScriptElements));
69
+
70
+ // Creating a funded PSBT requires pre-locking the inputs
71
+ const lock = await lockUtxo({
72
+ lnd,
73
+ transaction_id: utxo.transaction_id,
74
+ transaction_vout: utxo.transaction_vout,
75
+ });
76
+
77
+ const {psbt} = await createFundedPsbt({
78
+ fee_tokens_per_vbyte: 50,
79
+ lnd,
80
+ inputs: [{
81
+ sequence,
82
+ transaction_id: utxo.transaction_id,
83
+ transaction_vout: utxo.transaction_vout,
84
+ }],
85
+ outputs: [{is_change: true, script: output, tokens: 1}],
86
+ timelock,
87
+ version,
88
+ });
89
+
90
+ const signed = await signPsbt({lnd, psbt});
91
+
92
+ // Make sure this tx can be published
93
+ await broadcastChainTransaction({lnd, transaction: signed.transaction});
94
+
95
+ // Make sure the publishing succeeded by looking for it in chain txns
96
+ const {transactions} = await getChainTransactions({lnd});
97
+
98
+ const [{transaction}] = transactions;
99
+
100
+ equal(signed.transaction, transaction, 'Transaction is broadcast');
101
+
102
+ const tx = componentsOfTransaction({transaction});
103
+
104
+ // Check all the elements of the 1 in 1 out transaction
105
+ equal(tx.inputs.length, [utxo].length, 'Used a single input');
106
+ equal(tx.inputs[0].sequence, sequence, 'Used specified input sequence');
107
+ equal(tx.inputs[0].id, utxo.transaction_id, 'Used specified tx id');
108
+ equal(tx.inputs[0].vout, utxo.transaction_vout, 'Used specified tx vout');
109
+ equal(tx.locktime, timelock, 'Used specified timelock value');
110
+ equal(tx.outputs.length, [output].length, 'Used a single output');
111
+ equal(tx.outputs[0].script, output, 'Output used output script');
112
+ equal(tx.outputs[0].tokens, 4999993913, 'Output spent all tokens');
113
+ equal(tx.version, version, 'Used specified version value');
114
+
115
+ // Create a 1 in 2 out transaction, so one with change
116
+ const withChange = await asyncRetry({interval, times}, async () => {
117
+ await generate({});
118
+
119
+ return await createFundedPsbt({
120
+ lnd,
121
+ outputs: [{script: output, tokens: 500}],
122
+ });
123
+ });
124
+
125
+ const signedChange = await signPsbt({lnd, psbt: withChange.psbt});
126
+
127
+ const signedTx = componentsOfTransaction({
128
+ transaction: signedChange.transaction,
129
+ });
130
+
131
+ equal(signedTx.outputs.length, 2, 'Change output created');
132
+ } catch (err) {
133
+ await kill({});
134
+
135
+ equal(err, null, 'No error expected');
136
+ }
137
+
138
+ await kill({});
139
+
140
+ return;
141
+ });