UNPKG

balanceofsatoshis

Version:
201 lines (169 loc) 5.57 kB
const asyncAuto = require('async/auto'); const {getNodeAlias} = require('ln-sync'); const moment = require('moment'); const {returnResult} = require('asyncjs-util'); const {parsePaymentRequest} = require('ln-service'); const getPayRequest = require('./get_pay_request'); const getPayTerms = require('./get_pay_terms'); const parseUrl = require('./parse_url'); const {pay} = require('./../network'); const {isArray} = Array; const isNumber = n => !isNaN(n); const {round} = Math; const tokensAsBigUnit = tokens => (tokens / 1e8).toFixed(8); const tokensAsMillitokens = n => n * 1000; /** Pay to lnurl { ask: <Ask Function> avoid: [<Avoid Forwarding Through String>] [fs]: { getFile: <Read File Contents Function> (path, cbk) => {} } lnd: <Authenticated LND API Object> lnurl: <Lnurl String> logger: <Winston Logger Object> max_fee: <Max Fee Tokens Number> max_paths: <Maximum Paths Number> out: [<Out Through Peer With Public Key Hex String>] request: <Request Function> } @returns via cbk or Promise */ module.exports = (args, cbk) => { return new Promise((resolve, reject) => { return asyncAuto({ // Check arguments validate: cbk => { if (!args.ask) { return cbk([400, 'ExpectedAskFunctionToGetPaymentRequestFromLnurl']); } if (!isArray(args.avoid)) { return cbk([400, 'ExpectedAvoidArrayToGetPaymentRequestFromLnurl']); } if (!args.lnurl) { return cbk([400, 'ExpectedUrlToGetPaymentRequestFromLnurl']); } try { parseUrl({url: args.lnurl}); } catch (err) { return cbk([400, err.message]); } if (!args.lnd) { return cbk([400, 'ExpectedLndToGetPaymentRequestFromLnurl']); } if (!args.logger) { return cbk([400, 'ExpectedLoggerToGetPaymentRequestFromLnurl']); } if (!args.max_fee) { return cbk([400, 'ExpectedMaxFeeToGetPaymentRequestFromLnurl']); } if (!args.max_paths) { return cbk([400, 'ExpectedMaxPathsCountToPayViaLnurl']); } if (!isArray(args.out)) { return cbk([400, 'ExpectedArrayOfOutPeersToPayViaLnurl']); } if (!args.request) { return cbk([400, 'ExpectedRequestFunctionToGetLnurlData']); } return cbk(); }, // Get accepted terms from the encoded url getTerms: ['validate', ({}, cbk) => { return getPayTerms({ request: args.request, url: parseUrl({url: args.lnurl}).url, }, cbk); }], // Ask the user for how much they want to send askAmount: ['getTerms', ({getTerms}, cbk) => { const {max} = getTerms; const {min} = getTerms; return args.ask({ default: getTerms.min, message: `Amount to pay? (min: ${min}, max: ${max})`, name: 'amount', type: 'input', validate: input => { if (!input) { return false; } // The amount should be numeric in sats if (!isNumber(input)) { return false; } if (round(input) !== Number(input)) { return 'Fractional amounts are not supported'; } if (Number(input) > max) { return `Service max sendable is ${max}, try a lower amount?`; } if (Number(input) < min) { return `Service min sendable is ${min}, try a higher amount?`; } return true; }, }, ({amount}) => cbk(null, tokensAsMillitokens(Number(amount)))); }], // Get payment request getRequest: ['askAmount', 'getTerms', ({askAmount, getTerms}, cbk) => { return getPayRequest({ hash: getTerms.hash, mtokens: askAmount.toString(), request: args.request, url: getTerms.url, }, cbk); }], // Get the destination node alias getAlias: ['getRequest', ({getRequest}, cbk) => { return getNodeAlias({id: getRequest.destination, lnd: args.lnd}, cbk); }], // Confirm payment confirm: [ 'getAlias', 'getRequest', 'getTerms', ({getAlias, getRequest, getTerms}, cbk) => { const details = parsePaymentRequest({request: getRequest.request}); args.logger.info({ amount: details.safe_tokens, description: getTerms.description, payment_request: getRequest.request, expires: moment(details.expires_at).fromNow(), }); const to = `${getAlias.alias} ${getAlias.id}`.trim(); return args.ask({ message: `Pay ${tokensAsBigUnit(details.safe_tokens)} to ${to}?`, name: 'ok', type: 'confirm', default: true, }, ({ok}) => { if (!ok) { return cbk([400, 'PaymentRequestPaymentCanceled']); } return cbk(); }); }], // Pay the payment request pay: ['confirm', 'getRequest', ({getRequest}, cbk) => { return pay({ avoid: args.avoid, fs: args.fs, lnd: args.lnd, logger: args.logger, max_fee: args.max_fee, max_paths: args.max_paths, out: args.out, request: getRequest.request, }, cbk); }], }, returnResult({reject, resolve, of: 'pay'}, cbk)); }); };