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 +4 -0
- package/bos +3 -0
- package/package.json +3 -3
- package/peers/channels_from_arguments.js +4 -0
- package/peers/open_channels.js +19 -0
- package/test/integration/test_open_channels.js +1 -0
- package/test/integration/test_taproot_channels.js +132 -0
- package/test/integration/test_trusted_channels.js +1 -0
- package/test/peers/test_channels_from_arguments.js +5 -0
package/CHANGELOG.md
CHANGED
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.
|
|
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": "
|
|
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.
|
|
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,
|
package/peers/open_channels.js
CHANGED
|
@@ -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,
|
|
@@ -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
|
+
});
|
|
@@ -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',
|