Payments and invoices controllers

clnrest-migration
ShahanaFarooqui 7 months ago
parent d361df0cff
commit 89a4f3558e

@ -15,7 +15,7 @@ export const getBalance = (req, res, next) => {
let confBalance = 0;
let unconfBalance = 0;
let totalBalance = 0;
const versionCompatible = common.isVersionCompatible('23.02');
const versionCompatible = common.isVersionCompatible(req.session.selectedNode.ln_version, '23.02');
body.outputs.forEach((output) => {
if (output.status === 'confirmed') {
confBalance = confBalance + (versionCompatible ? (output.amount_msat / 1000) : output.value);

@ -112,7 +112,7 @@ export const getLocalRemoteBalance = (req, res, next) => {
}
options.url = req.session.selectedNode.ln_server_url + '/v1/listfunds';
request.post(options).then((body) => {
const versionCompatible = common.isVersionCompatible('23.02');
const versionCompatible = common.isVersionCompatible(req.session.selectedNode.ln_version, '23.02');
let localBalance = 0;
let remoteBalance = 0;
let pendingBalance = 0;

@ -12,7 +12,7 @@ export const getFees = (req, res, next) => {
}
options.url = req.session.selectedNode.ln_server_url + '/v1/getinfo';
request.post(options).then((body) => {
const versionCompatible = common.isVersionCompatible('23.02');
const versionCompatible = common.isVersionCompatible(req.session.selectedNode.ln_version, '23.02');
const feeData = { feeCollected: ((versionCompatible ? body.fees_collected_msat : body.msatoshi_fees_collected) || 0) };
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Fees', msg: 'Fee Received', data: feeData });
res.status(200).json(feeData);

@ -48,7 +48,6 @@ export const getInfo = (req, res, next) => {
body.uris.push(body.id + '@' + addr.address + ':' + addr.port);
});
}
common.setVersion(body.version || '');
req.session.selectedNode.ln_version = body.version || '';
req.session.selectedNode.api_version = body.api_version || '';
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Connecting to the Core Lightning\'s Websocket Server.' });

@ -10,8 +10,8 @@ export const deleteExpiredInvoice = (req, res, next) => {
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
const queryStr = req.query.maxExpiry ? '?maxexpiry=' + req.query.maxExpiry : '';
options.url = req.session.selectedNode.ln_server_url + '/v1/invoice/delExpiredInvoice' + queryStr;
options.url = req.session.selectedNode.ln_server_url + '/v1/delexpiredinvoice';
options.body = req.query.maxexpiry ? { maxexpiry: req.query.maxexpiry } : null;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoice', msg: 'Invoices Deleted', data: body });
res.status(204).json({ status: 'Invoice Deleted Successfully' });
@ -26,8 +26,8 @@ export const listInvoices = (req, res, next) => {
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
const labelQuery = req.query.label ? '?label=' + req.query.label : '';
options.url = req.session.selectedNode.ln_server_url + '/v1/invoice/listInvoices' + labelQuery;
options.body = req.query.label ? { label: req.query.label } : null;
options.url = req.session.selectedNode.ln_server_url + '/v1/listinvoices';
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Invoice', msg: 'Invoices List URL', data: options.url });
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Invoice', msg: 'Invoices List Received', data: body });
@ -43,7 +43,7 @@ export const addInvoice = (req, res, next) => {
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/invoice/genInvoice';
options.url = req.session.selectedNode.ln_server_url + '/v1/invoice';
options.body = req.body;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoice', msg: 'Invoice Created', data: body });

@ -10,7 +10,8 @@ export const getRoute = (req, res, next) => {
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/network/getRoute/' + req.params.destPubkey + '/' + req.params.amount;
options.url = req.session.selectedNode.ln_server_url + '/v1/getroute';
options.body = { id: req.params.destPubkey, amount_msat: req.params.amount, riskfactor: (req.query.riskFactor || 0) };
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Network Routes Received', data: body });
res.status(200).json({ routes: body });
@ -19,28 +20,14 @@ export const getRoute = (req, res, next) => {
return res.status(err.statusCode).json({ message: err.message, error: err.error });
});
};
export const listNode = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Node Lookup..' });
options = common.getOptions(req);
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/network/listNode/' + req.params.id;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Node Lookup Finished', data: body });
res.status(200).json(body);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Network', 'Node Lookup Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
});
};
export const listChannel = (req, res, next) => {
export const listChannels = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Channel Lookup..' });
options = common.getOptions(req);
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/network/listChannel/' + req.params.channelShortId;
options.url = req.session.selectedNode.ln_server_url + '/v1/listchannels';
options.body = req.params.channelShortId ? { short_channel_id: req.params.channelShortId } : null;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Channel Lookup Finished', data: body });
res.status(200).json(body);
@ -55,7 +42,8 @@ export const feeRates = (req, res, next) => {
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/network/feeRates/' + req.params.feeRateStyle;
options.url = req.session.selectedNode.ln_server_url + '/v1/feerates';
options.body = req.params.feeRateStyle ? { style: req.params.feeRateStyle } : null;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Network Fee Rates Received for ' + req.params.feeRateStyle, data: body });
res.status(200).json(body);
@ -71,20 +59,24 @@ export const listNodes = (req, res, next) => {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
const queryStr = req.query.liquidity_ads ? '?liquidity_ads=' + req.query.liquidity_ads : '';
options.url = req.session.selectedNode.ln_server_url + '/v1/network/listNodes' + queryStr;
options.url = req.session.selectedNode.ln_server_url + '/v1/listNodes';
options.body = req.params.id ? { id: req.params.id } : null;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Network', msg: 'List Nodes URL' + options.url });
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'List Nodes Finished', data: body });
body.forEach((node) => {
if (node.option_will_fund) {
node.option_will_fund.lease_fee_base_msat = (node.option_will_fund.lease_fee_base_msat && typeof node.option_will_fund.lease_fee_base_msat === 'string' &&
node.option_will_fund.lease_fee_base_msat.includes('msat')) ? node.option_will_fund.lease_fee_base_msat?.replace('msat', '') : node.option_will_fund.lease_fee_base_msat;
node.option_will_fund.channel_fee_max_base_msat = (node.option_will_fund.channel_fee_max_base_msat && typeof node.option_will_fund.channel_fee_max_base_msat === 'string' &&
node.option_will_fund.channel_fee_max_base_msat.includes('msat')) ? node.option_will_fund.channel_fee_max_base_msat?.replace('msat', '') : node.option_will_fund.channel_fee_max_base_msat;
}
return node;
});
res.status(200).json(body);
let response = body.nodes;
if (req.query.liquidity_ads && typeof req.query.liquidity_ads === 'string' && req.query.liquidity_ads.toLowerCase() === 'yes') {
response = body.nodes.filter((node) => {
if (node.option_will_fund) {
node.option_will_fund.lease_fee_base_msat = (node.option_will_fund.lease_fee_base_msat && typeof node.option_will_fund.lease_fee_base_msat === 'string' &&
node.option_will_fund.lease_fee_base_msat.includes('msat')) ? node.option_will_fund.lease_fee_base_msat?.replace('msat', '') : node.option_will_fund.lease_fee_base_msat;
node.option_will_fund.channel_fee_max_base_msat = (node.option_will_fund.channel_fee_max_base_msat && typeof node.option_will_fund.channel_fee_max_base_msat === 'string' &&
node.option_will_fund.channel_fee_max_base_msat.includes('msat')) ? node.option_will_fund.channel_fee_max_base_msat?.replace('msat', '') : node.option_will_fund.channel_fee_max_base_msat;
}
return node;
});
}
res.status(200).json(response);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Network', 'Node Lookup Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });

@ -33,13 +33,8 @@ export const listOffers = (req, res, next) => {
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/offers/listoffers';
if (req.query.offer_id) {
options.url = options.url + '?offer_id=' + req.query.offer_id;
}
if (req.query.active_only) {
options.url = options.url + '?active_only=' + req.query.active_only;
}
options.url = req.session.selectedNode.ln_server_url + '/v1/listoffers';
options.body = { offer_id: (req.query.offer_id) ? req.query.offer_id : null, active_only: !(req.query.active_only === '0' || req.query.active_only === 'false' || !req.query.active_only) };
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Offers', msg: 'Offers List URL', data: options.url });
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Offers List Received', data: body });
@ -55,7 +50,17 @@ export const createOffer = (req, res, next) => {
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/offers/offer';
options.url = req.session.selectedNode.ln_server_url + '/v1/offer';
req.body.issuer = req.body.issuer ? req.body.issuer : req.body.vendor ? req.body.vendor : null;
req.body.label = (req.body.label) ? req.body.label : null;
req.body.quantity_max = (req.body.quantity_max) ? req.body.quantity_max : null;
req.body.absolute_expiry = (req.body.absolute_expiry) ? req.body.absolute_expiry : null;
req.body.recurrence = (req.body.recurrence) ? req.body.recurrence : null;
req.body.recurrence_base = (req.body.recurrence_base) ? req.body.recurrence_base : null;
req.body.recurrence_paywindow = (req.body.recurrence_paywindow) ? req.body.recurrence_paywindow : null;
req.body.recurrence_limit = (req.body.recurrence_limit) ? req.body.recurrence_limit : null;
req.body.single_use = !(req.body.single_use === '0' || req.body.single_use === 'false' || !req.body.single_use);
req.body.quantity_min = (req.body.quantity_min) ? req.body.quantity_min : null;
options.body = req.body;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Offer Created', data: body });
@ -71,7 +76,13 @@ export const fetchOfferInvoice = (req, res, next) => {
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/offers/fetchInvoice';
options.url = req.session.selectedNode.ln_server_url + '/v1/fetchinvoice';
req.body.msatoshi = (req.body.msatoshi) ? req.body.msatoshi : null;
req.body.quantity = (req.body.quantity) ? req.body.quantity : null;
req.body.recurrence_counter = (req.body.recurrence_counter) ? req.body.recurrence_counter : null;
req.body.recurrence_start = (req.body.recurrence_start) ? req.body.recurrence_start : null;
req.body.recurrence_label = (req.body.recurrence_label) ? req.body.recurrence_label : null;
req.body.timeout = (req.body.timeout) ? req.body.timeout : null;
options.body = req.body;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Offers', msg: 'Offer Invoice Body', data: options.body });
request.post(options).then((body) => {
@ -88,7 +99,8 @@ export const disableOffer = (req, res, next) => {
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/offers/disableOffer/' + req.params.offerID;
options.url = req.session.selectedNode.ln_server_url + '/v1/disableOffer';
options.body = { offer_id: req.params.offerID };
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Offer Disabled', data: body });
res.status(202).json(body);

@ -10,7 +10,8 @@ export const getNewAddress = (req, res, next) => {
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/newaddr?addrType=' + req.query.type;
options.url = req.session.selectedNode.ln_server_url + '/v1/newaddr';
options.body = { addresstype: req.query.type };
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'OnChain', msg: 'New Address Generated', data: body });
res.status(200).json(body);
@ -26,6 +27,10 @@ export const onChainWithdraw = (req, res, next) => {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/withdraw';
req.body.destination = req.body.address;
req.body.feeRate = (req.body.feeRate) ? req.body.feeRate : null;
req.body.minConf = (req.body.minConf) ? req.body.minConf : null;
req.body.utxos = (req.body.utxos) ? req.body.utxos : null;
options.body = req.body;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'OnChain', msg: 'OnChain Withdraw Options', data: options.body });
request.post(options).then((body) => {
@ -42,7 +47,7 @@ export const getUTXOs = (req, res, next) => {
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/listFunds';
options.url = req.session.selectedNode.ln_server_url + '/v1/listfunds';
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'OnChain', msg: 'Funds List Received', data: body });
res.status(200).json(body);

@ -69,7 +69,10 @@ export const listPayments = (req, res, next) => {
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/pay/listPayments';
options.url = req.session.selectedNode.ln_server_url + '/v1/listsendpays';
options.body.bolt11 = req.query.invoice || null;
options.body.payment_hash = req.query.payment_hash || null;
options.body.status = req.query.status || null;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Payments', msg: 'Payment List Received', data: body.payments });
res.status(200).json(groupBy(body.payments));
@ -85,18 +88,36 @@ export const postPayment = (req, res, next) => {
}
if (req.body.paymentType === 'KEYSEND') {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Keysend Payment..' });
options.url = req.session.selectedNode.ln_server_url + '/v1/pay/keysend';
options.url = req.session.selectedNode.ln_server_url + '/v1/keysend';
req.body.destination = req.body.pubkey;
req.body.msatoshi = req.body.amount;
req.body.label = (req.body.label) ? req.body.label : null;
req.body.maxfeepercent = (req.body.maxfeepercent) ? req.body.maxfeepercent : null;
req.body.retry_for = (req.body.retry_for) ? req.body.retry_for : null;
req.body.maxdelay = (req.body.maxdelay) ? req.body.maxdelay : null;
req.body.exemptfee = (req.body.exemptfee) ? req.body.exemptfee : null;
options.body = req.body;
}
else {
if (req.body.paymentType === 'OFFER') {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Sending Offer Payment..' });
options.body = { invoice: req.body.invoice };
}
else {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Sending Invoice Payment..' });
options.body = req.body;
}
req.body.bolt11 = (req.body.invoice) ? req.body.invoice : null;
req.body.msatoshi = (req.body.amount) ? req.body.amount : null;
req.body.label = (req.body.label) ? req.body.label : null;
req.body.riskfactor = (req.body.riskfactor) ? req.body.riskfactor : null;
req.body.maxfeepercent = (req.body.maxfeepercent) ? req.body.maxfeepercent : null;
req.body.retry_for = (req.body.retry_for) ? req.body.retry_for : null;
req.body.maxdelay = (req.body.maxdelay) ? req.body.maxdelay : null;
req.body.exemptfee = (req.body.exemptfee) ? req.body.exemptfee : null;
req.body.localinvreqid = (req.body.localinvreqid) ? req.body.localinvreqid : null;
req.body.exclude = (req.body.exclude) ? req.body.exclude : null;
req.body.maxfee = (req.body.maxfee) ? req.body.maxfee : null;
req.body.description = (req.body.description) ? req.body.description : null;
options.body = req.body;
options.url = req.session.selectedNode.ln_server_url + '/v1/pay';
}
request.post(options).then((body) => {

@ -1,11 +1,10 @@
import exprs from 'express';
const { Router } = exprs;
import { isAuthenticated } from '../../utils/authCheck.js';
import { getRoute, listNode, listChannel, feeRates, listNodes } from '../../controllers/cln/network.js';
import { getRoute, listChannels, feeRates, listNodes } from '../../controllers/cln/network.js';
const router = Router();
router.get('/getRoute/:destPubkey/:amount', isAuthenticated, getRoute);
router.get('/listNode/:id', isAuthenticated, listNode);
router.get('/listChannel/:channelShortId', isAuthenticated, listChannel);
router.get('/listChannels/:channelShortId', isAuthenticated, listChannels);
router.get('/feeRates/:feeRateStyle', isAuthenticated, feeRates);
router.get('/listNodes', isAuthenticated, listNodes);
router.get('/listNodes/:id', isAuthenticated, listNodes);
export default router;

@ -424,14 +424,11 @@ export class CommonService {
fs.writeFile(channel_backup_file, '', () => { });
});
};
this.setVersion = (version) => {
this.ln_version = version;
};
this.isVersionCompatible = (checkVersion) => {
if (this.ln_version && this.ln_version !== '') {
this.isVersionCompatible = (currentVersion, checkVersion) => {
if (currentVersion && currentVersion !== '') {
// eslint-disable-next-line prefer-named-capture-group
const pattern = /v?(\d+(\.\d+)*)/;
const match = this.ln_version.match(pattern);
const match = currentVersion.match(pattern);
if (match && match.length && match.length > 1) {
this.logger.log({ selectedNode: this.initSelectedNode, level: 'INFO', fileName: 'Common', msg: 'Global Version ' + match[1] });
this.logger.log({ selectedNode: this.initSelectedNode, level: 'INFO', fileName: 'Common', msg: 'Checking Compatiblility with Version ' + checkVersion });
@ -444,7 +441,7 @@ export class CommonService {
(+currentVersionArr[0] === +checkVersionsArr[0] && +currentVersionArr[1] === +checkVersionsArr[1] && +currentVersionArr[2] >= +checkVersionsArr[2]);
}
else {
this.logger.log({ selectedNode: this.initSelectedNode, level: 'ERROR', fileName: 'Common', msg: 'Invalid Version String ' + this.ln_version });
this.logger.log({ selectedNode: this.initSelectedNode, level: 'ERROR', fileName: 'Common', msg: 'Invalid Version String ' + currentVersion });
return false;
}
}

728
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -14,7 +14,7 @@ export const getBalance = (req, res, next) => {
let confBalance = 0;
let unconfBalance = 0;
let totalBalance = 0;
const versionCompatible = common.isVersionCompatible('23.02');
const versionCompatible = common.isVersionCompatible(req.session.selectedNode.ln_version, '23.02');
body.outputs.forEach((output) => {
if (output.status === 'confirmed') {
confBalance = confBalance + (versionCompatible ? (output.amount_msat / 1000) : output.value);

@ -107,7 +107,7 @@ export const getLocalRemoteBalance = (req, res, next) => {
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/listfunds';
request.post(options).then((body) => {
const versionCompatible = common.isVersionCompatible('23.02');
const versionCompatible = common.isVersionCompatible(req.session.selectedNode.ln_version, '23.02');
let localBalance = 0;
let remoteBalance = 0;
let pendingBalance = 0;

@ -11,7 +11,7 @@ export const getFees = (req, res, next) => {
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/getinfo';
request.post(options).then((body) => {
const versionCompatible = common.isVersionCompatible('23.02');
const versionCompatible = common.isVersionCompatible(req.session.selectedNode.ln_version, '23.02');
const feeData = { feeCollected: ((versionCompatible ? body.fees_collected_msat : body.msatoshi_fees_collected) || 0) };
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Fees', msg: 'Fee Received', data: feeData });
res.status(200).json(feeData);

@ -45,7 +45,6 @@ export const getInfo = (req, res, next) => {
body.uris.push(body.id + '@' + addr.address + ':' + addr.port);
});
}
common.setVersion(body.version || '');
req.session.selectedNode.ln_version = body.version || '';
req.session.selectedNode.api_version = body.api_version || '';
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'GetInfo', msg: 'Connecting to the Core Lightning\'s Websocket Server.' });

@ -9,8 +9,8 @@ export const deleteExpiredInvoice = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoices', msg: 'Deleting Expired Invoices..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
const queryStr = req.query.maxExpiry ? '?maxexpiry=' + req.query.maxExpiry : '';
options.url = req.session.selectedNode.ln_server_url + '/v1/invoice/delExpiredInvoice' + queryStr;
options.url = req.session.selectedNode.ln_server_url + '/v1/delexpiredinvoice';
options.body = req.query.maxexpiry ? { maxexpiry: req.query.maxexpiry } : null;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoice', msg: 'Invoices Deleted', data: body });
res.status(204).json({ status: 'Invoice Deleted Successfully' });
@ -24,8 +24,8 @@ export const listInvoices = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoices', msg: 'Getting Invoices..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
const labelQuery = req.query.label ? '?label=' + req.query.label : '';
options.url = req.session.selectedNode.ln_server_url + '/v1/invoice/listInvoices' + labelQuery;
options.body = req.query.label ? { label: req.query.label } : null;
options.url = req.session.selectedNode.ln_server_url + '/v1/listinvoices';
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Invoice', msg: 'Invoices List URL', data: options.url });
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Invoice', msg: 'Invoices List Received', data: body });
@ -40,7 +40,7 @@ export const addInvoice = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoices', msg: 'Creating Invoice..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/invoice/genInvoice';
options.url = req.session.selectedNode.ln_server_url + '/v1/invoice';
options.body = req.body;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Invoice', msg: 'Invoice Created', data: body });

@ -9,7 +9,8 @@ export const getRoute = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Getting Network Routes..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/network/getRoute/' + req.params.destPubkey + '/' + req.params.amount;
options.url = req.session.selectedNode.ln_server_url + '/v1/getroute';
options.body = { id: req.params.destPubkey, amount_msat: req.params.amount, riskfactor: (req.query.riskFactor || 0) };
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Network Routes Received', data: body });
res.status(200).json({ routes: body });
@ -19,25 +20,12 @@ export const getRoute = (req, res, next) => {
});
};
export const listNode = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Node Lookup..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/network/listNode/' + req.params.id;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Node Lookup Finished', data: body });
res.status(200).json(body);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Network', 'Node Lookup Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
});
};
export const listChannel = (req, res, next) => {
export const listChannels = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Channel Lookup..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/network/listChannel/' + req.params.channelShortId;
options.url = req.session.selectedNode.ln_server_url + '/v1/listchannels';
options.body = req.params.channelShortId ? { short_channel_id: req.params.channelShortId } : null;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Channel Lookup Finished', data: body });
res.status(200).json(body);
@ -51,7 +39,8 @@ export const feeRates = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Getting Network Fee Rates..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/network/feeRates/' + req.params.feeRateStyle;
options.url = req.session.selectedNode.ln_server_url + '/v1/feerates';
options.body = req.params.feeRateStyle ? { style : req.params.feeRateStyle } : null;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'Network Fee Rates Received for ' + req.params.feeRateStyle, data: body });
res.status(200).json(body);
@ -66,20 +55,24 @@ export const listNodes = (req, res, next) => {
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
const queryStr = req.query.liquidity_ads ? '?liquidity_ads=' + req.query.liquidity_ads : '';
options.url = req.session.selectedNode.ln_server_url + '/v1/network/listNodes' + queryStr;
options.url = req.session.selectedNode.ln_server_url + '/v1/listNodes';
options.body = req.params.id ? { id: req.params.id } : null;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Network', msg: 'List Nodes URL' + options.url });
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'List Nodes Finished', data: body });
body.forEach((node) => {
if (node.option_will_fund) {
node.option_will_fund.lease_fee_base_msat = (node.option_will_fund.lease_fee_base_msat && typeof node.option_will_fund.lease_fee_base_msat === 'string' &&
node.option_will_fund.lease_fee_base_msat.includes('msat')) ? node.option_will_fund.lease_fee_base_msat?.replace('msat', '') : node.option_will_fund.lease_fee_base_msat;
node.option_will_fund.channel_fee_max_base_msat = (node.option_will_fund.channel_fee_max_base_msat && typeof node.option_will_fund.channel_fee_max_base_msat === 'string' &&
node.option_will_fund.channel_fee_max_base_msat.includes('msat')) ? node.option_will_fund.channel_fee_max_base_msat?.replace('msat', '') : node.option_will_fund.channel_fee_max_base_msat;
}
return node;
});
res.status(200).json(body);
let response = body.nodes;
if (req.query.liquidity_ads && typeof req.query.liquidity_ads === 'string' && req.query.liquidity_ads.toLowerCase() === 'yes') {
response = body.nodes.filter((node) => {
if (node.option_will_fund) {
node.option_will_fund.lease_fee_base_msat = (node.option_will_fund.lease_fee_base_msat && typeof node.option_will_fund.lease_fee_base_msat === 'string' &&
node.option_will_fund.lease_fee_base_msat.includes('msat')) ? node.option_will_fund.lease_fee_base_msat?.replace('msat', '') : node.option_will_fund.lease_fee_base_msat;
node.option_will_fund.channel_fee_max_base_msat = (node.option_will_fund.channel_fee_max_base_msat && typeof node.option_will_fund.channel_fee_max_base_msat === 'string' &&
node.option_will_fund.channel_fee_max_base_msat.includes('msat')) ? node.option_will_fund.channel_fee_max_base_msat?.replace('msat', '') : node.option_will_fund.channel_fee_max_base_msat;
}
return node;
});
}
res.status(200).json(response);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Network', 'Node Lookup Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });

@ -35,13 +35,8 @@ export const listOffers = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Getting Offers..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/offers/listoffers';
if (req.query.offer_id) {
options.url = options.url + '?offer_id=' + req.query.offer_id;
}
if (req.query.active_only) {
options.url = options.url + '?active_only=' + req.query.active_only;
}
options.url = req.session.selectedNode.ln_server_url + '/v1/listoffers';
options.body = { offer_id: (req.query.offer_id) ? req.query.offer_id : null, active_only: !(req.query.active_only === '0' || req.query.active_only === 'false' || !req.query.active_only) };
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Offers', msg: 'Offers List URL', data: options.url });
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Offers List Received', data: body });
@ -56,7 +51,17 @@ export const createOffer = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Creating Offer..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/offers/offer';
options.url = req.session.selectedNode.ln_server_url + '/v1/offer';
req.body.issuer = req.body.issuer ? req.body.issuer : req.body.vendor ? req.body.vendor : null;
req.body.label = (req.body.label) ? req.body.label : null;
req.body.quantity_max = (req.body.quantity_max) ? req.body.quantity_max : null;
req.body.absolute_expiry = (req.body.absolute_expiry) ? req.body.absolute_expiry : null;
req.body.recurrence = (req.body.recurrence) ? req.body.recurrence : null;
req.body.recurrence_base = (req.body.recurrence_base) ? req.body.recurrence_base : null;
req.body.recurrence_paywindow = (req.body.recurrence_paywindow) ? req.body.recurrence_paywindow : null;
req.body.recurrence_limit = (req.body.recurrence_limit) ? req.body.recurrence_limit : null;
req.body.single_use = !(req.body.single_use === '0' || req.body.single_use === 'false' || !req.body.single_use);
req.body.quantity_min = (req.body.quantity_min) ? req.body.quantity_min : null;
options.body = req.body;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Offer Created', data: body });
@ -71,7 +76,13 @@ export const fetchOfferInvoice = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Getting Offer Invoice..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/offers/fetchInvoice';
options.url = req.session.selectedNode.ln_server_url + '/v1/fetchinvoice';
req.body.msatoshi = (req.body.msatoshi) ? req.body.msatoshi : null;
req.body.quantity = (req.body.quantity) ? req.body.quantity : null;
req.body.recurrence_counter = (req.body.recurrence_counter) ? req.body.recurrence_counter : null;
req.body.recurrence_start = (req.body.recurrence_start) ? req.body.recurrence_start : null;
req.body.recurrence_label = (req.body.recurrence_label) ? req.body.recurrence_label : null;
req.body.timeout = (req.body.timeout) ? req.body.timeout : null;
options.body = req.body;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Offers', msg: 'Offer Invoice Body', data: options.body });
request.post(options).then((body) => {
@ -87,7 +98,8 @@ export const disableOffer = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Disabling Offer..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/offers/disableOffer/' + req.params.offerID;
options.url = req.session.selectedNode.ln_server_url + '/v1/disableOffer';
options.body = { offer_id: req.params.offerID };
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Offers', msg: 'Offer Disabled', data: body });
res.status(202).json(body);

@ -9,7 +9,8 @@ export const getNewAddress = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'OnChain', msg: 'Generating New Address..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/newaddr?addrType=' + req.query.type;
options.url = req.session.selectedNode.ln_server_url + '/v1/newaddr';
options.body = { addresstype: req.query.type };
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'OnChain', msg: 'New Address Generated', data: body });
res.status(200).json(body);
@ -24,6 +25,10 @@ export const onChainWithdraw = (req, res, next) => {
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/withdraw';
req.body.destination = req.body.address;
req.body.feeRate = (req.body.feeRate) ? req.body.feeRate : null;
req.body.minConf = (req.body.minConf) ? req.body.minConf : null;
req.body.utxos = (req.body.utxos) ? req.body.utxos : null;
options.body = req.body;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'OnChain', msg: 'OnChain Withdraw Options', data: options.body });
request.post(options).then((body) => {
@ -39,7 +44,7 @@ export const getUTXOs = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'OnChain', msg: 'Listing Funds..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/listFunds';
options.url = req.session.selectedNode.ln_server_url + '/v1/listfunds';
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'OnChain', msg: 'Funds List Received', data: body });
res.status(200).json(body);

@ -60,7 +60,10 @@ export const listPayments = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'List Payments..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/pay/listPayments';
options.url = req.session.selectedNode.ln_server_url + '/v1/listsendpays';
options.body.bolt11 = req.query.invoice || null;
options.body.payment_hash = req.query.payment_hash || null;
options.body.status = req.query.status || null;
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Payments', msg: 'Payment List Received', data: body.payments });
res.status(200).json(groupBy(body.payments));
@ -75,16 +78,34 @@ export const postPayment = (req, res, next) => {
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
if (req.body.paymentType === 'KEYSEND') {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Keysend Payment..' });
options.url = req.session.selectedNode.ln_server_url + '/v1/pay/keysend';
options.url = req.session.selectedNode.ln_server_url + '/v1/keysend';
req.body.destination = req.body.pubkey;
req.body.msatoshi = req.body.amount;
req.body.label = (req.body.label) ? req.body.label : null;
req.body.maxfeepercent = (req.body.maxfeepercent) ? req.body.maxfeepercent : null;
req.body.retry_for = (req.body.retry_for) ? req.body.retry_for : null;
req.body.maxdelay = (req.body.maxdelay) ? req.body.maxdelay : null;
req.body.exemptfee = (req.body.exemptfee) ? req.body.exemptfee : null;
options.body = req.body;
} else {
if (req.body.paymentType === 'OFFER') {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Sending Offer Payment..' });
options.body = { invoice: req.body.invoice };
} else {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Payments', msg: 'Sending Invoice Payment..' });
options.body = req.body;
}
req.body.bolt11 = (req.body.invoice) ? req.body.invoice : null;
req.body.msatoshi = (req.body.amount) ? req.body.amount : null;
req.body.label = (req.body.label) ? req.body.label : null;
req.body.riskfactor = (req.body.riskfactor) ? req.body.riskfactor : null;
req.body.maxfeepercent = (req.body.maxfeepercent) ? req.body.maxfeepercent : null;
req.body.retry_for = (req.body.retry_for) ? req.body.retry_for : null;
req.body.maxdelay = (req.body.maxdelay) ? req.body.maxdelay : null;
req.body.exemptfee = (req.body.exemptfee) ? req.body.exemptfee : null;
req.body.localinvreqid = (req.body.localinvreqid) ? req.body.localinvreqid : null;
req.body.exclude = (req.body.exclude) ? req.body.exclude : null;
req.body.maxfee = (req.body.maxfee) ? req.body.maxfee : null;
req.body.description = (req.body.description) ? req.body.description : null;
options.body = req.body;
options.url = req.session.selectedNode.ln_server_url + '/v1/pay';
}
request.post(options).then((body) => {

@ -1,14 +1,13 @@
import exprs from 'express';
const { Router } = exprs;
import { isAuthenticated } from '../../utils/authCheck.js';
import { getRoute, listNode, listChannel, feeRates, listNodes } from '../../controllers/cln/network.js';
import { getRoute, listChannels, feeRates, listNodes } from '../../controllers/cln/network.js';
const router = Router();
router.get('/getRoute/:destPubkey/:amount', isAuthenticated, getRoute);
router.get('/listNode/:id', isAuthenticated, listNode);
router.get('/listChannel/:channelShortId', isAuthenticated, listChannel);
router.get('/listChannels/:channelShortId', isAuthenticated, listChannels);
router.get('/feeRates/:feeRateStyle', isAuthenticated, feeRates);
router.get('/listNodes', isAuthenticated, listNodes);
router.get('/listNodes/:id', isAuthenticated, listNodes);
export default router;

@ -433,15 +433,11 @@ export class CommonService {
});
};
public setVersion = (version) => {
this.ln_version = version;
};
public isVersionCompatible = (checkVersion) => {
if (this.ln_version && this.ln_version !== '') {
public isVersionCompatible = (currentVersion, checkVersion) => {
if (currentVersion && currentVersion !== '') {
// eslint-disable-next-line prefer-named-capture-group
const pattern = /v?(\d+(\.\d+)*)/;
const match = this.ln_version.match(pattern);
const match = currentVersion.match(pattern);
if (match && match.length && match.length > 1) {
this.logger.log({ selectedNode: this.initSelectedNode, level: 'INFO', fileName: 'Common', msg: 'Global Version ' + match[1] });
this.logger.log({ selectedNode: this.initSelectedNode, level: 'INFO', fileName: 'Common', msg: 'Checking Compatiblility with Version ' + checkVersion });
@ -453,7 +449,7 @@ export class CommonService {
(+currentVersionArr[0] === +checkVersionsArr[0] && +currentVersionArr[1] > +checkVersionsArr[1]) ||
(+currentVersionArr[0] === +checkVersionsArr[0] && +currentVersionArr[1] === +checkVersionsArr[1] && +currentVersionArr[2] >= +checkVersionsArr[2]);
} else {
this.logger.log({ selectedNode: this.initSelectedNode, level: 'ERROR', fileName: 'Common', msg: 'Invalid Version String ' + this.ln_version });
this.logger.log({ selectedNode: this.initSelectedNode, level: 'ERROR', fileName: 'Common', msg: 'Invalid Version String ' + currentVersion });
return false;
}
}

@ -603,7 +603,7 @@ export class CLNEffects implements OnDestroy {
mergeMap((action: { type: string, payload: ChannelLookup }) => {
this.store.dispatch(openSpinner({ payload: action.payload.uiMessage }));
this.store.dispatch(updateCLNAPICallStatus({ payload: { action: 'Lookup', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.NETWORK_API + '/listChannel/' + action.payload.shortChannelID).
return this.httpClient.get(this.CHILD_API_URL + API_END_POINTS.NETWORK_API + '/listChannels/' + action.payload.shortChannelID).
pipe(
map((resChannel) => {
this.logger.info(resChannel);
@ -616,7 +616,7 @@ export class CLNEffects implements OnDestroy {
}),
catchError((err: any) => {
if (action.payload.showError) {
this.handleErrorWithAlert('Lookup', action.payload.uiMessage, 'Channel Lookup Failed', this.CHILD_API_URL + API_END_POINTS.NETWORK_API + '/listChannel/' + action.payload.shortChannelID, err);
this.handleErrorWithAlert('Lookup', action.payload.uiMessage, 'Channel Lookup Failed', this.CHILD_API_URL + API_END_POINTS.NETWORK_API + '/listChannels/' + action.payload.shortChannelID, err);
} else {
this.store.dispatch(closeSpinner({ payload: action.payload.uiMessage }));
}

Loading…
Cancel
Save