lightning
Version:
Lightning Network client library
196 lines (171 loc) • 6.78 kB
JavaScript
const asyncAuto = require('async/auto');
const asyncRetry = require('async/retry');
const {returnResult} = require('asyncjs-util');
const {htlcAsPayment} = require('./../../lnd_responses');
const {isLnd} = require('./../../lnd_requests');
const {rpcInvoiceAsInvoice} = require('./../../lnd_responses');
const {sortBy} = require('./../../arrays');
const asStart = n => !!n ? Math.floor(new Date(n).getTime() / 1e3) : undefined;
const asEnd = n => !!n ? Math.ceil(new Date(n).getTime() / 1e3) : undefined;
const createdAtSort = array => sortBy({array, attribute: 'created_at'});
const defaultLimit = 100;
const {isArray} = Array;
const isString = n => typeof n === 'string';
const lastPageFirstIndexOffset = 1;
const method = 'listInvoices';
const {parse} = JSON;
const {stringify} = JSON;
const type = 'default';
/** Get all created invoices.
If a next token is returned, pass it to get another page of invoices.
Requires `invoices:read` permission
Invoice `payment` is not supported on LND 0.11.1 and below
`created_after` is not supported on LND 0.15.5 and below
`created_before` is not supported on LND 0.15.5 and below
{
[created_after]: <Creation Date After or Equal to ISO 8601 Date String>
[created_before]: <Creation Date Before or Equal to ISO 8601 Date String>
[is_unconfirmed]: <Omit Canceled and Settled Invoices Bool>
[limit]: <Page Result Limit Number>
lnd: <Authenticated LND API Object>
[token]: <Opaque Paging Token String>
}
@returns via cbk or Promise
{
invoices: [{
[chain_address]: <Fallback Chain Address String>
cltv_delta: <Final CLTV Delta Number>
[confirmed_at]: <Settled at ISO 8601 Date String>
[confirmed_index]: <Confirmed Index Number>
created_at: <ISO 8601 Date String>
description: <Description String>
[description_hash]: <Description Hash Hex String>
expires_at: <ISO 8601 Date String>
features: [{
bit: <BOLT 09 Feature Bit Number>
is_known: <Feature is Known Bool>
is_required: <Feature Support is Required To Pay Bool>
type: <Feature Type String>
}]
id: <Payment Hash Hex String>
index: <Index Number>
[is_canceled]: <Invoice is Canceled Bool>
is_confirmed: <Invoice is Confirmed Bool>
[is_held]: <HTLC is Held Bool>
is_private: <Invoice is Private Bool>
[is_push]: <Invoice is Push Payment Bool>
mtokens: <Millitokens String>
[payment]: <Payment Identifying Secret Hex String>
payments: [{
[canceled_at]: <Payment Canceled At ISO 8601 Date String>
[confirmed_at]: <Payment Settled At ISO 8601 Date String>
created_at: <Payment Held Since ISO 860 Date String>
created_height: <Payment Held Since Block Height Number>
in_channel: <Incoming Payment Through Channel Id String>
is_canceled: <Payment is Canceled Bool>
is_confirmed: <Payment is Confirmed Bool>
is_held: <Payment is Held Bool>
messages: [{
type: <Message Type Number String>
value: <Raw Value Hex String>
}]
mtokens: <Incoming Payment Millitokens String>
[pending_index]: <Pending Payment Channel HTLC Index Number>
timeout: <HTLC CLTV Timeout Height Number>
tokens: <Payment Tokens Number>
[total_mtokens]: <Total Millitokens String>
}]
received: <Received Tokens Number>
received_mtokens: <Received Millitokens String>
[request]: <Bolt 11 Invoice String>
secret: <Secret Preimage Hex String>
tokens: <Tokens Number>
}]
[next]: <Next Opaque Paging Token String>
}
*/
module.exports = (args, cbk) => {
return new Promise((resolve, reject) => {
return asyncAuto({
// Validate arguments
validate: cbk => {
if (!!args.limit && !!args.token) {
return cbk([400, 'UnexpectedLimitWhenPagingInvoicesWithToken']);
}
if (!isLnd({method, type, lnd: args.lnd})) {
return cbk([400, 'ExpectedLndForInvoiceListing']);
}
return cbk();
},
// Get the list of invoices
listInvoices: ['validate', ({}, cbk) => {
let after = asStart(args.created_after);
let before = asEnd(args.created_before);
let limit = args.limit || defaultLimit;
let offset;
// When there is a token, parse it out into an offset and a limit
if (!!args.token) {
try {
const pagingToken = parse(args.token);
after = pagingToken.after;
before = pagingToken.before;
offset = pagingToken.offset;
limit = pagingToken.limit;
} catch (err) {
return cbk([400, 'ExpectedValidPagingTokenForInvoicesReq', {err}]);
}
}
return asyncRetry({}, cbk => {
return args.lnd[type][method]({
creation_date_start: after,
creation_date_end: before,
index_offset: offset || Number(),
num_max_invoices: limit,
pending_only: args.is_unconfirmed === true || undefined,
reversed: true,
},
(err, res) => {
if (!!err) {
return cbk([503, 'UnexpectedGetInvoicesError', {err}]);
}
if (!res) {
return cbk([503, 'ExpectedResponseForListInvoicesRequest']);
}
if (!isArray(res.invoices)) {
return cbk([503, 'ExpectedInvoicesListForInvoicesQuery']);
}
if (!isString(res.first_index_offset)) {
return cbk([503, 'ExpectedFirstIndexOffsetForInvoicesQuery']);
}
if (!isString(res.last_index_offset)) {
return cbk([503, 'ExpectedLastIndexOffsetForInvoicesQuery']);
}
const offset = Number(res.first_index_offset);
const token = stringify({after, before, limit, offset});
return cbk(null, {
invoices: res.invoices,
token: offset === lastPageFirstIndexOffset ? undefined : token,
});
});
},
cbk);
}],
// Mapped invoices
mapped: ['listInvoices', ({listInvoices}, cbk) => {
try {
return cbk(null, listInvoices.invoices.map(rpcInvoiceAsInvoice));
} catch (err) {
return cbk([503, err.message]);
}
}],
// Sorted invoices
sorted: ['listInvoices', 'mapped', ({listInvoices, mapped}, cbk) => {
return cbk(null, {
invoices: createdAtSort(mapped).sorted.reverse(),
next: !!mapped.length ? listInvoices.token : undefined,
});
}],
},
returnResult({reject, resolve, of: 'sorted'}, cbk));
});
};