From ba411e4212030e7d7f12f1c1e9ed6c7f204f05e9 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 9 Jan 2021 15:44:38 -0400 Subject: [PATCH 01/14] make it clear it is a getter --- utils/lightningServices/lightning-services.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/lightningServices/lightning-services.js b/utils/lightningServices/lightning-services.js index 9c198c3b..6f61e0d9 100644 --- a/utils/lightningServices/lightning-services.js +++ b/utils/lightningServices/lightning-services.js @@ -74,6 +74,10 @@ class LightningServices { } } + getServices() { + return this.services + } + get servicesData() { return this.lnServicesData } From 79280e2d3011f372a98f8ed7032d1a9fca487dae Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 9 Jan 2021 16:17:52 -0400 Subject: [PATCH 02/14] wildcard import --- src/routes.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/routes.js b/src/routes.js index 715cd43d..c9313708 100644 --- a/src/routes.js +++ b/src/routes.js @@ -30,11 +30,7 @@ const { const GunActions = require('../services/gunDB/contact-api/actions') const GunGetters = require('../services/gunDB/contact-api/getters') const GunKey = require('../services/gunDB/contact-api/key') -const { - sendPaymentV2Keysend, - sendPaymentV2Invoice, - listPayments -} = require('../utils/lightningServices/v2') +const LV2 = require('../utils/lightningServices/v2') const GunWriteRPC = require('../services/gunDB/rpc') const DEFAULT_MAX_NUM_ROUTES_TO_QUERY = 10 @@ -1375,7 +1371,7 @@ module.exports = async ( } return res.status(200).json( - await listPayments({ + await LV2.listPayments({ include_incomplete, index_offset, max_payments, @@ -1662,7 +1658,7 @@ module.exports = async ( }) } - const payment = await sendPaymentV2Keysend({ + const payment = await LV2.sendPaymentV2Keysend({ amt, dest, feeLimit, @@ -1675,7 +1671,7 @@ module.exports = async ( } const { payreq } = req.body - const payment = await sendPaymentV2Invoice({ + const payment = await LV2.sendPaymentV2Invoice({ feeLimit, payment_request: payreq, amt: req.body.amt, From 34264db89575ee2759263c21733b7edca2712cc8 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 9 Jan 2021 16:25:55 -0400 Subject: [PATCH 03/14] typings --- utils/lightningServices/lightning-services.js | 3 +++ utils/lightningServices/types.ts | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/utils/lightningServices/lightning-services.js b/utils/lightningServices/lightning-services.js index 6f61e0d9..71ef98d9 100644 --- a/utils/lightningServices/lightning-services.js +++ b/utils/lightningServices/lightning-services.js @@ -74,6 +74,9 @@ class LightningServices { } } + /** + * @returns {import('./types').Services} + */ getServices() { return this.services } diff --git a/utils/lightningServices/types.ts b/utils/lightningServices/types.ts index f8e77d81..4b8b5781 100644 --- a/utils/lightningServices/types.ts +++ b/utils/lightningServices/types.ts @@ -106,3 +106,28 @@ export interface SendPaymentInvoiceParams { payment_request: string timeoutSeconds?: number } + +type StreamListener = (data: any) => void + +/** + * Caution: Not all methods return an stream. + */ +interface LightningStream { + on(ev: 'data' | 'end' | 'error' | 'status', listener: StreamListener): void +} + +type LightningCB = (err: Error, data: Record) => void + +type LightningMethod = ( + args: Record, + cb?: LightningCB +) => LightningStream + +/** + * Makes it easier for code calling services. + */ +export interface Services { + lightning: Record + walletUnlocker: Record + router: Record +} From a2fe681e18b7e35d1ffae38d798a939f07cb735d Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 9 Jan 2021 16:29:52 -0400 Subject: [PATCH 04/14] new newAddress --- src/routes.js | 29 ++++++++++------------------- utils/lightningServices/v2.js | 21 ++++++++++++++++++++- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/routes.js b/src/routes.js index c9313708..d0fb8359 100644 --- a/src/routes.js +++ b/src/routes.js @@ -1090,25 +1090,16 @@ module.exports = async ( }) // newaddress - app.post('/api/lnd/newaddress', (req, res) => { - const { lightning } = LightningServices.services - lightning.newAddress({ type: req.body.type }, async (err, response) => { - if (err) { - logger.debug('NewAddress Error:', err) - const health = await checkHealth() - if (health.LNDStatus.success) { - res.status(400).json({ - field: 'newAddress', - errorMessage: sanitizeLNDError(err.message) - }) - } else { - res.status(500) - res.json({ errorMessage: 'LND is down' }) - } - } - logger.debug('NewAddress:', response) - res.json(response) - }) + app.post('/api/lnd/newaddress', async (req, res) => { + try { + return res.json({ + address: await LV2.newAddress(req.body.type) + }) + } catch (e) { + return res.status(500).json({ + errorMessage: e.message + }) + } }) // connect peer to lnd node diff --git a/utils/lightningServices/v2.js b/utils/lightningServices/v2.js index 34f42f44..89132e47 100644 --- a/utils/lightningServices/v2.js +++ b/utils/lightningServices/v2.js @@ -402,9 +402,28 @@ const decodePayReq = payReq => ) }) +/** + * @param {0|1} type + * @returns {Promise} + */ +const newAddress = (type = 0) => { + const { lightning } = lightningServices.getServices() + + return Common.Utils.makePromise((res, rej) => { + lightning.newAddress({ type }, (err, response) => { + if (err) { + rej(new Error(err.message)) + } else { + res(response.address) + } + }) + }) +} + module.exports = { sendPaymentV2Keysend, sendPaymentV2Invoice, listPayments, - decodePayReq + decodePayReq, + newAddress } From f164efd2d0a054a48a81480ef2a0e531ba93afd3 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 9 Jan 2021 17:11:46 -0400 Subject: [PATCH 05/14] new listUnspent --- src/routes.js | 29 +++++++++++++---------------- utils/lightningServices/types.ts | 32 ++++++++++++++++++++++++++++++++ utils/lightningServices/v2.js | 31 ++++++++++++++++++++++++++++++- 3 files changed, 75 insertions(+), 17 deletions(-) diff --git a/src/routes.js b/src/routes.js index d0fb8359..19b24506 100644 --- a/src/routes.js +++ b/src/routes.js @@ -1946,22 +1946,19 @@ module.exports = async ( ) }) - app.post('/api/lnd/listunspent', (req, res) => { - const { lightning } = LightningServices.services - const { minConfirmations = 3, maxConfirmations = 6 } = req.body - lightning.listUnspent( - { - min_confs: minConfirmations, - max_confs: maxConfirmations - }, - (err, unspent) => { - if (err) { - return handleError(res, err) - } - logger.debug('ListUnspent:', unspent) - res.json(unspent) - } - ) + app.post('/api/lnd/listunspent', async (req, res) => { + try { + return res.status(200).json({ + utxos: await LV2.listUnspent( + req.body.minConfirmations, + req.body.maxConfirmations + ) + }) + } catch (e) { + return res.status(500).json({ + errorMessage: e.message + }) + } }) app.get('/api/lnd/transactions', (req, res) => { diff --git a/utils/lightningServices/types.ts b/utils/lightningServices/types.ts index 4b8b5781..6e3c2f33 100644 --- a/utils/lightningServices/types.ts +++ b/utils/lightningServices/types.ts @@ -131,3 +131,35 @@ export interface Services { walletUnlocker: Record router: Record } + +export interface Utxo { + /** + * The type of address. + */ + address_type: unknown + + /** + * The address. + */ + address: string + + /** + * The value of the unspent coin in satoshis. + */ + amount_sat: number + + /** + * The pkscript in hex. + */ + pk_script: string + + /** + * The outpoint in format txid:n. + */ + outpoint: unknown + + /** + * The number of confirmations for the Utxo. + */ + confirmations: number +} diff --git a/utils/lightningServices/v2.js b/utils/lightningServices/v2.js index 89132e47..bda5f6ee 100644 --- a/utils/lightningServices/v2.js +++ b/utils/lightningServices/v2.js @@ -420,10 +420,39 @@ const newAddress = (type = 0) => { }) } +/** + * @typedef {import('./types').Utxo} Utxo + */ + +/** + * @param {number} minConfs + * @param {number} maxConfs + * @returns {Promise} + */ +const listUnspent = (minConfs = 3, maxConfs = 6) => + Common.makePromise((res, rej) => { + const { lightning } = lightningServices.getServices() + + lightning.listUnspent( + { + min_confs: minConfs, + max_confs: maxConfs + }, + (err, unspent) => { + if (err) { + rej(new Error(err.message)) + } else { + res(unspent.utxos) + } + } + ) + }) + module.exports = { sendPaymentV2Keysend, sendPaymentV2Invoice, listPayments, decodePayReq, - newAddress + newAddress, + listUnspent } From 4665e9332be6983035253edccadb4b1ce22ec9a1 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sun, 10 Jan 2021 09:33:30 -0400 Subject: [PATCH 06/14] use types from common --- utils/lightningServices/types.ts | 32 -------------------------------- utils/lightningServices/v2.js | 6 +----- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/utils/lightningServices/types.ts b/utils/lightningServices/types.ts index 6e3c2f33..4b8b5781 100644 --- a/utils/lightningServices/types.ts +++ b/utils/lightningServices/types.ts @@ -131,35 +131,3 @@ export interface Services { walletUnlocker: Record router: Record } - -export interface Utxo { - /** - * The type of address. - */ - address_type: unknown - - /** - * The address. - */ - address: string - - /** - * The value of the unspent coin in satoshis. - */ - amount_sat: number - - /** - * The pkscript in hex. - */ - pk_script: string - - /** - * The outpoint in format txid:n. - */ - outpoint: unknown - - /** - * The number of confirmations for the Utxo. - */ - confirmations: number -} diff --git a/utils/lightningServices/v2.js b/utils/lightningServices/v2.js index bda5f6ee..e9d5d0cc 100644 --- a/utils/lightningServices/v2.js +++ b/utils/lightningServices/v2.js @@ -420,14 +420,10 @@ const newAddress = (type = 0) => { }) } -/** - * @typedef {import('./types').Utxo} Utxo - */ - /** * @param {number} minConfs * @param {number} maxConfs - * @returns {Promise} + * @returns {Promise} */ const listUnspent = (minConfs = 3, maxConfs = 6) => Common.makePromise((res, rej) => { From bb0941d6e97c753301bd70373d0436b1520e2869 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sun, 10 Jan 2021 09:55:19 -0400 Subject: [PATCH 07/14] new listChannels() --- src/routes.js | 30 +++++++++++------------------- utils/lightningServices/types.ts | 13 +++++++++++++ utils/lightningServices/v2.js | 24 +++++++++++++++++++++++- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/routes.js b/src/routes.js index 19b24506..f10fd1eb 100644 --- a/src/routes.js +++ b/src/routes.js @@ -1144,25 +1144,17 @@ module.exports = async ( }) // get lnd node opened channels list - app.get('/api/lnd/listchannels', (req, res) => { - const { lightning } = LightningServices.services - lightning.listChannels({}, async (err, response) => { - if (err) { - logger.debug('ListChannels Error:', err) - const health = await checkHealth() - if (health.LNDStatus.success) { - res.status(400).json({ - field: 'listChannels', - errorMessage: sanitizeLNDError(err.message) - }) - } else { - res.status(500) - res.json({ errorMessage: 'LND is down' }) - } - } - logger.debug('ListChannels:', response) - res.json(response) - }) + app.get('/api/lnd/listchannels', async (_, res) => { + try { + return res.json({ + channels: await LV2.listChannels() + }) + } catch (e) { + console.log(e) + return res.status(500).json({ + errorMessage: e.message + }) + } }) // get lnd node pending channels list diff --git a/utils/lightningServices/types.ts b/utils/lightningServices/types.ts index 4b8b5781..faa7f0b9 100644 --- a/utils/lightningServices/types.ts +++ b/utils/lightningServices/types.ts @@ -1,6 +1,7 @@ /** * @format */ +import * as Common from 'shock-common' export interface PaymentV2 { payment_hash: string @@ -131,3 +132,15 @@ export interface Services { walletUnlocker: Record router: Record } + +export interface ListChannelsReq { + active_only: boolean + inactive_only: boolean + public_only: boolean + private_only: boolean + /** + * Filters the response for channels with a target peer's pubkey. If peer is + * empty, all channels will be returned. + */ + peer: Common.Bytes +} diff --git a/utils/lightningServices/v2.js b/utils/lightningServices/v2.js index e9d5d0cc..467a15c8 100644 --- a/utils/lightningServices/v2.js +++ b/utils/lightningServices/v2.js @@ -444,11 +444,33 @@ const listUnspent = (minConfs = 3, maxConfs = 6) => ) }) +/** + * @typedef {import('./types').ListChannelsReq} ListChannelsReq + */ + +/** + * @param {ListChannelsReq} req + * @returns {Promise} + */ +const listChannels = req => + Common.makePromise((res, rej) => { + const { lightning } = lightningServices.getServices() + + lightning.listChannels(req, (err, resp) => { + if (err) { + rej(new Error(err.message)) + } else { + res(resp.channels) + } + }) + }) + module.exports = { sendPaymentV2Keysend, sendPaymentV2Invoice, listPayments, decodePayReq, newAddress, - listUnspent + listUnspent, + listChannels } From f517fd6090fca0dfe1d9696c667e1de40883e042 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sun, 10 Jan 2021 10:20:58 -0400 Subject: [PATCH 08/14] getChanInfo() --- utils/lightningServices/v2.js | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/utils/lightningServices/v2.js b/utils/lightningServices/v2.js index 467a15c8..6857d870 100644 --- a/utils/lightningServices/v2.js +++ b/utils/lightningServices/v2.js @@ -465,6 +465,31 @@ const listChannels = req => }) }) +/** + * https://api.lightning.community/#getchaninfo + * @param {string} chanID + * @returns {Promise} + */ +const getChanInfo = chanID => + Common.makePromise((res, rej) => { + const { lightning } = lightningServices.getServices() + + lightning.getChanInfo( + { + chan_id: chanID + }, + (err, resp) => { + if (err) { + rej(new Error(err.message)) + } else { + // Needs cast because typescript refuses to assign Record + // to an actual object :shrugs + res(/** @type {Common.ChannelEdge} */ (resp)) + } + } + ) + }) + module.exports = { sendPaymentV2Keysend, sendPaymentV2Invoice, @@ -472,5 +497,6 @@ module.exports = { decodePayReq, newAddress, listUnspent, - listChannels + listChannels, + getChanInfo } From 4a3a802a2a04f62397b28c661f637bff50b6f82b Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sun, 10 Jan 2021 10:33:36 -0400 Subject: [PATCH 09/14] route body snippet --- .vscode/snippets.code-snippets | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .vscode/snippets.code-snippets diff --git a/.vscode/snippets.code-snippets b/.vscode/snippets.code-snippets new file mode 100644 index 00000000..53bd01c5 --- /dev/null +++ b/.vscode/snippets.code-snippets @@ -0,0 +1,33 @@ +{ + // Place your api workspace snippets here. Each snippet is defined under a + // snippet name and has a scope, prefix, body and description. Add comma + // separated ids of the languages where the snippet is applicable in the scope + // field. If scope is left empty or omitted, the snippet gets applied to all + // languages. The prefix is what is used to trigger the snippet and the body + // will be expanded and inserted. Possible variables are: $1, $2 for tab + // stops, $0 for the final cursor position, and ${1:label}, ${2:another} for + // placeholders. Placeholders with the same ids are connected. Example: "Print + // to console": {"scope": "javascript,typescript", "prefix": "log", "body": + // ["console.log('$1');", "$2" + // ], + // "description": "Log output to console" + // } + + "Route Body": { + "body": [ + "try {", + " return res.json({", + "", + " })", + "} catch (e) {", + " console.log(e)", + " return res.status(500).json({", + " errorMessage: e.message", + " })", + "}" + ], + "description": "Route Body", + "prefix": "rbody", + "scope": "javascript" + } +} \ No newline at end of file From c5e48b1eb50aef48a55c733f71b8206851bcd927 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sun, 10 Jan 2021 10:33:43 -0400 Subject: [PATCH 10/14] use new getChanInfo() --- src/routes.js | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/src/routes.js b/src/routes.js index f10fd1eb..7de4143e 100644 --- a/src/routes.js +++ b/src/routes.js @@ -1020,30 +1020,15 @@ module.exports = async ( ) }) // get lnd chan info - app.post('/api/lnd/getchaninfo', (req, res) => { - const { lightning } = LightningServices.services - - lightning.getChanInfo( - { chan_id: req.body.chan_id }, - async (err, response) => { - if (err) { - logger.debug('GetChanInfo Error:', err) - const health = await checkHealth() - if (health.LNDStatus.success) { - res.status(400) - res.json({ - field: 'getChanInfo', - errorMessage: sanitizeLNDError(err.message) - }) - } else { - res.status(500) - res.json({ errorMessage: 'LND is down' }) - } - } - logger.debug('GetChanInfo:', response) - res.json(response) - } - ) + app.post('/api/lnd/getchaninfo', async (req, res) => { + try { + return res.json(await LV2.getChanInfo(req.body.chan_id)) + } catch (e) { + console.log(e) + return res.status(500).json({ + errorMessage: e.message + }) + } }) app.get('/api/lnd/getnetworkinfo', (req, res) => { From 5cab6deeb17c04b0243cac229365394e481a519b Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sun, 10 Jan 2021 13:27:03 -0400 Subject: [PATCH 11/14] new listPeers() --- src/routes.js | 30 +++++++++++------------------- utils/lightningServices/v2.js | 28 +++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/routes.js b/src/routes.js index 7de4143e..99ed7dcf 100644 --- a/src/routes.js +++ b/src/routes.js @@ -1053,25 +1053,17 @@ module.exports = async ( }) // get lnd node active channels list - app.get('/api/lnd/listpeers', (req, res) => { - const { lightning } = LightningServices.services - lightning.listPeers({}, async (err, response) => { - if (err) { - logger.debug('ListPeers Error:', err) - const health = await checkHealth() - if (health.LNDStatus.success) { - res.status(400).json({ - field: 'listPeers', - errorMessage: sanitizeLNDError(err.message) - }) - } else { - res.status(500) - res.json({ errorMessage: 'LND is down' }) - } - } - logger.debug('ListPeers:', response) - res.json(response) - }) + app.get('/api/lnd/listpeers', async (req, res) => { + try { + return res.json({ + peers: await LV2.listPeers(req.body.latestError) + }) + } catch (e) { + console.log(e) + return res.status(500).json({ + errorMessage: e.message + }) + } }) // newaddress diff --git a/utils/lightningServices/v2.js b/utils/lightningServices/v2.js index 6857d870..a158aed1 100644 --- a/utils/lightningServices/v2.js +++ b/utils/lightningServices/v2.js @@ -490,6 +490,31 @@ const getChanInfo = chanID => ) }) +/** + * https://api.lightning.community/#listpeers + * @param {boolean=} latestError If true, only the last error that our peer sent + * us will be returned with the peer's information, rather than the full set of + * historic errors we have stored. + * @returns {Promise} + */ +const listPeers = latestError => + Common.makePromise((res, rej) => { + const { lightning } = lightningServices.getServices() + + lightning.listPeers( + { + latest_error: latestError + }, + (err, resp) => { + if (err) { + rej(new Error(err.message)) + } else { + res(resp.peers) + } + } + ) + }) + module.exports = { sendPaymentV2Keysend, sendPaymentV2Invoice, @@ -498,5 +523,6 @@ module.exports = { newAddress, listUnspent, listChannels, - getChanInfo + getChanInfo, + listPeers } From d6cdba227693ffb0da7b6a2079bdadd8f4ef09a5 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sun, 10 Jan 2021 16:54:54 -0400 Subject: [PATCH 12/14] pending channels --- src/routes.js | 29 +++++++++-------------------- utils/lightningServices/types.ts | 22 ++++++++++++++++++++++ utils/lightningServices/v2.js | 25 ++++++++++++++++++++++++- 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/routes.js b/src/routes.js index 99ed7dcf..9697d46d 100644 --- a/src/routes.js +++ b/src/routes.js @@ -1134,26 +1134,15 @@ module.exports = async ( } }) - // get lnd node pending channels list - app.get('/api/lnd/pendingchannels', (req, res) => { - const { lightning } = LightningServices.services - lightning.pendingChannels({}, async (err, response) => { - if (err) { - logger.debug('PendingChannels Error:', err) - const health = await checkHealth() - if (health.LNDStatus.success) { - res.status(400).json({ - field: 'pendingChannels', - errorMessage: sanitizeLNDError(err.message) - }) - } else { - res.status(500) - res.json({ errorMessage: 'LND is down' }) - } - } - logger.debug('PendingChannels:', response) - res.json(response) - }) + app.get('/api/lnd/pendingchannels', async (req, res) => { + try { + return res.json(await LV2.pendingChannels()) + } catch (e) { + console.log(e) + return res.status(500).json({ + errorMessage: e.message + }) + } }) app.get('/api/lnd/unifiedTrx', (req, res) => { diff --git a/utils/lightningServices/types.ts b/utils/lightningServices/types.ts index faa7f0b9..c390d545 100644 --- a/utils/lightningServices/types.ts +++ b/utils/lightningServices/types.ts @@ -144,3 +144,25 @@ export interface ListChannelsReq { */ peer: Common.Bytes } + +/** + * https://api.lightning.community/#pendingchannels + */ +export interface PendingChannelsRes { + /** + * The balance in satoshis encumbered in pending channels. + */ + total_limbo_balance: string + /** + * Channels pending opening. + */ + pending_open_channels: Common.PendingOpenChannel[] + /** + * Channels pending force closing. + */ + pending_force_closing_channels: Common.ForceClosedChannel[] + /** + * Channels waiting for closing tx to confirm. + */ + waiting_close_channels: Common.WaitingCloseChannel[] +} diff --git a/utils/lightningServices/v2.js b/utils/lightningServices/v2.js index a158aed1..07c5574a 100644 --- a/utils/lightningServices/v2.js +++ b/utils/lightningServices/v2.js @@ -515,6 +515,28 @@ const listPeers = latestError => ) }) +/** + * @typedef {import('./types').PendingChannelsRes} PendingChannelsRes + */ + +/** + * @returns {Promise} + */ +const pendingChannels = () => + Common.makePromise((res, rej) => { + const { lightning } = lightningServices.getServices() + + lightning.pendingChannels({}, (err, resp) => { + if (err) { + rej(new Error(err.message)) + } else { + // Needs cast because typescript refuses to assign Record + // to an actual object :shrugs + res(/** @type {PendingChannelsRes} */ (resp)) + } + }) + }) + module.exports = { sendPaymentV2Keysend, sendPaymentV2Invoice, @@ -524,5 +546,6 @@ module.exports = { listUnspent, listChannels, getChanInfo, - listPeers + listPeers, + pendingChannels } From 427c896f42e8fff18f41531b5643e5fecf21d618 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 13 Jan 2021 17:34:38 -0400 Subject: [PATCH 13/14] new "addInvoice()" --- src/routes.js | 82 ++++++++++---------------------- utils/lightningServices/types.ts | 28 +++++++++++ utils/lightningServices/v2.js | 37 +++++++++++++- 3 files changed, 89 insertions(+), 58 deletions(-) diff --git a/src/routes.js b/src/routes.js index 9697d46d..e38e0afa 100644 --- a/src/routes.js +++ b/src/routes.js @@ -1709,64 +1709,32 @@ module.exports = async ( }) // addinvoice - app.post('/api/lnd/addinvoice', (req, res) => { - const { lightning } = LightningServices.services - const invoiceRequest = { memo: req.body.memo, private: true } - if (req.body.value) { - invoiceRequest.value = req.body.value - } - if (req.body.expiry) { - invoiceRequest.expiry = req.body.expiry - } - lightning.addInvoice(invoiceRequest, async (err, newInvoice) => { - if (err) { - logger.debug('AddInvoice Error:', err) - const health = await checkHealth() - if (health.LNDStatus.success) { - res.status(400).json({ - field: 'addInvoice', - errorMessage: sanitizeLNDError(err.message) - }) - } else { - res.status(500) - res.json({ errorMessage: 'LND is down' }) + app.post('/api/lnd/addinvoice', async (req, res) => { + const { expiry, value, memo } = req.body + const addInvoiceRes = await LV2.addInvoice(value, memo, true, expiry) + + if (value) { + const channelsList = await LV2.listChannels({ active_only: true }) + let remoteBalance = Big(0) + channelsList.forEach(element => { + const remB = Big(element.remote_balance) + if (remB.gt(remoteBalance)) { + remoteBalance = remB } - return err - } - logger.debug('AddInvoice:', newInvoice) - if (req.body.value) { - logger.debug('AddInvoice liquidity check:') - lightning.listChannels({ active_only: true }, async (err, response) => { - if (err) { - logger.debug('ListChannels Error:', err) - const health = await checkHealth() - if (health.LNDStatus.success) { - res.status(400).json({ - field: 'listChannels', - errorMessage: sanitizeLNDError(err.message) - }) - } else { - res.status(500) - res.json({ errorMessage: 'LND is down' }) - } - } - logger.debug('ListChannels:', response) - const channelsList = response.channels - let remoteBalance = Big(0) - channelsList.forEach(element => { - const remB = Big(element.remote_balance) - if (remB.gt(remoteBalance)) { - remoteBalance = remB - } - }) - newInvoice.liquidityCheck = remoteBalance > req.body.value - //newInvoice.remoteBalance = remoteBalance - res.json(newInvoice) - }) - } else { - res.json(newInvoice) - } - }) + }) + + addInvoiceRes.liquidityCheck = remoteBalance > value + //newInvoice.remoteBalance = remoteBalance + } + + try { + return res.json(addInvoiceRes) + } catch (e) { + console.log(e) + return res.status(500).json({ + errorMessage: e.message + }) + } }) // signmessage diff --git a/utils/lightningServices/types.ts b/utils/lightningServices/types.ts index c390d545..ca0d034f 100644 --- a/utils/lightningServices/types.ts +++ b/utils/lightningServices/types.ts @@ -166,3 +166,31 @@ export interface PendingChannelsRes { */ waiting_close_channels: Common.WaitingCloseChannel[] } + +/** + * https://github.com/lightningnetwork/lnd/blob/daf7c8a85420fc67fffa18fa5f7d08c2040946e4/lnrpc/rpc.proto#L2948 + */ +export interface AddInvoiceRes { + /** + * + */ + r_hash: Common.Bytes + /** + * A bare-bones invoice for a payment within the Lightning Network. With the + * details of the invoice, the sender has all the data necessary to send a + * payment to the recipient. + */ + payment_request: string + /** + * The "add" index of this invoice. Each newly created invoice will increment + * this index making it monotonically increasing. Callers to the + * SubscribeInvoices call can use this to instantly get notified of all added + * invoices with an add_index greater than this one. + */ + add_index: string + /** + * The payment address of the generated invoice. This value should be used in + * all payments for this invoice as we require it for end to end security. + */ + payment_addr: Common.Bytes +} diff --git a/utils/lightningServices/v2.js b/utils/lightningServices/v2.js index 07c5574a..b933c63b 100644 --- a/utils/lightningServices/v2.js +++ b/utils/lightningServices/v2.js @@ -537,6 +537,40 @@ const pendingChannels = () => }) }) +/** + * @typedef {import('./types').AddInvoiceRes} AddInvoiceRes + */ +/** + * https://api.lightning.community/#addinvoice + * @param {number} value + * @param {string=} memo + * @param {boolean=} confidential Alias for `private`. + * @param {number=} expiry + * @returns {Promise} + */ +const addInvoice = (value, memo = '', confidential = true, expiry = 180) => + Common.makePromise((res, rej) => { + const { lightning } = lightningServices.getServices() + + lightning.addInvoice( + { + value, + memo, + private: confidential, + expiry + }, + (err, resp) => { + if (err) { + rej(new Error(err.message)) + } else { + // Needs cast because typescript refuses to assign Record + // to an actual object :shrugs + res(/** @type {AddInvoiceRes} */ (resp)) + } + } + ) + }) + module.exports = { sendPaymentV2Keysend, sendPaymentV2Invoice, @@ -547,5 +581,6 @@ module.exports = { listChannels, getChanInfo, listPeers, - pendingChannels + pendingChannels, + addInvoice } From e4caaac67e3038fd8a4a421887698cc542e3f187 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 13 Jan 2021 17:38:29 -0400 Subject: [PATCH 14/14] POST -> GET --- src/routes.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/routes.js b/src/routes.js index e38e0afa..f61a4857 100644 --- a/src/routes.js +++ b/src/routes.js @@ -1872,7 +1872,7 @@ module.exports = async ( ) }) - app.post('/api/lnd/listunspent', async (req, res) => { + const listunspent = async (req, res) => { try { return res.status(200).json({ utxos: await LV2.listUnspent( @@ -1885,7 +1885,12 @@ module.exports = async ( errorMessage: e.message }) } - }) + } + + app.get('/api/lnd/listunspent', listunspent) + + // TODO: should be GET + app.post('/api/lnd/listunspent', listunspent) app.get('/api/lnd/transactions', (req, res) => { const { lightning } = LightningServices.services