UNPKG

paid-services

Version:
129 lines (102 loc) 3.96 kB
const asyncAuto = require('async/auto'); const asyncMap = require('async/map'); const {broadcastTransaction} = require('ln-sync'); const {getIdentity} = require('ln-service'); const {getNodeAlias} = require('ln-sync'); const {returnResult} = require('asyncjs-util'); const tinysecp = require('tiny-secp256k1'); const askForGroupDetails = require('./ask_for_group_details'); const assembleChannelGroup = require('./assemble_channel_group'); const descriptionForGroup = 'group channel open'; const join = arr => arr.join(', '); const niceName = ({alias, id}) => `${alias} ${id}`.trim(); /** Ask for the details of the group to create and then create the group { ask: <Ask Function> lnd: <Authenticated LND API Object> logger: <Winston Logger Object> } @returns via cbk or Promise */ module.exports = ({ask, lnd, logger}, cbk) => { return new Promise((resolve, reject) => { return asyncAuto({ // Import ECPair library ecp: async () => (await import('ecpair')).ECPairFactory(tinysecp), // Check arguments validate: cbk => { if (!ask) { return cbk([400, 'ExpectedAskFunctionToCreateGroup']); } if (!lnd) { return cbk([400, 'ExpectedAuthenticatedLndToCreateGroup']); } if (!logger) { return cbk([400, 'ExpectedWinstonLoggerToCreateGroup']); } return cbk(); }, // Ask for group details askForDetails: ['validate', ({}, cbk) => { return askForGroupDetails({ask, lnd}, cbk); }], // Get identity public key getIdentity: ['validate', ({}, cbk) => getIdentity({lnd}, cbk)], // Fund and assemble the group assembleGroup: [ 'ecp', 'askForDetails', 'getIdentity', ({ecp, askForDetails, getIdentity}, cbk) => { const coordinate = assembleChannelGroup({ ecp, lnd, capacity: askForDetails.capacity, count: askForDetails.count, identity: getIdentity.public_key, rate: askForDetails.rate, }); const code = getIdentity.public_key + coordinate.id; logger.info({group_invite_code: code}); // The group must fill up with participants first coordinate.events.once('filled', async ({ids}) => { const members = ids.filter(n => n !== getIdentity.public_key); const nodes = await asyncMap(members, async id => { return niceName(await getNodeAlias({id, lnd})); }); return logger.info({ready: join(nodes)}); }); // Once filled, members will connect with their partners coordinate.events.once('connected', () => logger.info({peered: true})); // Members will propose pending channels to each other coordinate.events.once('proposed', ({unsigned}) => { return logger.info({proposed: unsigned}); }); // Once all pending channels are in place, signatures will be received coordinate.events.once('signed', signed => logger.info({signed})); // Finally the open channel tx will be broadcast coordinate.events.once('broadcasting', broadcast => { return logger.info({publishing: broadcast.transaction}); }); // Finally the open channel tx is broadcast coordinate.events.once('broadcast', broadcast => { coordinate.events.removeAllListeners(); logger.info({transaction_id: broadcast.id}); return broadcastTransaction({ lnd, logger, description: descriptionForGroup, transaction: broadcast.transaction, }, cbk); }); coordinate.events.once('error', err => { return cbk([503, 'UnexpectedErrorAssemblingChannelGroup', {err}]); }); return; }], }, returnResult({reject, resolve, of: 'assembleGroup'}, cbk)); }); };