paid-services 4.0.5 → 4.2.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,13 @@
1
1
  # Versions
2
2
 
3
+ ## Version 4.2.0
4
+
5
+ - `manageSwap`: Add support for P2TR output addresses
6
+
7
+ ## Version 4.1.0
8
+
9
+ - `createGroupChannel`: Add `members` to restrict and order group membership
10
+
3
11
  ## Version 4.0.5
4
12
 
5
13
  - `manageTrades`: Fix connection to seller failing
@@ -142,6 +142,7 @@ module.exports = ({capacity, proposed, rate}, cbk) => {
142
142
  .map(utxo => ({
143
143
  id: utxo.transaction_id,
144
144
  non_witness_utxo: utxo.non_witness_utxo,
145
+ sequence: Number(),
145
146
  vout: utxo.transaction_vout,
146
147
  witness_utxo: utxo.witness_utxo,
147
148
  }))
@@ -25,6 +25,7 @@ const minGroupCount = 2;
25
25
  const now = () => new Date().toISOString();
26
26
  const staleDate = () => new Date(Date.now() - (1000 * 60 * 10)).toISOString();
27
27
  const typeGroupId = '1';
28
+ const uniq = arr => Array.from(new Set(arr));
28
29
 
29
30
  /** Coordinate channel group
30
31
 
@@ -33,6 +34,7 @@ const typeGroupId = '1';
33
34
  count: <Group Members Count Number>
34
35
  identity: <Coordinator Identity Public Key Hex String>
35
36
  lnd: <Authenticated LND API Object>
37
+ [members]: [<Member Node Id Public Key Hex String>]
36
38
  rate: <Chain Fee Rate Number>
37
39
  }
38
40
 
@@ -87,7 +89,7 @@ const typeGroupId = '1';
87
89
  // All members have submitted their partial signatures
88
90
  @event 'signed'
89
91
  */
90
- module.exports = ({capacity, count, identity, lnd, rate}) => {
92
+ module.exports = ({capacity, count, identity, lnd, members, rate}) => {
91
93
  if (count < minGroupCount) {
92
94
  throw new Error('ExpectedHigherGroupMembersCountToCoordinateGroup');
93
95
  }
@@ -100,8 +102,13 @@ module.exports = ({capacity, count, identity, lnd, rate}) => {
100
102
  throw new Error('ExpectedAuthenticatedLndToCoordinateGroup');
101
103
  }
102
104
 
105
+ if (!!members && uniq(members).length !== count) {
106
+ throw new Error('ExpectedCompleteSetOfAllowedMembers');
107
+ }
108
+
103
109
  // Instantiate the group with self as a member
104
110
  const group = {
111
+ allowed: members,
105
112
  connected: [],
106
113
  emitter: new EventEmitter(),
107
114
  members: [{id: identity}],
@@ -152,6 +159,11 @@ module.exports = ({capacity, count, identity, lnd, rate}) => {
152
159
  return;
153
160
  }
154
161
 
162
+ // Exit early when group member is not allowed
163
+ if (!!group.allowed && !group.allowed.includes(req.from)) {
164
+ return res.failure([403, 'AccessDeniedToGroup']);
165
+ }
166
+
155
167
  // Emit event that someone is joining
156
168
  if (!group.members.find(n => n.id === req.from)) {
157
169
  group.emitter.emit('joining', {id: req.from});
@@ -27,6 +27,7 @@ const times = 2 * 60 * 10;
27
27
  ecp: <ECPair Library Object>
28
28
  identity: <Coordinator Identity Public Key Hex String>
29
29
  lnd: <Authenticated LND API Object>
30
+ [members]: [<Member Identity Public Key Hex String>]
30
31
  rate: <Chain Fee Tokens Per VByte Number>
31
32
  }
32
33
 
@@ -68,12 +69,20 @@ const times = 2 * 60 * 10;
68
69
  @event 'signed'
69
70
  {}
70
71
  */
71
- module.exports = ({capacity, count, ecp, identity, lnd, rate}) => {
72
+ module.exports = ({capacity, count, ecp, identity, lnd, members, rate}) => {
72
73
  if (count < minGroupCount) {
73
74
  throw new Error('ExpectedHigherGroupCountToAssembleChannelGroup');
74
75
  }
75
76
 
76
- const coordinator = coordinateGroup({capacity, count, identity, lnd, rate});
77
+ const coordinator = coordinateGroup({
78
+ capacity,
79
+ count,
80
+ identity,
81
+ lnd,
82
+ members,
83
+ rate,
84
+ });
85
+
77
86
  const emitter = new EventEmitter();
78
87
  const pending = {};
79
88
 
@@ -10,7 +10,10 @@ const tinysecp = require('tiny-secp256k1');
10
10
  const assembleChannelGroup = require('./assemble_channel_group');
11
11
 
12
12
  const halfOf = n => n / 2;
13
+ const {isArray} = Array;
14
+ const isPublicKey = n => !!n && /^0[2-3][0-9A-F]{64}$/i.test(n);
13
15
  const isOdd = n => !!(n % 2);
16
+ const isValidMembersCount = (n, count) => !n.length || n.length === count - 1;
14
17
  const join = arr => arr.join(', ');
15
18
  const maxGroupSize = 420;
16
19
  const minChannelSize = 2e4;
@@ -18,13 +21,14 @@ const minGroupSize = 2;
18
21
  const niceName = ({alias, id}) => `${alias} ${id}`.trim();
19
22
  const signPsbtEndpoint = '/walletrpc.WalletKit/SignPsbt';
20
23
 
21
- /** Join a channel group
24
+ /** Create a channel group
22
25
 
23
26
  {
24
27
  capacity: <Channel Capacity Tokens Number>
25
28
  count: <Group Member Count Number>
26
29
  lnd: <Authenticated LND API Object>
27
30
  logger: <Winston Logger Object>
31
+ [members]: [<Member Identity Public Key Hex String>]
28
32
  rate: <Opening Chain Fee Tokens Per VByte Rate Number>
29
33
  }
30
34
 
@@ -69,6 +73,18 @@ module.exports = (args, cbk) => {
69
73
  return cbk([400, 'ExpectedWinstonLoggerToCreateChannelGroup']);
70
74
  }
71
75
 
76
+ if (!isArray(args.members)) {
77
+ return cbk([400, 'ExpectedArrayOfGroupMembersToCreateChannelGroup']);
78
+ }
79
+
80
+ if (!isValidMembersCount(args.members, args.count)) {
81
+ return cbk([400, 'ExpectedCompleteSetOfAllowedGroupMembers']);
82
+ }
83
+
84
+ if (!!args.members.filter(n => !isPublicKey(n)).length) {
85
+ return cbk([400, 'ExpectedNodeIdentityPublicKeysForChannelGroup']);
86
+ }
87
+
72
88
  if (!args.rate) {
73
89
  return cbk([400, 'ExpectedOpeningFeeRateToCreateChannelGroup']);
74
90
  }
@@ -121,12 +137,15 @@ module.exports = (args, cbk) => {
121
137
  'getIdentity',
122
138
  ({ecp, getIdentity}, cbk) =>
123
139
  {
140
+ const members = [getIdentity.public_key].concat(args.members);
141
+
124
142
  const coordinate = assembleChannelGroup({
125
143
  ecp,
126
144
  capacity: args.capacity,
127
145
  count: args.count,
128
146
  identity: getIdentity.public_key,
129
147
  lnd: args.lnd,
148
+ members: !!args.members.length ? members : undefined,
130
149
  rate: args.rate,
131
150
  });
132
151
 
@@ -4,6 +4,7 @@ const minGroupCount = 2;
4
4
 
5
5
  {
6
6
  group: {
7
+ allowed: [<Allowed Public Key Id Hex String>]
7
8
  ids: [<Public Key Id Hex String>]
8
9
  }
9
10
  id: <Identity Public Key Hex String>
@@ -21,11 +22,13 @@ module.exports = ({group, id}) => {
21
22
  return {inbound: group.ids.find(n => n !== id)};
22
23
  }
23
24
 
24
- const [first] = group.ids;
25
- const reversed = group.ids.slice().reverse();
25
+ const ids = group.allowed || group.ids;
26
+
27
+ const [first] = ids;
28
+ const reversed = ids.slice().reverse();
26
29
 
27
30
  const [last] = reversed;
28
- const [, next] = group.ids.slice(group.ids.indexOf(id));
31
+ const [, next] = ids.slice(ids.indexOf(id));
29
32
 
30
33
  const [, previous] = reversed.slice(reversed.indexOf(id));
31
34
 
package/package.json CHANGED
@@ -14,10 +14,10 @@
14
14
  "bolt01": "1.2.5",
15
15
  "bolt07": "1.8.2",
16
16
  "ecpair": "2.1.0",
17
- "goldengate": "11.4.0",
18
- "invoices": "2.2.0",
19
- "ln-service": "54.2.6",
20
- "ln-sync": "4.0.5",
17
+ "goldengate": "12.0.0",
18
+ "invoices": "2.2.2",
19
+ "ln-service": "54.8.0",
20
+ "ln-sync": "4.1.0",
21
21
  "psbt": "2.7.1",
22
22
  "p2tr": "1.3.2",
23
23
  "tiny-secp256k1": "2.2.1"
@@ -25,7 +25,7 @@
25
25
  "description": "Lightning Paid Services library",
26
26
  "devDependencies": {
27
27
  "@alexbosworth/tap": "15.0.11",
28
- "ln-docker-daemons": "3.1.4",
28
+ "ln-docker-daemons": "4.0.2",
29
29
  "mock-lnd": "1.4.4",
30
30
  "secp256k1": "4.0.3"
31
31
  },
@@ -47,5 +47,5 @@
47
47
  "integration-tests": "tap -j 2 --branches=1 --functions=1 --lines=1 --statements=1 -t 180 test/integration/*.js",
48
48
  "test": "tap --branches=1 --functions=1 --lines=1 --statements=1 -t 60 test/actions/*.js test/balanced/*.js test/capacity/*.js test/client/*.js test/config/*.js test/p2p/*.js test/records/*.js test/respond/*.js test/server/*.js test/swaps/*.js test/services/*.js test/trades/*.js"
49
49
  },
50
- "version": "4.0.5"
50
+ "version": "4.2.0"
51
51
  }
@@ -65,6 +65,7 @@ const encodeAddress = (prefix, data) => bech32m.encode(prefix, data);
65
65
  const externalKeyAsOutputScript = key => `5120${key}`;
66
66
  const family = 805;
67
67
  const {floor} = Math;
68
+ const format = 'p2tr';
68
69
  const {from} = Buffer;
69
70
  const {fromHex} = Transaction;
70
71
  const fuzzBlocks = 100;
@@ -79,7 +80,7 @@ const {min} = Math;
79
80
  const minTokens = 10000;
80
81
  const minBlockMs = 1000 * 60;
81
82
  const pollInterval = {btcregtest: 100};
82
- const ppmRate = (fee, total) => fee * 1e6 / total.tokens;
83
+ const ppmRate = (fee, total) => fee * 1e6 / total;
83
84
  const preimageByteLength = 32;
84
85
  const pubKeyAsInternalKey = key => Buffer.from(key).slice(1).toString('hex');
85
86
  const pushSecret = asyncTimeout(releaseSwapOutSecret, 1000 * 30);
@@ -155,7 +156,7 @@ module.exports = (args, cbk) => {
155
156
  return cbk(null, {address: args.sweep_address});
156
157
  }
157
158
 
158
- return createChainAddress({lnd: args.lnd}, cbk);
159
+ return createChainAddress({format, lnd: args.lnd}, cbk);
159
160
  }],
160
161
 
161
162
  // Get the current chain fee rate for the sweep fee rate calculation
@@ -42,9 +42,11 @@ const {typePayMetadata} = require('./swap_field_types');
42
42
  const bufferAsHex = buffer => buffer.toString('hex');
43
43
  const defaultMaxFundingConfirmationDelay = 12;
44
44
  const defaultMinDelta = 60;
45
+ const estimatedSize = 150;
45
46
  const family = 805;
46
47
  const flatten = arr => [].concat(...arr);
47
48
  const {floor} = Math;
49
+ const format = 'p2tr';
48
50
  const {from} = Buffer;
49
51
  const {fromHex} = Transaction;
50
52
  const fuzzBlocks = 100;
@@ -126,7 +128,7 @@ module.exports = (args, cbk) => {
126
128
 
127
129
  // Get an address to sweep out to
128
130
  getSweepAddress: ['validate', ({}, cbk) => {
129
- return createChainAddress({lnd: args.lnd}, cbk);
131
+ return createChainAddress({format, lnd: args.lnd}, cbk);
130
132
  }],
131
133
 
132
134
  // Get the encryption key to decode the recovery secrets
@@ -370,6 +372,11 @@ module.exports = (args, cbk) => {
370
372
  });
371
373
 
372
374
  const refunds = uniqBy(feeRates, 'rate').map(({rate, height}) => {
375
+ // Exit early when there is nothing to recover
376
+ if (rate * estimatedSize > recoveryDetails.tokens) {
377
+ return;
378
+ }
379
+
373
380
  return taprootRefundTransaction({
374
381
  ecp,
375
382
  block_height: height,
@@ -388,7 +395,7 @@ module.exports = (args, cbk) => {
388
395
  });
389
396
  });
390
397
 
391
- return cbk(null, refunds.map(n => n.transaction));
398
+ return cbk(null, refunds.filter(n => !!n).map(n => n.transaction));
392
399
  }],
393
400
 
394
401
  // Sign the refund transactions
@@ -13,6 +13,7 @@ const {returnResult} = require('asyncjs-util');
13
13
  const decodeOffToOnRequest = require('./decode_off_to_on_request');
14
14
  const decodeOffToOnRestart = require('./decode_off_to_on_restart');
15
15
  const {decodeTrade} = require('./../trades');
16
+ const outputScriptForAddress = require('./output_script_for_address');
16
17
  const recoverResponseToSwapOut = require('./recover_response_to_swap_out');
17
18
  const requestSwapOut = require('./request_swap_out');
18
19
  const respondToSwapOutRequest = require('./respond_to_swap_out_request');
@@ -310,7 +311,10 @@ module.exports = (args, cbk) => {
310
311
  }
311
312
 
312
313
  try {
313
- return !!toOutputScript(input, networks[getNetwork.bitcoinjs]);
314
+ return !!outputScriptForAddress({
315
+ address: input,
316
+ network: getNetwork.bitcoinjs,
317
+ });
314
318
  } catch (err) {
315
319
  return 'Unsupported on-chain address format';
316
320
  }
@@ -0,0 +1,55 @@
1
+ const {address} = require('bitcoinjs-lib');
2
+ const {networks} = require('bitcoinjs-lib');
3
+
4
+ const bufferAsHex = buffer => buffer.toString('hex');
5
+ const byteLengthForP2tr = 32;
6
+ const {fromBech32} = address;
7
+ const prefixForP2tr = '5120';
8
+ const toOutputScript = (a, n) => address.toOutputScript(a, n).toString('hex');
9
+ const versionTaproot = 1;
10
+
11
+ /** Get the output script for an address
12
+
13
+ {
14
+ address: <Address String>
15
+ network: <BitcoinJs Network Name String>
16
+ }
17
+
18
+ @throws
19
+ <Error>
20
+
21
+ @returns
22
+ {
23
+ script: <Output Script Hex String>
24
+ }
25
+ */
26
+ module.exports = ({address, network}) => {
27
+ try {
28
+ return {
29
+ script: bufferAsHex(toOutputScript(address, networks[network])),
30
+ };
31
+ } catch (err) {
32
+ // Exit early when this is not a bech32 address
33
+ try {
34
+ fromBech32(address);
35
+ } catch (_) {
36
+ throw err;
37
+ }
38
+
39
+ const {data, prefix, version} = fromBech32(address);
40
+
41
+ if (prefix !== networks[network].bech32) {
42
+ throw new Error('InvalidNetworkToConvertAddressToOutputScript');
43
+ }
44
+
45
+ if (version !== versionTaproot) {
46
+ throw new Error('UnexpectedVersionOfAddressToConverToOutputScript');
47
+ }
48
+
49
+ if (data.length !== byteLengthForP2tr) {
50
+ throw new Error('UnexpectedByteLengthForPayToTaprootAddress');
51
+ }
52
+
53
+ return {script: `${prefixForP2tr}${bufferAsHex(data)}`};
54
+ }
55
+ };
@@ -31,6 +31,7 @@ const defaultFeeRate = 5000;
31
31
  const defaultMaxAmount = 21e14;
32
32
  const defaultMaxFeeForDeposit = 1337;
33
33
  const defaultSwapAmount = 2500000;
34
+ const feeAsPpm = (fee, total) => Math.ceil(fee * 1e6 / total);
34
35
  const findRecord = (r, type) => (r.find(n => n.type === type) || {}).value;
35
36
  const {floor} = Math;
36
37
  const hexAsBuffer = hex => Buffer.from(hex, 'hex');
@@ -421,14 +422,19 @@ module.exports = (args, cbk) => {
421
422
 
422
423
  const deposit = mtokensAsTokens(response.deposit_mtokens);
423
424
 
425
+ const combinedFee = tokens - askForTokens + deposit;
424
426
  const serviceFee = tokensAsBigUnit(deposit);
425
427
  const totalFee = tokensAsBigUnit(tokens - askForTokens + deposit);
426
428
 
429
+ const ppmTotal = feeAsPpm(combinedFee, askForTokens);
430
+
431
+ const feeInfo = `total fee is ${totalFee}, est PPM ${ppmTotal}`
432
+
427
433
  return cbk(null, {
428
434
  deposit,
429
435
  fee: tokens - askForTokens,
430
436
  incoming_peer: response.incoming_peer,
431
- pricing: `Execution cost ${serviceFee}, total fee is ${totalFee}`,
437
+ pricing: `Execution cost ${serviceFee}, ${feeInfo}`,
432
438
  rate: rateForFee(askForTokens, deposit + (tokens - askForTokens)),
433
439
  timeout: response.timeout,
434
440
  });
@@ -82,6 +82,7 @@ test(`Setup joint channel group`, async ({end, equal, strictSame}) => {
82
82
  count: nodes.length,
83
83
  lnd: control.lnd,
84
84
  logger: {info: line => createLog.push(line)},
85
+ members: [],
85
86
  rate: feeRate,
86
87
  });
87
88
  },
@@ -0,0 +1,202 @@
1
+ const {once} = require('events');
2
+
3
+ const {addPeer} = require('ln-service');
4
+ const asyncMap = require('async/map');
5
+ const asyncRetry = require('async/retry');
6
+ const {createChainAddress} = require('ln-service');
7
+ const {getChainTransactions} = require('ln-service');
8
+ const {getChannels} = require('ln-service');
9
+ const {getNetwork} = require('ln-sync');
10
+ const {getUtxos} = require('ln-service');
11
+ const {networks} = require('bitcoinjs-lib');
12
+ const {sendToChainAddress} = require('ln-service');
13
+ const {spawnLightningCluster} = require('ln-docker-daemons');
14
+ const {test} = require('@alexbosworth/tap');
15
+ const tinysecp = require('tiny-secp256k1');
16
+
17
+ const assembleChannelGroup = require('./../../groups/assemble_channel_group');
18
+ const {confirmIncomingChannel} = require('./../../groups/funding');
19
+ const {getGroupDetails} = require('./../../groups/p2p');
20
+ const joinChannelGroup = require('./../../groups/join_channel_group');
21
+
22
+ const capacity = 1e5;
23
+ const count = 102;
24
+ const feeRate = 1;
25
+ const interval = 10;
26
+ const size = 4;
27
+ const tokens = 1e6;
28
+ const times = 2000;
29
+
30
+ // Make a joint transaction channel group with a sort defined
31
+ test(`Setup sorted channel group`, async ({end, equal, strictSame}) => {
32
+ const ecp = (await import('ecpair')).ECPairFactory(tinysecp);
33
+ const {kill, nodes} = await spawnLightningCluster({size});
34
+
35
+ const [control, target, remote, extra] = nodes;
36
+
37
+ const {generate, lnd} = control;
38
+
39
+ try {
40
+ // Setup the cluster of nodes to have funds and be connected
41
+
42
+ // Make some funds for control
43
+ await generate({count});
44
+
45
+ // Get the bitcoinjs network
46
+ const network = networks[(await getNetwork({lnd})).bitcoinjs];
47
+
48
+ // Create a target chain address
49
+ const targetAddress = await createChainAddress({lnd: target.lnd});
50
+
51
+ // Send coins to target
52
+ await sendToChainAddress({lnd, tokens, address: targetAddress.address});
53
+
54
+ // Create a remote chain address
55
+ const remoteAddress = await createChainAddress({lnd: remote.lnd});
56
+
57
+ // Create an address on the extra node
58
+ const extraAddress = await createChainAddress({lnd: extra.lnd});
59
+
60
+ // Send coins to remote
61
+ await sendToChainAddress({lnd, tokens, address: remoteAddress.address});
62
+
63
+ // Send coins to extra
64
+ await sendToChainAddress({lnd, tokens, address: extraAddress.address});
65
+
66
+ // Wait for funds to arrive
67
+ await asyncRetry({interval, times}, async () => {
68
+ await generate({});
69
+
70
+ const {transactions} = await getChainTransactions({lnd});
71
+
72
+ if (!!transactions.filter(n => !n.is_confirmed).length) {
73
+ throw new Error('TransactionsAreUnconfirmed');
74
+ }
75
+ });
76
+
77
+ // Wait for UTXOs to be confirmed
78
+ await asyncRetry({interval, times}, async () => {
79
+ const remoteUtxos = await getUtxos({lnd: remote.lnd});
80
+ const targetUtxos = await getUtxos({lnd: target.lnd});
81
+
82
+ if (!targetUtxos.utxos.filter(n => !!n.confirmation_count).length) {
83
+ throw new Error('ExpectedConfirmedUtxoOnTarget');
84
+ }
85
+
86
+ if (!remoteUtxos.utxos.filter(n => !!n.confirmation_count).length) {
87
+ throw new Error('ExpectedConfirmUtxoOnRemote');
88
+ }
89
+ });
90
+
91
+ // Connect control to target
92
+ await addPeer({lnd, public_key: target.id, socket: target.socket});
93
+
94
+ // Connect target to remote
95
+ await addPeer({
96
+ lnd: target.lnd,
97
+ public_key: remote.id,
98
+ socket: remote.socket,
99
+ });
100
+
101
+ // Connect remote to control
102
+ await addPeer({
103
+ lnd: remote.lnd,
104
+ public_key: control.id,
105
+ socket: control.socket,
106
+ });
107
+
108
+ // Connect extra to the other nodes
109
+ await asyncMap([control, target, remote], async ({id, socket}) => {
110
+ await addPeer({socket, lnd: extra.lnd, public_key: id});
111
+ });
112
+
113
+ // Start Group Coordination
114
+
115
+ // Start the coordination
116
+ const assemble = assembleChannelGroup({
117
+ capacity,
118
+ ecp,
119
+ count: nodes.length,
120
+ identity: control.id,
121
+ lnd: control.lnd,
122
+ members: [control.id, extra.id, remote.id, target.id],
123
+ rate: feeRate,
124
+ });
125
+
126
+ const events = {};
127
+
128
+ assemble.events.once('broadcast', n => events.broadcast = n);
129
+ assemble.events.once('filled', n => events.filled = n);
130
+
131
+ // Target, remote, and extra join the group
132
+ const joins = await asyncMap([target, remote, extra], async node => {
133
+ const group = await getGroupDetails({
134
+ coordinator: control.id,
135
+ id: assemble.id,
136
+ lnd: node.lnd,
137
+ });
138
+
139
+ const join = joinChannelGroup({
140
+ capacity: group.capacity,
141
+ coordinator: control.id,
142
+ count: group.count,
143
+ id: assemble.id,
144
+ lnd: node.lnd,
145
+ rate: group.rate,
146
+ });
147
+
148
+ const [{inbound, outbound}] = await once(join, 'peering');
149
+
150
+ switch (node.id) {
151
+ case (extra.id):
152
+ strictSame(inbound, control.id, 'Extra inbound is control');
153
+ strictSame(outbound, remote.id, 'Extra outbound is remote');
154
+ break;
155
+
156
+ case (remote.id):
157
+ strictSame(inbound, extra.id, 'Remote inbound is extra');
158
+ strictSame(outbound, target.id, 'Remote outbound is target');
159
+ break;
160
+
161
+ case (target.id):
162
+ strictSame(inbound, remote.id, 'Target inbound is remote');
163
+ strictSame(outbound, control.id, 'Target outbound is control');
164
+ break;
165
+
166
+ default:
167
+ break;
168
+ }
169
+
170
+ strictSame(!!inbound, true, 'Received inbound peer');
171
+ strictSame(!!outbound, true, 'Received outbound peer');
172
+
173
+ const [tx] = await once(join, 'end');
174
+
175
+ return tx;
176
+ });
177
+
178
+ // Transaction ids of the open should be returned
179
+ const ids = joins.map(n => n.id);
180
+
181
+ // Finished, wait for the channels to activate
182
+ await generate({count});
183
+
184
+ await asyncRetry({interval, times}, async () => {
185
+ const {channels} = await getChannels({lnd, is_active: true});
186
+
187
+ if (!channels.length) {
188
+ throw new Error('ExpectedChannelActivation');
189
+ }
190
+ });
191
+
192
+ strictSame(events.broadcast.id.length, 64, 'Got broadcast tx id');
193
+ strictSame(!!events.broadcast.transaction, true, 'Got broadcast tx');
194
+ strictSame(events.filled.ids.length, nodes.length, 'Got filled event');
195
+ } catch (err) {
196
+ strictSame(err, null, 'Expected no failure');
197
+ } finally {
198
+ await kill({});
199
+ }
200
+
201
+ return end();
202
+ });
@@ -53,7 +53,7 @@ test(`Start offchain swap`, async ({end, equal, strictSame}) => {
53
53
  });
54
54
 
55
55
  await asyncRetry({interval, times}, async () => {
56
- const {channels} = await getChannels({lnd, is_actve: true});
56
+ const {channels} = await getChannels({lnd, is_active: true});
57
57
 
58
58
  if (!!channels.length) {
59
59
  return channels;
@@ -53,7 +53,7 @@ test(`Swap with claim path`, async ({end, equal, strictSame}) => {
53
53
  });
54
54
 
55
55
  await asyncRetry({interval, times}, async () => {
56
- const {channels} = await getChannels({lnd, is_actve: true});
56
+ const {channels} = await getChannels({lnd, is_active: true});
57
57
 
58
58
  if (!!channels.length) {
59
59
  return channels;
@@ -58,7 +58,7 @@ test(`Timeout a swap`, async ({end, equal, strictSame}) => {
58
58
  });
59
59
 
60
60
  await asyncRetry({interval, times}, async () => {
61
- const {channels} = await getChannels({lnd, is_actve: true});
61
+ const {channels} = await getChannels({lnd, is_active: true});
62
62
 
63
63
  if (!!channels.length) {
64
64
  return channels;