balanceofsatoshis 17.2.0 → 17.3.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,9 @@
1
1
  # Versions
2
2
 
3
+ ## 17.3.0
4
+
5
+ - `open`: Add `commitment` flag to allow specifying a simplified_taproot type
6
+
3
7
  ## 17.2.0
4
8
 
5
9
  - `telegram`: Add `--use-rounded-units` to format amounts as rounded amounts
package/bos CHANGED
@@ -1241,9 +1241,11 @@ prog
1241
1241
  .help('Skip external option by specifying --internal-fund-at-fee-rate')
1242
1242
  .help('For trusted funding specify --type as private-trusted/public-trusted')
1243
1243
  .help('Trusted channel funding is not supported in LND 0.15.0 and below')
1244
+ .help('Simplified Taproot channels are not supported in LND 0.17.0 & below')
1244
1245
  .argument('<peer_public_keys...>', 'With nodes with public keys')
1245
1246
  .option('--amount <channel_capacity>', 'Capacities to open', REPEATABLE)
1246
1247
  .option('--avoid-broadcast', 'Avoid broadcasting channel open transaction')
1248
+ .option('--commitment <type>', 'default or simplified_taproot', REPEATABLE)
1247
1249
  .option('--coop-close-address <addr>', 'Coop-close address', REPEATABLE)
1248
1250
  .option('--external-funding', 'Use external funds for the channel open')
1249
1251
  .option('--give <give_amount>', 'Amount to gift to peer', REPEATABLE)
@@ -1260,6 +1262,7 @@ prog
1260
1262
  logger,
1261
1263
  ask: await commands.interrogate({}),
1262
1264
  capacities: collect(options.amount),
1265
+ commitments: collect(options.commitment),
1263
1266
  cooperative_close_addresses: collect(options.coopCloseAddress),
1264
1267
  fs: {getFile: readFile},
1265
1268
  gives: collect(options.give),
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "@alexbosworth/node-fetch": "2.6.2",
18
18
  "abort-controller": "3.0.0",
19
19
  "asciichart": "1.5.25",
20
- "async": "3.2.4",
20
+ "async": "3.2.5",
21
21
  "asyncjs-util": "1.2.12",
22
22
  "bech32": "2.0.0",
23
23
  "bip66": "1.1.5",
@@ -38,7 +38,7 @@
38
38
  "inquirer": "9.2.11",
39
39
  "ln-accounting": "7.0.2",
40
40
  "ln-service": "57.1.0",
41
- "ln-sync": "5.2.3",
41
+ "ln-sync": "6.0.0",
42
42
  "ln-telegram": "6.0.0",
43
43
  "moment": "2.29.4",
44
44
  "paid-services": "5.0.5",
@@ -82,5 +82,5 @@
82
82
  "postpublish": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t alexbosworth/balanceofsatoshis -t alexbosworth/balanceofsatoshis:$npm_package_version --push .",
83
83
  "test": "npx nyc@15.1.0 node --experimental-test-coverage --test test/arrays/*.js test/balances/*.js test/chain/*.js test/display/*.js test/encryption/*.js test/lnd/*.js test/network/*.js test/nodes/*.js test/peers/*.js test/responses/*.js test/routing/*.js test/services/*.js test/swaps/*.js test/tags/*.js test/telegram/*.js test/wallets/*.js"
84
84
  },
85
- "version": "17.2.0"
85
+ "version": "17.3.0"
86
86
  }
@@ -1,5 +1,6 @@
1
1
  const defaultChannelCapacity = 5e6;
2
2
  const defaultChannelDescription = 'bos open';
3
+ const isSimpleP2tr = (arr, i) => !!arr[i] && arr[i] === 'simplified_taproot';
3
4
  const isTrusted = type => ['private-trusted', 'public-trusted'].includes(type);
4
5
  const numericFeeRate = n => !!n && /^\d+$/.test(n) ? Number(n) : undefined;
5
6
  const privateTypes = ['private', 'private-trusted'];
@@ -11,6 +12,7 @@ const uniq = arr => Array.from(new Set(arr));
11
12
  {
12
13
  addresses: [<Address String>]
13
14
  capacities: [<Channel Capacity Tokens Number>]
15
+ commitments: [<Channel Commitment Types String>]
14
16
  gives: [<Give Tokens String>]
15
17
  nodes: [<Channel Partner Node Identity Public Key Hex String>]
16
18
  rates: [<Set Fee Rate String>]
@@ -27,6 +29,7 @@ const uniq = arr => Array.from(new Set(arr));
27
29
  description: <Channel Description String>
28
30
  [give_tokens]: <Give Tokens Number>
29
31
  is_private: <Channel Is Private Bool>
32
+ is_simplified_taproot: <Channel Is Taproot Bool>
30
33
  partner_public_key: <Channel Partner Identity Public Key Hex String>
31
34
  [rate]: <Set Fee Rate String>
32
35
  }]
@@ -43,6 +46,7 @@ module.exports = args => {
43
46
  fee_rate: numericFeeRate(args.rates[i]),
44
47
  give_tokens: !!args.gives[i] ? Number(args.gives[i]) : undefined,
45
48
  is_private: !!args.types[i] && privateTypes.includes(args.types[i]),
49
+ is_simplified_taproot: isSimpleP2tr(args.commitments, i),
46
50
  is_trusted_funding: !!args.types[i] && isTrusted(args.types[i]),
47
51
  node: args.saved[i] || undefined,
48
52
  partner_public_key: key,
@@ -48,6 +48,8 @@ const {fromHex} = Transaction;
48
48
  const interval = 1000;
49
49
  const {isArray} = Array;
50
50
  const isPublicKey = n => !!n && /^0[2-3][0-9A-F]{64}$/i.test(n);
51
+ const isUnknown = (a1, a2) => a1.findIndex(n => !a2.includes(n)) !== -1;
52
+ const knownCommits = ['default', 'simplified_taproot'];
51
53
  const knownTypes = ['private', 'private-trusted', 'public', 'public-trusted'];
52
54
  const lineBreak = '\n';
53
55
  const noInternalFundingVersions = ['0.11.0-beta', '0.11.1-beta'];
@@ -68,6 +70,7 @@ const utxoPollingTimes = 20;
68
70
  {
69
71
  ask: <Ask For Input Function>
70
72
  capacities: [<New Channel Capacity Tokens String>]
73
+ commitments: [<Channel Commitment Types String>]
71
74
  cooperative_close_addresses: [<Cooperative Close Address>]
72
75
  fs: {
73
76
  getFile: <Read File Contents Function> (path, cbk) => {}
@@ -103,6 +106,10 @@ module.exports = (args, cbk) => {
103
106
  return cbk([400, 'ExpectedChannelCapacitiesToOpenChannels']);
104
107
  }
105
108
 
109
+ if (!isArray(args.commitments)) {
110
+ return cbk([400, 'ExpectedArrayOfChannelOutputTypesToOpenChannels']);
111
+ }
112
+
106
113
  if (!isArray(args.cooperative_close_addresses)) {
107
114
  return cbk([400, 'ExpectedCooperativeCloseAddressesArray']);
108
115
  }
@@ -133,6 +140,7 @@ module.exports = (args, cbk) => {
133
140
 
134
141
  const closeAddrCount = args.cooperative_close_addresses.length;
135
142
  const hasCapacities = !!args.capacities.length;
143
+ const hasCommitments = !!args.commitments.length;
136
144
  const hasGives = !!args.gives.length;
137
145
  const hasFeeRates = !!args.set_fee_rates.length;
138
146
  const hasNodes = !!args.opening_nodes.length;
@@ -142,6 +150,10 @@ module.exports = (args, cbk) => {
142
150
  return cbk([400, 'CapacitiesMustBeSpecifiedForEveryPublicKey']);
143
151
  }
144
152
 
153
+ if (!!hasCommitments && publicKeysLength !== args.commitments.length) {
154
+ return cbk([400, 'CommitmentTypesMustBeSpecifiedForEveryPublicKey']);
155
+ }
156
+
145
157
  if (!!closeAddrCount && publicKeysLength !== closeAddrCount) {
146
158
  return cbk([400, 'MustSetCoopClosingAddressForEveryPublicKey']);
147
159
  }
@@ -174,6 +186,10 @@ module.exports = (args, cbk) => {
174
186
  return cbk([400, 'UnknownChannelType', {channel_types: knownTypes}]);
175
187
  }
176
188
 
189
+ if (isUnknown(args.commitments, knownCommits)) {
190
+ return cbk([400, 'UnknownCommitment', {commitments: knownCommits}]);
191
+ }
192
+
177
193
  if (!!args.types.length && args.types.length !== publicKeysLength) {
178
194
  return cbk([400, 'ChannelTypesMustBeSpecifiedForEveryPublicKey']);
179
195
  }
@@ -263,6 +279,7 @@ module.exports = (args, cbk) => {
263
279
  const {opens} = channelsFromArguments({
264
280
  capacities,
265
281
  addresses: args.cooperative_close_addresses,
282
+ commitments: args.commitments,
266
283
  gives: args.gives,
267
284
  nodes: args.public_keys,
268
285
  rates: args.set_fee_rates,
@@ -445,6 +462,7 @@ module.exports = (args, cbk) => {
445
462
  cooperative_close_address: channel.cooperative_close_address,
446
463
  give_tokens: channel.give_tokens,
447
464
  is_private: channel.is_private,
465
+ is_simplified_taproot: channel.is_simplified_taproot,
448
466
  is_trusted_funding: channel.is_trusted_funding,
449
467
  lnd: getLnds.find(n => n.node === node).lnd,
450
468
  partner_public_key: channel.partner_public_key,
@@ -457,6 +475,7 @@ module.exports = (args, cbk) => {
457
475
  cooperative_close_address: test.cooperative_close_address,
458
476
  give_tokens: test.give_tokens,
459
477
  is_private: test.is_private,
478
+ is_simplified_taproot: test.is_simplified_taproot,
460
479
  is_trusted_funding: test.is_trusted_funding,
461
480
  lnd: test.lnd,
462
481
  partner_public_key: test.partner_public_key,
@@ -79,6 +79,7 @@ test(`Open channels`, async () => {
79
79
  throw new Error('UnrecognizedParameter');
80
80
  },
81
81
  capacities: ['6*m'],
82
+ commitments: [],
82
83
  cooperative_close_addresses: [address],
83
84
  fs: {getFile: () => {}},
84
85
  gives: [1e5],
@@ -0,0 +1,132 @@
1
+ const {equal} = require('node:assert').strict;
2
+ const test = require('node:test');
3
+
4
+ const {addPeer} = require('ln-service');
5
+ const asyncAuto = require('async/auto');
6
+ const asyncEach = require('async/each');
7
+ const asyncRetry = require('async/retry');
8
+ const {createChainAddress} = require('ln-service');
9
+ const {fundPsbt} = require('ln-service');
10
+ const {getChannels} = require('ln-service');
11
+ const {getPendingChannels} = require('ln-service');
12
+ const {getWalletInfo} = require('ln-service');
13
+ const {openChannel} = require('ln-service');
14
+ const {signPsbt} = require('ln-service');
15
+ const {spawnLightningCluster} = require('ln-docker-daemons');
16
+ const {Transaction} = require('bitcoinjs-lib');
17
+
18
+ const {openChannels} = require('./../../peers');
19
+
20
+ const count = 100;
21
+ const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
22
+ const interval = 200;
23
+ const log = () => {};
24
+ const size = 2;
25
+ const times = 1000;
26
+
27
+ // Opening taproot channels should open channels with specified nodes
28
+ test(`Open taproot channels`, async () => {
29
+ const {kill, nodes} = await spawnLightningCluster({
30
+ size,
31
+ lnd_configuration: [
32
+ '--maxpendingchannels=10',
33
+ '--protocol.option-scid-alias',
34
+ '--protocol.simple-taproot-chans',
35
+ ],
36
+ });
37
+
38
+ const [{generate, id, lnd}, target] = nodes;
39
+
40
+ try {
41
+ await generate({count});
42
+
43
+ await asyncRetry({interval, times}, async () => {
44
+ await addPeer({lnd, public_key: target.id, socket: target.socket});
45
+
46
+ await asyncEach(nodes, async ({lnd}) => {
47
+ const chain = await getWalletInfo({lnd});
48
+
49
+ if (!chain.is_synced_to_chain || !chain.is_synced_to_graph) {
50
+ throw new Error('WaitingForSync');
51
+ }
52
+ });
53
+ });
54
+
55
+ const {address} = await asyncRetry({interval, times}, async () => {
56
+ return await createChainAddress({lnd});
57
+ });
58
+
59
+ // Propose a taproot channel
60
+ await asyncAuto({
61
+ // Propose the taproot channel to target
62
+ propose: async () => {
63
+ return asyncRetry({interval, times}, async () => {
64
+ await addPeer({lnd, public_key: target.id, socket: target.socket});
65
+
66
+ await openChannels({
67
+ lnd,
68
+ ask: async (args, cbk) => {
69
+ if (args.name === 'internal') {
70
+ return cbk({internal: false});
71
+ }
72
+
73
+ if (args.name === 'fund') {
74
+ const address = args.message.split(' ')[9];
75
+ const amount = args.message.split(' ')[7];
76
+
77
+ // Provide funding
78
+ const {psbt} = await fundPsbt({
79
+ lnd,
80
+ outputs: [{address, tokens: amount * 1e8}],
81
+ });
82
+
83
+ const signed = await signPsbt({lnd, psbt});
84
+
85
+ return cbk({fund: signed.psbt});
86
+ }
87
+
88
+ throw new Error('UnrecognizedParameter');
89
+ },
90
+ capacities: [],
91
+ cooperative_close_addresses: [],
92
+ commitments: ['simplified_taproot'],
93
+ fs: {getFile: () => {}},
94
+ gives: [],
95
+ logger: {info: log, error: log},
96
+ opening_nodes: [],
97
+ public_keys: [target.id],
98
+ request: () => {},
99
+ set_fee_rates: [],
100
+ types: ['private'],
101
+ });
102
+ });
103
+ },
104
+
105
+ // Generate blocks until the channel confirms
106
+ generate: async () => {
107
+ return await asyncRetry({interval, times}, async () => {
108
+ await generate({});
109
+
110
+ const {channels} = await getChannels({lnd});
111
+
112
+ if (!channels.length) {
113
+ throw new Error('Expected Channels');
114
+ }
115
+
116
+ const [channel] = channels;
117
+
118
+ equal(channel.type, 'simplified_taproot', 'Taproot channel opened');
119
+ });
120
+ },
121
+
122
+ // Stop the target node
123
+ finish: ['generate', 'propose', async ({}) => {
124
+ await target.kill({});
125
+ }],
126
+ });
127
+ } catch (err) {
128
+ equal(err, null, 'Expected no error');
129
+ }
130
+
131
+ await kill({});
132
+ });
@@ -106,6 +106,7 @@ test(`Open channels`, async () => {
106
106
  },
107
107
  capacities: [],
108
108
  cooperative_close_addresses: [],
109
+ commitments: [],
109
110
  fs: {getFile: () => {}},
110
111
  gives: [],
111
112
  logger: {info: log, error: log},
@@ -8,6 +8,7 @@ const makeArgs = overrides => {
8
8
  const args = {
9
9
  addresses: ['address'],
10
10
  capacities: [2],
11
+ commitments: [],
11
12
  gives: ['1'],
12
13
  nodes: [Buffer.alloc(33, 3).toString('hex')],
13
14
  rates: [],
@@ -33,6 +34,7 @@ const tests = [
33
34
  fee_rate: undefined,
34
35
  give_tokens: 1,
35
36
  is_private: true,
37
+ is_simplified_taproot: false,
36
38
  is_trusted_funding: false,
37
39
  node: undefined,
38
40
  partner_public_key: Buffer.alloc(33, 3).toString('hex'),
@@ -58,6 +60,7 @@ const tests = [
58
60
  fee_rate: undefined,
59
61
  give_tokens: undefined,
60
62
  is_private: false,
63
+ is_simplified_taproot: false,
61
64
  is_trusted_funding: false,
62
65
  node: undefined,
63
66
  partner_public_key: Buffer.alloc(33, 3).toString('hex'),
@@ -87,6 +90,7 @@ const tests = [
87
90
  fee_rate: 1,
88
91
  give_tokens: 3,
89
92
  is_private: true,
93
+ is_simplified_taproot: false,
90
94
  is_trusted_funding: false,
91
95
  node: 'savedA',
92
96
  partner_public_key: 'remoteNodeA',
@@ -102,6 +106,7 @@ const tests = [
102
106
  fee_rate: 2,
103
107
  give_tokens: 4,
104
108
  is_private: false,
109
+ is_simplified_taproot: false,
105
110
  is_trusted_funding: false,
106
111
  node: 'savedB',
107
112
  partner_public_key: 'remoteNodeB',