Revert "Add Loop version information"

pull/1298/head
ShahanaFarooqui 8 months ago committed by GitHub
parent 40295bac43
commit 282d8b120a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -124,7 +124,7 @@
"indent": ["error", 2, { "SwitchCase": 1, "MemberExpression": 1, "ArrayExpression": "off" }], "indent": ["error", 2, { "SwitchCase": 1, "MemberExpression": 1, "ArrayExpression": "off" }],
"keyword-spacing": ["error", { "before": true, "after": true, "overrides": { "this": { "before": false }}}], "keyword-spacing": ["error", { "before": true, "after": true, "overrides": { "this": { "before": false }}}],
"lines-around-comment": "error", "lines-around-comment": "error",
"max-depth": ["error", { "max": 7 }], "max-depth": ["error", { "max": 6 }],
"max-nested-callbacks": "error", "max-nested-callbacks": "error",
"max-statements-per-line": ["error", { "max": 3 }], "max-statements-per-line": ["error", { "max": 3 }],
"no-array-constructor": "error", "no-array-constructor": "error",

@ -40,7 +40,7 @@ export const listChannels = (req, res, next) => {
request(options).then((body) => { request(options).then((body) => {
body?.map((channel) => { body?.map((channel) => {
if (!channel.alias || channel.alias === '') { if (!channel.alias || channel.alias === '') {
channel.alias = channel.channel_id.substring(0, 20); channel.alias = channel.id.substring(0, 20);
} }
const local = channel.to_us_msat || 0; const local = channel.to_us_msat || 0;
const remote = (channel.total_msat - local) || 0; const remote = (channel.total_msat - local) || 0;

@ -16,12 +16,14 @@ export const simplifyAllChannels = (selNode, channels) => {
nodeId: channel.nodeId ? channel.nodeId : '', nodeId: channel.nodeId ? channel.nodeId : '',
channelId: channel.channelId ? channel.channelId : '', channelId: channel.channelId ? channel.channelId : '',
state: channel.state ? channel.state : '', state: channel.state ? channel.state : '',
announceChannel: channel.data && channel.data.commitments && channel.data.commitments.params && channel.data.commitments.params.channelFlags && channel.data.commitments.params.channelFlags.announceChannel ? channel.data.commitments.params.channelFlags.announceChannel : false, announceChannel: channel.data && channel.data.commitments && channel.data.commitments.channelFlags && channel.data.commitments.channelFlags.announceChannel ? channel.data.commitments.channelFlags.announceChannel : false,
toLocal: (channel.data.commitments.active[0].localCommit.spec.toLocal) ? Math.round(+channel.data.commitments.active[0].localCommit.spec.toLocal / 1000) : 0, toLocal: (channel.data.commitments.localCommit.spec.toLocal) ? Math.round(+channel.data.commitments.localCommit.spec.toLocal / 1000) : 0,
toRemote: (channel.data.commitments.active[0].localCommit.spec.toRemote) ? Math.round(+channel.data.commitments.active[0].localCommit.spec.toRemote / 1000) : 0, toRemote: (channel.data.commitments.localCommit.spec.toRemote) ? Math.round(+channel.data.commitments.localCommit.spec.toRemote / 1000) : 0,
shortChannelId: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.shortChannelId ? channel.data.channelUpdate.shortChannelId : '', shortChannelId: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.shortChannelId ? channel.data.channelUpdate.shortChannelId : '',
isInitiator: channel.data && channel.data.commitments && channel.data.commitments.params && channel.data.commitments.params.localParams && channel.data.commitments.params.localParams.isInitiator ? channel.data.commitments.params.localParams.isInitiator : false, isFunder: channel.data && channel.data.commitments && channel.data.commitments.localParams && channel.data.commitments.localParams.isFunder ? channel.data.commitments.localParams.isFunder : false,
buried: channel.data && channel.data.buried ? channel.data.buried : false,
feeBaseMsat: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeBaseMsat ? channel.data.channelUpdate.feeBaseMsat : 0, feeBaseMsat: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeBaseMsat ? channel.data.channelUpdate.feeBaseMsat : 0,
feeRatePerKw: (channel.data.commitments.localCommit.spec.feeratePerKw) ? channel.data.commitments.localCommit.spec.feeratePerKw : 0,
feeProportionalMillionths: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeProportionalMillionths ? channel.data.channelUpdate.feeProportionalMillionths : 0, feeProportionalMillionths: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeProportionalMillionths ? channel.data.channelUpdate.feeProportionalMillionths : 0,
alias: '' alias: ''
}); });
@ -157,6 +159,7 @@ export const closeChannel = (req, res, next) => {
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
}); });
}; };
// options.form = { sourceNodeId: req.params.source, targetNodeId: req.params.target, amountMsat: req.params.amount, ignoreNodeIds: req.params.ignore };
export const circularRebalance = (req, res, next) => { export const circularRebalance = (req, res, next) => {
const crInvDescription = 'Circular rebalancing invoice for ' + (req.body.amountMsat / 1000) + ' Sats'; const crInvDescription = 'Circular rebalancing invoice for ' + (req.body.amountMsat / 1000) + ' Sats';
options = common.getOptions(req); options = common.getOptions(req);

@ -6,7 +6,13 @@ const logger = Logger;
const common = Common; const common = Common;
export const loopOut = (req, res, next) => { export const loopOut = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping Out..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping Out..' });
options.uri = '/v1/loop/out'; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out';
options.body = { options.body = {
amt: req.body.amount, amt: req.body.amount,
sweep_conf_target: req.body.targetConf, sweep_conf_target: req.body.targetConf,
@ -35,7 +41,13 @@ export const loopOut = (req, res, next) => {
}; };
export const loopOutTerms = (req, res, next) => { export const loopOutTerms = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms..' });
options.uri = '/v1/loop/out/terms'; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Terms Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out/terms';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Out Terms Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Out Terms Received', data: body });
res.status(200).json(body); res.status(200).json(body);
@ -46,7 +58,13 @@ export const loopOutTerms = (req, res, next) => {
}; };
export const loopOutQuote = (req, res, next) => { export const loopOutQuote = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Quotes..' });
options.uri = '/v1/loop/out/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Quote URL', data: options.url }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Quote URL', data: options.url });
request(options).then((quoteRes) => { request(options).then((quoteRes) => {
quoteRes.amount = +req.params.amount; quoteRes.amount = +req.params.amount;
@ -60,13 +78,19 @@ export const loopOutQuote = (req, res, next) => {
}; };
export const loopOutTermsAndQuotes = (req, res, next) => { export const loopOutTermsAndQuotes = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms & Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms & Quotes..' });
options.uri = '/v1/loop/out/terms'; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Terms & Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out/terms';
request(options).then((terms) => { request(options).then((terms) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Terms Received', data: terms }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Terms Received', data: terms });
const options1 = options; const options1 = common.getSwapServerOptions(req);
const options2 = options; const options2 = common.getSwapServerOptions(req);
options1.uri = '/v1/loop/out/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options1.url = options1.url + '/v1/loop/out/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
options2.uri = '/v1/loop/out/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options2.url = options2.url + '/v1/loop/out/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Min Quote Options', data: options1 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Min Quote Options', data: options1 });
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Max Quote Options', data: options2 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Max Quote Options', data: options2 });
return Promise.all([request(options1), request(options2)]).then((values) => { return Promise.all([request(options1), request(options2)]).then((values) => {
@ -88,7 +112,13 @@ export const loopOutTermsAndQuotes = (req, res, next) => {
}; };
export const loopIn = (req, res, next) => { export const loopIn = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping In..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping In..' });
options.uri = '/v1/loop/in'; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in';
options.body = { options.body = {
amt: req.body.amount, amt: req.body.amount,
max_swap_fee: req.body.swapFee, max_swap_fee: req.body.swapFee,
@ -106,7 +136,13 @@ export const loopIn = (req, res, next) => {
}; };
export const loopInTerms = (req, res, next) => { export const loopInTerms = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms..' });
options.uri = '/v1/loop/in/terms'; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Terms Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in/terms';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop In Terms Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop In Terms Received', data: body });
res.status(200).json(body); res.status(200).json(body);
@ -117,7 +153,13 @@ export const loopInTerms = (req, res, next) => {
}; };
export const loopInQuote = (req, res, next) => { export const loopInQuote = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Quotes..' });
options.uri = '/v1/loop/in/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Quote Options', data: options.url }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Quote Options', data: options.url });
request(options).then((body) => { request(options).then((body) => {
body.amount = +req.params.amount; body.amount = +req.params.amount;
@ -131,13 +173,19 @@ export const loopInQuote = (req, res, next) => {
}; };
export const loopInTermsAndQuotes = (req, res, next) => { export const loopInTermsAndQuotes = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms & Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms & Quotes..' });
options.uri = '/v1/loop/in/terms'; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Terms & Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in/terms';
request(options).then((terms) => { request(options).then((terms) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Terms Received', data: terms }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Terms Received', data: terms });
const options1 = options; const options1 = common.getSwapServerOptions(req);
const options2 = options; const options2 = common.getSwapServerOptions(req);
options1.uri = '/v1/loop/in/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options1.url = options1.url + '/v1/loop/in/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
options2.uri = '/v1/loop/in/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options2.url = options2.url + '/v1/loop/in/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Min Quote Options', data: options1 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Min Quote Options', data: options1 });
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Max Quote Options', data: options2 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Max Quote Options', data: options2 });
return Promise.all([request(options1), request(options2)]).then((values) => { return Promise.all([request(options1), request(options2)]).then((values) => {
@ -159,12 +207,13 @@ export const loopInTermsAndQuotes = (req, res, next) => {
}; };
export const swaps = (req, res, next) => { export const swaps = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting List Swaps..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting List Swaps..' });
options = common.getSwapServerOptions(req);
if (options.url === '') { if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.'; const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'List Swaps Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode); const err = common.handleError({ statusCode: 500, message: 'List Swaps Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
} }
options.uri = '/v1/loop/swaps'; options.url = options.url + '/v1/loop/swaps';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Swaps Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Swaps Received', data: body });
res.status(200).json(body.swaps); res.status(200).json(body.swaps);
@ -175,29 +224,18 @@ export const swaps = (req, res, next) => {
}; };
export const swap = (req, res, next) => { export const swap = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Swap Information..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Swap Information..' });
options.uri = '/v1/loop/swap/' + req.params.id; options = common.getSwapServerOptions(req);
request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Swap Information Received', data: body });
res.status(200).json(body);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Loop', 'Get Swap Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
});
};
export const loopInfo = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Information..' });
options = common.setSwapServerOptions(req);
if (options.url === '') { if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.'; const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Get Loop Info Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode); const err = common.handleError({ statusCode: 500, message: 'Get Swap Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
} }
options.uri = '/v1/loop/info'; options.url = options.url + '/v1/loop/swap/' + req.params.id;
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Information Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Swap Information Received', data: body });
res.status(200).json(body); res.status(200).json(body);
}).catch((errRes) => { }).catch((errRes) => {
const err = common.handleError(errRes, 'Loop', 'Get Loop Info Error', req.session.selectedNode); const err = common.handleError(errRes, 'Loop', 'Get Swap Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
}); });
}; };

@ -137,25 +137,3 @@ export const CollectionFieldsEnum = { ...OfferFieldsEnum, ...PageSettingsFieldsE
export const LNDCollection = [CollectionsEnum.PAGE_SETTINGS]; export const LNDCollection = [CollectionsEnum.PAGE_SETTINGS];
export const ECLCollection = [CollectionsEnum.PAGE_SETTINGS]; export const ECLCollection = [CollectionsEnum.PAGE_SETTINGS];
export const CLNCollection = [CollectionsEnum.PAGE_SETTINGS, CollectionsEnum.OFFERS]; export const CLNCollection = [CollectionsEnum.PAGE_SETTINGS, CollectionsEnum.OFFERS];
export const ECL_UPDATED_DB = [
{
pageId: 'peers_channels',
tables: [
{
tableId: 'open_channels',
removed: ['buried', 'feeRatePerKw'],
renamed: ['isFunder:isInitiator']
},
{
tableId: 'pending_channels',
removed: ['buried', 'feeRatePerKw'],
renamed: ['isFunder:isInitiator']
},
{
tableId: 'inactive_channels',
removed: ['buried', 'feeRatePerKw'],
renamed: ['isFunder:isInitiator']
}
]
}
];

@ -1,9 +1,8 @@
import exprs from 'express'; import exprs from 'express';
const { Router } = exprs; const { Router } = exprs;
import { isAuthenticated } from '../../utils/authCheck.js'; import { isAuthenticated } from '../../utils/authCheck.js';
import { loopInfo, loopInTerms, loopInQuote, loopInTermsAndQuotes, loopIn, loopOutTerms, loopOutQuote, loopOutTermsAndQuotes, loopOut, swaps, swap } from '../../controllers/shared/loop.js'; import { loopInTerms, loopInQuote, loopInTermsAndQuotes, loopIn, loopOutTerms, loopOutQuote, loopOutTermsAndQuotes, loopOut, swaps, swap } from '../../controllers/shared/loop.js';
const router = Router(); const router = Router();
router.get('/info', isAuthenticated, loopInfo);
router.get('/in/terms', isAuthenticated, loopInTerms); router.get('/in/terms', isAuthenticated, loopInTerms);
router.get('/in/quote/:amount', isAuthenticated, loopInQuote); router.get('/in/quote/:amount', isAuthenticated, loopInQuote);
router.get('/in/termsAndQuotes', isAuthenticated, loopInTermsAndQuotes); router.get('/in/termsAndQuotes', isAuthenticated, loopInTermsAndQuotes);

@ -10,7 +10,6 @@ import sharedRoutes from '../routes/shared/index.js';
import lndRoutes from '../routes/lnd/index.js'; import lndRoutes from '../routes/lnd/index.js';
import clnRoutes from '../routes/cln/index.js'; import clnRoutes from '../routes/cln/index.js';
import eclRoutes from '../routes/eclair/index.js'; import eclRoutes from '../routes/eclair/index.js';
import { Database } from './database.js';
import { Common } from './common.js'; import { Common } from './common.js';
import { Logger } from './logger.js'; import { Logger } from './logger.js';
import { CLWSClient } from '../controllers/cln/webSocketClient.js'; import { CLWSClient } from '../controllers/cln/webSocketClient.js';
@ -25,7 +24,6 @@ export class ExpressApplication {
this.eclWsClient = ECLWSClient; this.eclWsClient = ECLWSClient;
this.clWsClient = CLWSClient; this.clWsClient = CLWSClient;
this.lndWsClient = LNDWSClient; this.lndWsClient = LNDWSClient;
this.databaseService = Database;
this.directoryName = dirname(fileURLToPath(import.meta.url)); this.directoryName = dirname(fileURLToPath(import.meta.url));
this.getApp = () => this.app; this.getApp = () => this.app;
this.setCORS = () => { CORS.mount(this.app); }; this.setCORS = () => { CORS.mount(this.app); };
@ -81,7 +79,6 @@ export class ExpressApplication {
this.setCORS(); this.setCORS();
this.setCSRF(); this.setCSRF();
this.setApplicationRoutes(); this.setApplicationRoutes();
this.databaseService.migrateDatabase();
} }
} }
export default ExpressApplication; export default ExpressApplication;

@ -29,10 +29,9 @@ export class CommonService {
{ name: 'JAN', days: 31 }, { name: 'FEB', days: 28 }, { name: 'MAR', days: 31 }, { name: 'APR', days: 30 }, { name: 'MAY', days: 31 }, { name: 'JUN', days: 30 }, { name: 'JAN', days: 31 }, { name: 'FEB', days: 28 }, { name: 'MAR', days: 31 }, { name: 'APR', days: 30 }, { name: 'MAY', days: 31 }, { name: 'JUN', days: 30 },
{ name: 'JUL', days: 31 }, { name: 'AUG', days: 31 }, { name: 'SEP', days: 30 }, { name: 'OCT', days: 31 }, { name: 'NOV', days: 30 }, { name: 'DEC', days: 31 } { name: 'JUL', days: 31 }, { name: 'AUG', days: 31 }, { name: 'SEP', days: 30 }, { name: 'OCT', days: 31 }, { name: 'NOV', days: 30 }, { name: 'DEC', days: 31 }
]; ];
this.setSwapServerOptions = (req) => { this.getSwapServerOptions = (req) => {
const swapOptions = { const swapOptions = {
baseUrl: req.session.selectedNode.swap_server_url, url: req.session.selectedNode.swap_server_url,
uri: '',
rejectUnauthorized: false, rejectUnauthorized: false,
json: true, json: true,
headers: { 'Grpc-Metadata-macaroon': '' } headers: { 'Grpc-Metadata-macaroon': '' }

@ -2,7 +2,7 @@ import * as fs from 'fs';
import { join, sep } from 'path'; import { join, sep } from 'path';
import { Common } from '../utils/common.js'; import { Common } from '../utils/common.js';
import { Logger } from '../utils/logger.js'; import { Logger } from '../utils/logger.js';
import { CollectionsEnum, validateDocument, LNDCollection, ECLCollection, CLNCollection, ECL_UPDATED_DB } from '../models/database.model.js'; import { validateDocument, LNDCollection, ECLCollection, CLNCollection } from '../models/database.model.js';
export class DatabaseService { export class DatabaseService {
constructor() { constructor() {
this.common = Common; this.common = Common;
@ -10,58 +10,6 @@ export class DatabaseService {
this.dbDirectory = join(this.common.db_directory_path, 'database'); this.dbDirectory = join(this.common.db_directory_path, 'database');
this.nodeDatabase = {}; this.nodeDatabase = {};
} }
migrateDatabase() {
this.common.nodes?.map((node) => {
if (node.ln_implementation === 'ECL') {
this.nodeDatabase[node.index] = { adapter: null, data: {} };
this.nodeDatabase[node.index].adapter = new DatabaseAdapter(this.dbDirectory, node);
this.fetchNodeData(node);
if (this.nodeDatabase[node.index].data.PageSettings) {
try {
const currPageSettings = JSON.parse(JSON.stringify(this.nodeDatabase[node.index].data.PageSettings));
ECL_UPDATED_DB.forEach((updatePage) => {
const foundPageDB = this.nodeDatabase[node.index].data.PageSettings.find((currPage) => currPage.pageId === updatePage.pageId);
if (foundPageDB) {
updatePage.tables.forEach((updateTable) => {
const foundTableDB = foundPageDB.tables.find((currTable) => currTable.tableId === updateTable.tableId);
if (foundTableDB) {
updateTable.removed.forEach((colToBeRemoved) => {
const foundIndex = foundTableDB.columnSelection.findIndex((col) => col === colToBeRemoved);
const foundIndexSM = foundTableDB.columnSelectionSM.findIndex((col) => col === colToBeRemoved);
if (foundIndex >= 0) {
foundTableDB.columnSelection?.splice(foundIndex, 1);
}
if (foundIndexSM >= 0) {
foundTableDB.columnSelectionSM?.splice(foundIndexSM, 1);
}
});
updateTable.renamed.forEach((colToBeRenamed) => {
const [oldName, newName] = colToBeRenamed.split(':');
const foundIndex = foundTableDB.columnSelection.findIndex((col) => col === oldName);
const foundIndexSM = foundTableDB.columnSelectionSM.findIndex((col) => col === oldName);
if (foundIndex >= 0) {
foundTableDB.columnSelection?.splice(foundIndex, 1, newName);
}
if (foundIndexSM >= 0) {
foundTableDB.columnSelectionSM?.splice(foundIndexSM, 1, newName);
}
});
}
});
}
});
if (currPageSettings !== this.nodeDatabase[node.index].data.PageSettings) {
this.saveDatabase(node, CollectionsEnum.PAGE_SETTINGS);
}
}
catch (err) {
this.logger.log({ selectedNode: node, level: 'ERROR', fileName: 'Database', msg: 'Database Migration Error', error: err });
}
}
}
return true;
});
}
loadDatabase(session) { loadDatabase(session) {
const { id, selectedNode } = session; const { id, selectedNode } = session;
try { try {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1113,93 +1113,163 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
d3-array d3-array
ISC BSD-3-Clause
Copyright 2010-2023 Mike Bostock Copyright 2010-2020 Mike Bostock
All rights reserved.
Permission to use, copy, modify, and/or distribute this software for any purpose Redistribution and use in source and binary forms, with or without modification,
with or without fee is hereby granted, provided that the above copyright notice are permitted provided that the following conditions are met:
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * Redistributions of source code must retain the above copyright notice, this
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND list of conditions and the following disclaimer.
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * Redistributions in binary form must reproduce the above copyright notice,
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER this list of conditions and the following disclaimer in the documentation
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF and/or other materials provided with the distribution.
THIS SOFTWARE.
* Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-brush d3-brush
ISC BSD-3-Clause
Copyright 2010-2021 Mike Bostock Copyright 2010-2016 Mike Bostock
All rights reserved.
Permission to use, copy, modify, and/or distribute this software for any purpose Redistribution and use in source and binary forms, with or without modification,
with or without fee is hereby granted, provided that the above copyright notice are permitted provided that the following conditions are met:
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * Redistributions of source code must retain the above copyright notice, this
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND list of conditions and the following disclaimer.
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * Redistributions in binary form must reproduce the above copyright notice,
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER this list of conditions and the following disclaimer in the documentation
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF and/or other materials provided with the distribution.
THIS SOFTWARE.
* Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-color d3-color
ISC BSD-3-Clause
Copyright 2010-2022 Mike Bostock Copyright 2010-2016 Mike Bostock
All rights reserved.
Permission to use, copy, modify, and/or distribute this software for any purpose Redistribution and use in source and binary forms, with or without modification,
with or without fee is hereby granted, provided that the above copyright notice are permitted provided that the following conditions are met:
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * Redistributions of source code must retain the above copyright notice, this
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND list of conditions and the following disclaimer.
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * Redistributions in binary form must reproduce the above copyright notice,
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER this list of conditions and the following disclaimer in the documentation
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF and/or other materials provided with the distribution.
THIS SOFTWARE.
* Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-dispatch d3-dispatch
ISC BSD-3-Clause
Copyright 2010-2021 Mike Bostock Copyright 2010-2016 Mike Bostock
All rights reserved.
Permission to use, copy, modify, and/or distribute this software for any purpose Redistribution and use in source and binary forms, with or without modification,
with or without fee is hereby granted, provided that the above copyright notice are permitted provided that the following conditions are met:
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * Redistributions of source code must retain the above copyright notice, this
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND list of conditions and the following disclaimer.
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * Redistributions in binary form must reproduce the above copyright notice,
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER this list of conditions and the following disclaimer in the documentation
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF and/or other materials provided with the distribution.
THIS SOFTWARE.
* Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-drag d3-drag
ISC BSD-3-Clause
Copyright 2010-2021 Mike Bostock Copyright 2010-2016 Mike Bostock
All rights reserved.
Permission to use, copy, modify, and/or distribute this software for any purpose Redistribution and use in source and binary forms, with or without modification,
with or without fee is hereby granted, provided that the above copyright notice are permitted provided that the following conditions are met:
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * Redistributions of source code must retain the above copyright notice, this
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND list of conditions and the following disclaimer.
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * Redistributions in binary form must reproduce the above copyright notice,
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER this list of conditions and the following disclaimer in the documentation
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF and/or other materials provided with the distribution.
THIS SOFTWARE.
* Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-ease d3-ease
BSD-3-Clause BSD-3-Clause
Copyright 2010-2021 Mike Bostock Copyright 2010-2016 Mike Bostock
Copyright 2001 Robert Penner Copyright 2001 Robert Penner
All rights reserved. All rights reserved.
@ -1230,88 +1300,157 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-format d3-format
ISC BSD-3-Clause
Copyright 2010-2021 Mike Bostock Copyright 2010-2015 Mike Bostock
All rights reserved.
Permission to use, copy, modify, and/or distribute this software for any purpose Redistribution and use in source and binary forms, with or without modification,
with or without fee is hereby granted, provided that the above copyright notice are permitted provided that the following conditions are met:
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * Redistributions of source code must retain the above copyright notice, this
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND list of conditions and the following disclaimer.
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * Redistributions in binary form must reproduce the above copyright notice,
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER this list of conditions and the following disclaimer in the documentation
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF and/or other materials provided with the distribution.
THIS SOFTWARE.
* Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-interpolate d3-interpolate
ISC BSD-3-Clause
Copyright 2010-2021 Mike Bostock Copyright 2010-2016 Mike Bostock
All rights reserved.
Permission to use, copy, modify, and/or distribute this software for any purpose Redistribution and use in source and binary forms, with or without modification,
with or without fee is hereby granted, provided that the above copyright notice are permitted provided that the following conditions are met:
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * Redistributions of source code must retain the above copyright notice, this
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND list of conditions and the following disclaimer.
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * Redistributions in binary form must reproduce the above copyright notice,
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER this list of conditions and the following disclaimer in the documentation
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF and/or other materials provided with the distribution.
THIS SOFTWARE.
* Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-scale d3-scale
ISC BSD-3-Clause
Copyright 2010-2021 Mike Bostock Copyright 2010-2015 Mike Bostock
All rights reserved.
Permission to use, copy, modify, and/or distribute this software for any purpose Redistribution and use in source and binary forms, with or without modification,
with or without fee is hereby granted, provided that the above copyright notice are permitted provided that the following conditions are met:
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * Redistributions of source code must retain the above copyright notice, this
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND list of conditions and the following disclaimer.
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * Redistributions in binary form must reproduce the above copyright notice,
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER this list of conditions and the following disclaimer in the documentation
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF and/or other materials provided with the distribution.
THIS SOFTWARE.
* Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-selection d3-selection
ISC BSD-3-Clause
Copyright 2010-2021 Mike Bostock Copyright (c) 2010-2018, Michael Bostock
All rights reserved.
Permission to use, copy, modify, and/or distribute this software for any purpose Redistribution and use in source and binary forms, with or without
with or without fee is hereby granted, provided that the above copyright notice modification, are permitted provided that the following conditions are met:
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * Redistributions of source code must retain the above copyright notice, this
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND list of conditions and the following disclaimer.
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * Redistributions in binary form must reproduce the above copyright notice,
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER this list of conditions and the following disclaimer in the documentation
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF and/or other materials provided with the distribution.
THIS SOFTWARE.
* The name Michael Bostock may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-time d3-time
ISC BSD-3-Clause
Copyright 2010-2022 Mike Bostock Copyright 2010-2016 Mike Bostock
All rights reserved.
Permission to use, copy, modify, and/or distribute this software for any purpose Redistribution and use in source and binary forms, with or without modification,
with or without fee is hereby granted, provided that the above copyright notice are permitted provided that the following conditions are met:
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * Redistributions of source code must retain the above copyright notice, this
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND list of conditions and the following disclaimer.
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * Redistributions in binary form must reproduce the above copyright notice,
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER this list of conditions and the following disclaimer in the documentation
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF and/or other materials provided with the distribution.
THIS SOFTWARE.
* Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-time-format d3-time-format
@ -1346,37 +1485,96 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-timer d3-timer
ISC BSD-3-Clause
Copyright 2010-2021 Mike Bostock Copyright 2010-2016 Mike Bostock
All rights reserved.
Permission to use, copy, modify, and/or distribute this software for any purpose Redistribution and use in source and binary forms, with or without modification,
with or without fee is hereby granted, provided that the above copyright notice are permitted provided that the following conditions are met:
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * Redistributions of source code must retain the above copyright notice, this
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND list of conditions and the following disclaimer.
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * Redistributions in binary form must reproduce the above copyright notice,
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER this list of conditions and the following disclaimer in the documentation
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF and/or other materials provided with the distribution.
THIS SOFTWARE.
* Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
d3-transition d3-transition
ISC BSD-3-Clause
Copyright 2010-2021 Mike Bostock Copyright (c) 2010-2015, Michael Bostock
All rights reserved.
Permission to use, copy, modify, and/or distribute this software for any purpose Redistribution and use in source and binary forms, with or without
with or without fee is hereby granted, provided that the above copyright notice modification, are permitted provided that the following conditions are met:
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * Redistributions of source code must retain the above copyright notice, this
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND list of conditions and the following disclaimer.
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * Redistributions in binary form must reproduce the above copyright notice,
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER this list of conditions and the following disclaimer in the documentation
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF and/or other materials provided with the distribution.
THIS SOFTWARE.
* The name Michael Bostock may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
TERMS OF USE - EASING EQUATIONS
Open source under the BSD License.
Copyright 2001 Robert Penner
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of the author nor the names of contributors may be used to
endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
des.js des.js
@ -1551,23 +1749,6 @@ PERFORMANCE OF THIS SOFTWARE.
internmap
ISC
Copyright 2021 Mike Bostock
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
material-icons material-icons
Apache-2.0 Apache-2.0

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -13,6 +13,6 @@
<style>html{width:100%;height:99%;line-height:1.5;overflow-x:hidden;font-family:Roboto,sans-serif!important;font-size:95%}@media only screen and (max-width: 56.25em){html{font-size:90%}}@media only screen and (max-width: 37.5em){html{font-size:80%}}body{box-sizing:border-box;height:100%;margin:0;overflow:hidden}*{margin:0;padding:0}@font-face{font-family:Roboto;src:url(Roboto-Thin.f7a95c9c5999532c.woff2) format("woff2"),url(Roboto-Thin.c13c157cb81e8ebb.woff) format("woff");font-weight:100;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-ThinItalic.b0e084abf689f393.woff2) format("woff2"),url(Roboto-ThinItalic.1111028df6cea564.woff) format("woff");font-weight:100;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Light.0e01b6cd13b3857f.woff2) format("woff2"),url(Roboto-Light.603ca9a537b88428.woff) format("woff");font-weight:300;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-LightItalic.232ef4b20215f720.woff2) format("woff2"),url(Roboto-LightItalic.1b5e142f787151c8.woff) format("woff");font-weight:300;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Regular.475ba9e4e2d63456.woff2) format("woff2"),url(Roboto-Regular.bcefbfee882bc1cb.woff) format("woff");font-weight:400;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-RegularItalic.e3a9ebdaac06bbc4.woff2) format("woff2"),url(Roboto-RegularItalic.0668fae6af0cf8c2.woff) format("woff");font-weight:400;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Medium.457532032ceb0168.woff2) format("woff2"),url(Roboto-Medium.6e1ae5f0b324a0aa.woff) format("woff");font-weight:500;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-MediumItalic.872f7060602d55d2.woff2) format("woff2"),url(Roboto-MediumItalic.e06fb533801cbb08.woff) format("woff");font-weight:500;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Bold.447291a88c067396.woff2) format("woff2"),url(Roboto-Bold.fc482e6133cf5e26.woff) format("woff");font-weight:700;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-BoldItalic.1b15168ef6fa4e16.woff2) format("woff2"),url(Roboto-BoldItalic.e26ba339b06f09f7.woff) format("woff");font-weight:700;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Black.2eaa390d458c877d.woff2) format("woff2"),url(Roboto-Black.b25f67ad8583da68.woff) format("woff");font-weight:900;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-BlackItalic.7dc03ee444552bc5.woff2) format("woff2"),url(Roboto-BlackItalic.c8dc642467cb3099.woff) format("woff");font-weight:900;font-style:italic}</style><link rel="stylesheet" href="styles.a04c018645a5044a.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.a04c018645a5044a.css"></noscript></head> <style>html{width:100%;height:99%;line-height:1.5;overflow-x:hidden;font-family:Roboto,sans-serif!important;font-size:95%}@media only screen and (max-width: 56.25em){html{font-size:90%}}@media only screen and (max-width: 37.5em){html{font-size:80%}}body{box-sizing:border-box;height:100%;margin:0;overflow:hidden}*{margin:0;padding:0}@font-face{font-family:Roboto;src:url(Roboto-Thin.f7a95c9c5999532c.woff2) format("woff2"),url(Roboto-Thin.c13c157cb81e8ebb.woff) format("woff");font-weight:100;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-ThinItalic.b0e084abf689f393.woff2) format("woff2"),url(Roboto-ThinItalic.1111028df6cea564.woff) format("woff");font-weight:100;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Light.0e01b6cd13b3857f.woff2) format("woff2"),url(Roboto-Light.603ca9a537b88428.woff) format("woff");font-weight:300;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-LightItalic.232ef4b20215f720.woff2) format("woff2"),url(Roboto-LightItalic.1b5e142f787151c8.woff) format("woff");font-weight:300;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Regular.475ba9e4e2d63456.woff2) format("woff2"),url(Roboto-Regular.bcefbfee882bc1cb.woff) format("woff");font-weight:400;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-RegularItalic.e3a9ebdaac06bbc4.woff2) format("woff2"),url(Roboto-RegularItalic.0668fae6af0cf8c2.woff) format("woff");font-weight:400;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Medium.457532032ceb0168.woff2) format("woff2"),url(Roboto-Medium.6e1ae5f0b324a0aa.woff) format("woff");font-weight:500;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-MediumItalic.872f7060602d55d2.woff2) format("woff2"),url(Roboto-MediumItalic.e06fb533801cbb08.woff) format("woff");font-weight:500;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Bold.447291a88c067396.woff2) format("woff2"),url(Roboto-Bold.fc482e6133cf5e26.woff) format("woff");font-weight:700;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-BoldItalic.1b15168ef6fa4e16.woff2) format("woff2"),url(Roboto-BoldItalic.e26ba339b06f09f7.woff) format("woff");font-weight:700;font-style:italic}@font-face{font-family:Roboto;src:url(Roboto-Black.2eaa390d458c877d.woff2) format("woff2"),url(Roboto-Black.b25f67ad8583da68.woff) format("woff");font-weight:900;font-style:normal}@font-face{font-family:Roboto;src:url(Roboto-BlackItalic.7dc03ee444552bc5.woff2) format("woff2"),url(Roboto-BlackItalic.c8dc642467cb3099.woff) format("woff");font-weight:900;font-style:italic}</style><link rel="stylesheet" href="styles.a04c018645a5044a.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.a04c018645a5044a.css"></noscript></head>
<body> <body>
<rtl-app></rtl-app> <rtl-app></rtl-app>
<script src="runtime.c2bb514ce598134b.js" type="module"></script><script src="polyfills.aa01d8f6b94657cb.js" type="module"></script><script src="main.8ef8f2009574bb18.js" type="module"></script> <script src="runtime.9c1e0f691dfda3dd.js" type="module"></script><script src="polyfills.aa01d8f6b94657cb.js" type="module"></script><script src="main.3ccfe42677016a42.js" type="module"></script>
</body></html> </body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
(()=>{"use strict";var e,v={},m={};function r(e){var f=m[e];if(void 0!==f)return f.exports;var t=m[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,r),t.loaded=!0,t.exports}r.m=v,e=[],r.O=(f,t,i,o)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,i,o]=e[n],s=!0,d=0;d<t.length;d++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[d]))?t.splice(d--,1):(s=!1,o<a&&(a=o));if(s){e.splice(n--,1);var u=i();void 0!==u&&(f=u)}}return f}o=o||0;for(var n=e.length;n>0&&e[n-1][2]>o;n--)e[n]=e[n-1];e[n]=[t,i,o]},r.d=(e,f)=>{for(var t in f)r.o(f,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:f[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((f,t)=>(r.f[t](e,f),f),[])),r.u=e=>e+"."+{167:"a3774800f5f9ed5a",267:"5508f97536cb5708",315:"d20113f8d2f54786",636:"eaef3bec0eb4cb7a"}[e]+".js",r.miniCssF=e=>{},r.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),(()=>{var e={},f="RTLApp:";r.l=(t,i,o,n)=>{if(e[t])e[t].push(i);else{var a,s;if(void 0!==o)for(var d=document.getElementsByTagName("script"),u=0;u<d.length;u++){var l=d[u];if(l.getAttribute("src")==t||l.getAttribute("data-webpack")==f+o){a=l;break}}a||(s=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",f+o),a.src=r.tu(t)),e[t]=[i];var c=(g,b)=>{a.onerror=a.onload=null,clearTimeout(p);var h=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),h&&h.forEach(y=>y(b)),g)return g(b)},p=setTimeout(c.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=c.bind(null,a.onerror),a.onload=c.bind(null,a.onload),s&&document.head.appendChild(a)}}})(),r.r=e=>{typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:f=>f},typeof trustedTypes<"u"&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="",(()=>{var e={666:0};r.f.j=(i,o)=>{var n=r.o(e,i)?e[i]:void 0;if(0!==n)if(n)o.push(n[2]);else if(666!=i){var a=new Promise((l,c)=>n=e[i]=[l,c]);o.push(n[2]=a);var s=r.p+r.u(i),d=new Error;r.l(s,l=>{if(r.o(e,i)&&(0!==(n=e[i])&&(e[i]=void 0),n)){var c=l&&("load"===l.type?"missing":l.type),p=l&&l.target&&l.target.src;d.message="Loading chunk "+i+" failed.\n("+c+": "+p+")",d.name="ChunkLoadError",d.type=c,d.request=p,n[1](d)}},"chunk-"+i,i)}else e[i]=0},r.O.j=i=>0===e[i];var f=(i,o)=>{var d,u,[n,a,s]=o,l=0;if(n.some(p=>0!==e[p])){for(d in a)r.o(a,d)&&(r.m[d]=a[d]);if(s)var c=s(r)}for(i&&i(o);l<n.length;l++)r.o(e,u=n[l])&&e[u]&&e[u][0](),e[u]=0;return r.O(c)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(f.bind(null,0)),t.push=f.bind(null,t.push.bind(t))})()})();

@ -1 +0,0 @@
(()=>{"use strict";var e,v={},m={};function r(e){var o=m[e];if(void 0!==o)return o.exports;var t=m[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,r),t.loaded=!0,t.exports}r.m=v,e=[],r.O=(o,t,i,f)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,i,f]=e[n],c=!0,l=0;l<t.length;l++)(!1&f||a>=f)&&Object.keys(r.O).every(b=>r.O[b](t[l]))?t.splice(l--,1):(c=!1,f<a&&(a=f));if(c){e.splice(n--,1);var d=i();void 0!==d&&(o=d)}}return o}f=f||0;for(var n=e.length;n>0&&e[n-1][2]>f;n--)e[n]=e[n-1];e[n]=[t,i,f]},r.d=(e,o)=>{for(var t in o)r.o(o,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:o[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((o,t)=>(r.f[t](e,o),o),[])),r.u=e=>e+"."+{167:"28293ff5a3323208",267:"3050ada6a6d9afd8",315:"25112d0bface4bf2",636:"b883c00cebb300aa"}[e]+".js",r.miniCssF=e=>{},r.o=(e,o)=>Object.prototype.hasOwnProperty.call(e,o),(()=>{var e={},o="RTLApp:";r.l=(t,i,f,n)=>{if(e[t])e[t].push(i);else{var a,c;if(void 0!==f)for(var l=document.getElementsByTagName("script"),d=0;d<l.length;d++){var u=l[d];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==o+f){a=u;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",o+f),a.src=r.tu(t)),e[t]=[i];var s=(g,b)=>{a.onerror=a.onload=null,clearTimeout(p);var h=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),h&&h.forEach(y=>y(b)),g)return g(b)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:o=>o},typeof trustedTypes<"u"&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="",(()=>{var e={666:0};r.f.j=(i,f)=>{var n=r.o(e,i)?e[i]:void 0;if(0!==n)if(n)f.push(n[2]);else if(666!=i){var a=new Promise((u,s)=>n=e[i]=[u,s]);f.push(n[2]=a);var c=r.p+r.u(i),l=new Error;r.l(c,u=>{if(r.o(e,i)&&(0!==(n=e[i])&&(e[i]=void 0),n)){var s=u&&("load"===u.type?"missing":u.type),p=u&&u.target&&u.target.src;l.message="Loading chunk "+i+" failed.\n("+s+": "+p+")",l.name="ChunkLoadError",l.type=s,l.request=p,n[1](l)}},"chunk-"+i,i)}else e[i]=0},r.O.j=i=>0===e[i];var o=(i,f)=>{var l,d,[n,a,c]=f,u=0;if(n.some(p=>0!==e[p])){for(l in a)r.o(a,l)&&(r.m[l]=a[l]);if(c)var s=c(r)}for(i&&i(f);u<n.length;u++)r.o(e,d=n[u])&&e[d]&&e[d][0](),e[d]=0;return r.O(s)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(o.bind(null,0)),t.push=o.bind(null,t.push.bind(t))})()})();

4
package-lock.json generated

@ -1,12 +1,12 @@
{ {
"name": "rtl", "name": "rtl",
"version": "0.14.1-beta", "version": "0.14.0-beta",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "rtl", "name": "rtl",
"version": "0.14.1-beta", "version": "0.14.0-beta",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ngrx/effects": "^15.0.0", "@ngrx/effects": "^15.0.0",

@ -1,6 +1,6 @@
{ {
"name": "rtl", "name": "rtl",
"version": "0.14.1-beta", "version": "0.14.0-beta",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"scripts": { "scripts": {

@ -35,7 +35,7 @@ export const listChannels = (req, res, next) => {
options.url = req.session.selectedNode.ln_server_url + '/v1/channel/listPeerChannels'; options.url = req.session.selectedNode.ln_server_url + '/v1/channel/listPeerChannels';
request(options).then((body) => { request(options).then((body) => {
body?.map((channel) => { body?.map((channel) => {
if (!channel.alias || channel.alias === '') { channel.alias = channel.channel_id.substring(0, 20); } if (!channel.alias || channel.alias === '') { channel.alias = channel.id.substring(0, 20); }
const local = channel.to_us_msat || 0; const local = channel.to_us_msat || 0;
const remote = (channel.total_msat - local) || 0; const remote = (channel.total_msat - local) || 0;
const total = channel.total_msat || 0; const total = channel.total_msat || 0;

@ -19,12 +19,14 @@ export const simplifyAllChannels = (selNode: CommonSelectedNode, channels) => {
nodeId: channel.nodeId ? channel.nodeId : '', nodeId: channel.nodeId ? channel.nodeId : '',
channelId: channel.channelId ? channel.channelId : '', channelId: channel.channelId ? channel.channelId : '',
state: channel.state ? channel.state : '', state: channel.state ? channel.state : '',
announceChannel: channel.data && channel.data.commitments && channel.data.commitments.params && channel.data.commitments.params.channelFlags && channel.data.commitments.params.channelFlags.announceChannel ? channel.data.commitments.params.channelFlags.announceChannel : false, announceChannel: channel.data && channel.data.commitments && channel.data.commitments.channelFlags && channel.data.commitments.channelFlags.announceChannel ? channel.data.commitments.channelFlags.announceChannel : false,
toLocal: (channel.data.commitments.active[0].localCommit.spec.toLocal) ? Math.round(+channel.data.commitments.active[0].localCommit.spec.toLocal / 1000) : 0, toLocal: (channel.data.commitments.localCommit.spec.toLocal) ? Math.round(+channel.data.commitments.localCommit.spec.toLocal / 1000) : 0,
toRemote: (channel.data.commitments.active[0].localCommit.spec.toRemote) ? Math.round(+channel.data.commitments.active[0].localCommit.spec.toRemote / 1000) : 0, toRemote: (channel.data.commitments.localCommit.spec.toRemote) ? Math.round(+channel.data.commitments.localCommit.spec.toRemote / 1000) : 0,
shortChannelId: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.shortChannelId ? channel.data.channelUpdate.shortChannelId : '', shortChannelId: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.shortChannelId ? channel.data.channelUpdate.shortChannelId : '',
isInitiator: channel.data && channel.data.commitments && channel.data.commitments.params && channel.data.commitments.params.localParams && channel.data.commitments.params.localParams.isInitiator ? channel.data.commitments.params.localParams.isInitiator : false, isFunder: channel.data && channel.data.commitments && channel.data.commitments.localParams && channel.data.commitments.localParams.isFunder ? channel.data.commitments.localParams.isFunder : false,
buried: channel.data && channel.data.buried ? channel.data.buried : false,
feeBaseMsat: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeBaseMsat ? channel.data.channelUpdate.feeBaseMsat : 0, feeBaseMsat: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeBaseMsat ? channel.data.channelUpdate.feeBaseMsat : 0,
feeRatePerKw: (channel.data.commitments.localCommit.spec.feeratePerKw) ? channel.data.commitments.localCommit.spec.feeratePerKw : 0,
feeProportionalMillionths: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeProportionalMillionths ? channel.data.channelUpdate.feeProportionalMillionths : 0, feeProportionalMillionths: channel.data && channel.data.channelUpdate && channel.data.channelUpdate.feeProportionalMillionths ? channel.data.channelUpdate.feeProportionalMillionths : 0,
alias: '' alias: ''
}); });
@ -153,6 +155,8 @@ export const closeChannel = (req, res, next) => {
}); });
}; };
// options.form = { sourceNodeId: req.params.source, targetNodeId: req.params.target, amountMsat: req.params.amount, ignoreNodeIds: req.params.ignore };
export const circularRebalance = (req, res, next) => { export const circularRebalance = (req, res, next) => {
const crInvDescription = 'Circular rebalancing invoice for ' + (req.body.amountMsat / 1000) + ' Sats'; const crInvDescription = 'Circular rebalancing invoice for ' + (req.body.amountMsat / 1000) + ' Sats';
options = common.getOptions(req); options = common.getOptions(req);

@ -7,7 +7,13 @@ const common: CommonService = Common;
export const loopOut = (req, res, next) => { export const loopOut = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping Out..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping Out..' });
options.uri = '/v1/loop/out'; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out';
options.body = { options.body = {
amt: req.body.amount, amt: req.body.amount,
sweep_conf_target: req.body.targetConf, sweep_conf_target: req.body.targetConf,
@ -33,7 +39,13 @@ export const loopOut = (req, res, next) => {
export const loopOutTerms = (req, res, next) => { export const loopOutTerms = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms..' });
options.uri = '/v1/loop/out/terms'; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Terms Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out/terms';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Out Terms Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Out Terms Received', data: body });
res.status(200).json(body); res.status(200).json(body);
@ -45,7 +57,13 @@ export const loopOutTerms = (req, res, next) => {
export const loopOutQuote = (req, res, next) => { export const loopOutQuote = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Quotes..' });
options.uri = '/v1/loop/out/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Quote URL', data: options.url }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Quote URL', data: options.url });
request(options).then((quoteRes) => { request(options).then((quoteRes) => {
quoteRes.amount = +req.params.amount; quoteRes.amount = +req.params.amount;
@ -60,12 +78,18 @@ export const loopOutQuote = (req, res, next) => {
export const loopOutTermsAndQuotes = (req, res, next) => { export const loopOutTermsAndQuotes = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms & Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Out Terms & Quotes..' });
options.uri = '/v1/loop/out/terms'; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop Out Terms & Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/out/terms';
request(options).then((terms) => { request(options).then((terms) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Terms Received', data: terms }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Terms Received', data: terms });
const options1 = options; const options2 = options; const options1 = common.getSwapServerOptions(req); const options2 = common.getSwapServerOptions(req);
options1.uri = '/v1/loop/out/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options1.url = options1.url + '/v1/loop/out/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
options2.uri = '/v1/loop/out/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options2.url = options2.url + '/v1/loop/out/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Min Quote Options', data: options1 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Min Quote Options', data: options1 });
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Max Quote Options', data: options2 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Out Max Quote Options', data: options2 });
return Promise.all([request(options1), request(options2)]).then((values) => { return Promise.all([request(options1), request(options2)]).then((values) => {
@ -88,7 +112,13 @@ export const loopOutTermsAndQuotes = (req, res, next) => {
export const loopIn = (req, res, next) => { export const loopIn = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping In..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Looping In..' });
options.uri = '/v1/loop/in'; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in';
options.body = { options.body = {
amt: req.body.amount, amt: req.body.amount,
max_swap_fee: req.body.swapFee, max_swap_fee: req.body.swapFee,
@ -107,7 +137,13 @@ export const loopIn = (req, res, next) => {
export const loopInTerms = (req, res, next) => { export const loopInTerms = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms..' });
options.uri = '/v1/loop/in/terms'; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Terms Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in/terms';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop In Terms Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop In Terms Received', data: body });
res.status(200).json(body); res.status(200).json(body);
@ -119,7 +155,13 @@ export const loopInTerms = (req, res, next) => {
export const loopInQuote = (req, res, next) => { export const loopInQuote = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Quotes..' });
options.uri = '/v1/loop/in/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in/quote/' + req.params.amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Quote Options', data: options.url }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Quote Options', data: options.url });
request(options).then((body) => { request(options).then((body) => {
body.amount = +req.params.amount; body.amount = +req.params.amount;
@ -134,12 +176,18 @@ export const loopInQuote = (req, res, next) => {
export const loopInTermsAndQuotes = (req, res, next) => { export const loopInTermsAndQuotes = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms & Quotes..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop In Terms & Quotes..' });
options.uri = '/v1/loop/in/terms'; options = common.getSwapServerOptions(req);
if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Loop In Terms & Quotes Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
}
options.url = options.url + '/v1/loop/in/terms';
request(options).then((terms) => { request(options).then((terms) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Terms Received', data: terms }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Terms Received', data: terms });
const options1 = options; const options2 = options; const options1 = common.getSwapServerOptions(req); const options2 = common.getSwapServerOptions(req);
options1.uri = '/v1/loop/in/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options1.url = options1.url + '/v1/loop/in/quote/' + terms.min_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
options2.uri = '/v1/loop/in/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline; options2.url = options2.url + '/v1/loop/in/quote/' + terms.max_swap_amount + '?conf_target=' + (req.query.targetConf ? req.query.targetConf : '2') + '&swap_publication_deadline=' + req.query.swapPublicationDeadline;
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Min Quote Options', data: options1 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Min Quote Options', data: options1 });
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Max Quote Options', data: options2 }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop In Max Quote Options', data: options2 });
return Promise.all([request(options1), request(options2)]).then((values) => { return Promise.all([request(options1), request(options2)]).then((values) => {
@ -162,12 +210,13 @@ export const loopInTermsAndQuotes = (req, res, next) => {
export const swaps = (req, res, next) => { export const swaps = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting List Swaps..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting List Swaps..' });
options = common.getSwapServerOptions(req);
if (options.url === '') { if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.'; const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'List Swaps Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode); const err = common.handleError({ statusCode: 500, message: 'List Swaps Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
} }
options.uri = '/v1/loop/swaps'; options.url = options.url + '/v1/loop/swaps';
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Swaps Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Loop', msg: 'Loop Swaps Received', data: body });
res.status(200).json(body.swaps); res.status(200).json(body.swaps);
@ -179,30 +228,18 @@ export const swaps = (req, res, next) => {
export const swap = (req, res, next) => { export const swap = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Swap Information..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Swap Information..' });
options.uri = '/v1/loop/swap/' + req.params.id; options = common.getSwapServerOptions(req);
request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Swap Information Received', data: body });
res.status(200).json(body);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Loop', 'Get Swap Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
});
};
export const loopInfo = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Getting Loop Information..' });
options = common.setSwapServerOptions(req);
if (options.url === '') { if (options.url === '') {
const errMsg = 'Loop Server URL is missing in the configuration.'; const errMsg = 'Loop Server URL is missing in the configuration.';
const err = common.handleError({ statusCode: 500, message: 'Get Loop Info Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode); const err = common.handleError({ statusCode: 500, message: 'Get Swap Error', error: errMsg }, 'Loop', errMsg, req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
} }
options.uri = '/v1/loop/info'; options.url = options.url + '/v1/loop/swap/' + req.params.id;
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Information Received', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Loop', msg: 'Loop Swap Information Received', data: body });
res.status(200).json(body); res.status(200).json(body);
}).catch((errRes) => { }).catch((errRes) => {
const err = common.handleError(errRes, 'Loop', 'Get Loop Info Error', req.session.selectedNode); const err = common.handleError(errRes, 'Loop', 'Get Swap Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
}); });
}; };

@ -154,26 +154,3 @@ export const CollectionFieldsEnum = { ...OfferFieldsEnum, ...PageSettingsFieldsE
export const LNDCollection = [CollectionsEnum.PAGE_SETTINGS]; export const LNDCollection = [CollectionsEnum.PAGE_SETTINGS];
export const ECLCollection = [CollectionsEnum.PAGE_SETTINGS]; export const ECLCollection = [CollectionsEnum.PAGE_SETTINGS];
export const CLNCollection = [CollectionsEnum.PAGE_SETTINGS, CollectionsEnum.OFFERS]; export const CLNCollection = [CollectionsEnum.PAGE_SETTINGS, CollectionsEnum.OFFERS];
export const ECL_UPDATED_DB = [
{
pageId: 'peers_channels',
tables: [
{
tableId: 'open_channels',
removed: ['buried', 'feeRatePerKw'],
renamed: ['isFunder:isInitiator']
},
{
tableId: 'pending_channels',
removed: ['buried', 'feeRatePerKw'],
renamed: ['isFunder:isInitiator']
},
{
tableId: 'inactive_channels',
removed: ['buried', 'feeRatePerKw'],
renamed: ['isFunder:isInitiator']
}
]
}
];

@ -1,11 +1,10 @@
import exprs from 'express'; import exprs from 'express';
const { Router } = exprs; const { Router } = exprs;
import { isAuthenticated } from '../../utils/authCheck.js'; import { isAuthenticated } from '../../utils/authCheck.js';
import { loopInfo, loopInTerms, loopInQuote, loopInTermsAndQuotes, loopIn, loopOutTerms, loopOutQuote, loopOutTermsAndQuotes, loopOut, swaps, swap } from '../../controllers/shared/loop.js'; import { loopInTerms, loopInQuote, loopInTermsAndQuotes, loopIn, loopOutTerms, loopOutQuote, loopOutTermsAndQuotes, loopOut, swaps, swap } from '../../controllers/shared/loop.js';
const router = Router(); const router = Router();
router.get('/info', isAuthenticated, loopInfo);
router.get('/in/terms', isAuthenticated, loopInTerms); router.get('/in/terms', isAuthenticated, loopInTerms);
router.get('/in/quote/:amount', isAuthenticated, loopInQuote); router.get('/in/quote/:amount', isAuthenticated, loopInQuote);
router.get('/in/termsAndQuotes', isAuthenticated, loopInTermsAndQuotes); router.get('/in/termsAndQuotes', isAuthenticated, loopInTermsAndQuotes);

@ -11,7 +11,6 @@ import sharedRoutes from '../routes/shared/index.js';
import lndRoutes from '../routes/lnd/index.js'; import lndRoutes from '../routes/lnd/index.js';
import clnRoutes from '../routes/cln/index.js'; import clnRoutes from '../routes/cln/index.js';
import eclRoutes from '../routes/eclair/index.js'; import eclRoutes from '../routes/eclair/index.js';
import { Database, DatabaseService } from './database.js';
import { Common, CommonService } from './common.js'; import { Common, CommonService } from './common.js';
import { Logger, LoggerService } from './logger.js'; import { Logger, LoggerService } from './logger.js';
import { CLWSClient, CLWebSocketClient } from '../controllers/cln/webSocketClient.js'; import { CLWSClient, CLWebSocketClient } from '../controllers/cln/webSocketClient.js';
@ -28,7 +27,6 @@ export class ExpressApplication {
public eclWsClient: ECLWebSocketClient = ECLWSClient; public eclWsClient: ECLWebSocketClient = ECLWSClient;
public clWsClient: CLWebSocketClient = CLWSClient; public clWsClient: CLWebSocketClient = CLWSClient;
public lndWsClient: LNDWebSocketClient = LNDWSClient; public lndWsClient: LNDWebSocketClient = LNDWSClient;
public databaseService: DatabaseService = Database;
public directoryName = dirname(fileURLToPath(import.meta.url)); public directoryName = dirname(fileURLToPath(import.meta.url));
constructor() { constructor() {
@ -42,7 +40,6 @@ export class ExpressApplication {
this.setCORS(); this.setCORS();
this.setCSRF(); this.setCSRF();
this.setApplicationRoutes(); this.setApplicationRoutes();
this.databaseService.migrateDatabase();
} }
public getApp = () => this.app; public getApp = () => this.app;

@ -34,10 +34,9 @@ export class CommonService {
constructor() { } constructor() { }
public setSwapServerOptions = (req) => { public getSwapServerOptions = (req) => {
const swapOptions = { const swapOptions = {
baseUrl: req.session.selectedNode.swap_server_url, url: req.session.selectedNode.swap_server_url,
uri: '',
rejectUnauthorized: false, rejectUnauthorized: false,
json: true, json: true,
headers: { 'Grpc-Metadata-macaroon': '' } headers: { 'Grpc-Metadata-macaroon': '' }

@ -2,7 +2,7 @@ import * as fs from 'fs';
import { join, sep } from 'path'; import { join, sep } from 'path';
import { Common, CommonService } from '../utils/common.js'; import { Common, CommonService } from '../utils/common.js';
import { Logger, LoggerService } from '../utils/logger.js'; import { Logger, LoggerService } from '../utils/logger.js';
import { Collections, CollectionsEnum, validateDocument, LNDCollection, ECLCollection, CLNCollection, ECL_UPDATED_DB } from '../models/database.model.js'; import { Collections, CollectionsEnum, validateDocument, LNDCollection, ECLCollection, CLNCollection } from '../models/database.model.js';
import { CommonSelectedNode } from '../models/config.model.js'; import { CommonSelectedNode } from '../models/config.model.js';
export class DatabaseService { export class DatabaseService {
@ -14,58 +14,6 @@ export class DatabaseService {
constructor() { } constructor() { }
migrateDatabase() {
this.common.nodes?.map((node: any) => {
if (node.ln_implementation === 'ECL') {
this.nodeDatabase[node.index] = { adapter: null, data: {} };
this.nodeDatabase[node.index].adapter = new DatabaseAdapter(this.dbDirectory, node);
this.fetchNodeData(node);
if (this.nodeDatabase[node.index].data.PageSettings) {
try {
const currPageSettings = JSON.parse(JSON.stringify(this.nodeDatabase[node.index].data.PageSettings));
ECL_UPDATED_DB.forEach((updatePage) => {
const foundPageDB = this.nodeDatabase[node.index].data.PageSettings.find((currPage) => currPage.pageId === updatePage.pageId);
if (foundPageDB) {
updatePage.tables.forEach((updateTable) => {
const foundTableDB = foundPageDB.tables.find((currTable) => currTable.tableId === updateTable.tableId);
if (foundTableDB) {
updateTable.removed.forEach((colToBeRemoved) => {
const foundIndex = foundTableDB.columnSelection.findIndex((col) => col === colToBeRemoved);
const foundIndexSM = foundTableDB.columnSelectionSM.findIndex((col) => col === colToBeRemoved);
if (foundIndex >= 0) {
foundTableDB.columnSelection?.splice(foundIndex, 1);
}
if (foundIndexSM >= 0) {
foundTableDB.columnSelectionSM?.splice(foundIndexSM, 1);
}
});
updateTable.renamed.forEach((colToBeRenamed) => {
const [oldName, newName] = colToBeRenamed.split(':');
const foundIndex = foundTableDB.columnSelection.findIndex((col) => col === oldName);
const foundIndexSM = foundTableDB.columnSelectionSM.findIndex((col) => col === oldName);
if (foundIndex >= 0) {
foundTableDB.columnSelection?.splice(foundIndex, 1, newName);
}
if (foundIndexSM >= 0) {
foundTableDB.columnSelectionSM?.splice(foundIndexSM, 1, newName);
}
});
}
});
}
});
if (currPageSettings !== this.nodeDatabase[node.index].data.PageSettings) {
this.saveDatabase(node, CollectionsEnum.PAGE_SETTINGS);
}
} catch (err) {
this.logger.log({ selectedNode: node, level: 'ERROR', fileName: 'Database', msg: 'Database Migration Error', error: err });
}
}
}
return true;
});
}
loadDatabase(session: any) { loadDatabase(session: any) {
const { id, selectedNode } = session; const { id, selectedNode } = session;
try { try {
@ -250,7 +198,7 @@ export class DatabaseAdapter {
private dbFilePath = ''; private dbFilePath = '';
private userSessions = []; private userSessions = [];
constructor(public dbDirectoryPath: string, public selNode: CommonSelectedNode = null, public id: string = '') { constructor(public dbDirectoryPath: string, private selNode: CommonSelectedNode = null, private id: string = '') {
this.dbFilePath = dbDirectoryPath + sep + 'node-' + selNode.index; this.dbFilePath = dbDirectoryPath + sep + 'node-' + selNode.index;
// For backward compatibility Start // For backward compatibility Start
const oldFilePath = dbDirectoryPath + sep + 'rtldb-node-' + selNode.index + '.json'; const oldFilePath = dbDirectoryPath + sep + 'rtldb-node-' + selNode.index + '.json';

@ -10,12 +10,6 @@
<h4 fxLayoutAlign="start" class="dashboard-info-title">Transactions</h4> <h4 fxLayoutAlign="start" class="dashboard-info-title">Transactions</h4>
<div class="overflow-wrap dashboard-info-value">{{fees?.totalTxCount | number}}</div> <div class="overflow-wrap dashboard-info-value">{{fees?.totalTxCount | number}}</div>
</div> </div>
<div *ngIf="!fees?.totalTxCount">
<h4 fxLayoutAlign="start" class="dashboard-info-title">Transactions</h4>
<a class="overflow-wrap dashboard-info-value" [routerLink]="['../routing']">
Go to Routing
</a>
</div>
</div> </div>
</div> </div>
<ng-template #errorBlock> <ng-template #errorBlock>

@ -21,7 +21,7 @@ import { RTLState } from '../../store/rtl.state';
import { addUpdateOfferBookmark, fetchBalance, fetchChannels, fetchFeeRates, fetchFees, fetchInvoices, fetchLocalRemoteBalance, import { addUpdateOfferBookmark, fetchBalance, fetchChannels, fetchFeeRates, fetchFees, fetchInvoices, fetchLocalRemoteBalance,
fetchPayments, fetchPeers, fetchUTXOs, setLookup, setPeers, setQueryRoutes, updateCLAPICallStatus, updateInvoice, setOfferInvoice, fetchPayments, fetchPeers, fetchUTXOs, setLookup, setPeers, setQueryRoutes, updateCLAPICallStatus, updateInvoice, setOfferInvoice,
sendPaymentStatus, setForwardingHistory, fetchPageSettings } from './cln.actions'; sendPaymentStatus, setForwardingHistory, fetchPageSettings } from './cln.actions';
import { allAPIsCallStatus } from './cln.selector'; import { allAPIsCallStatus, clnNodeInformation, nodeInfoAndBalance } from './cln.selector';
import { ApiCallsListCL } from '../../shared/models/apiCallsPayload'; import { ApiCallsListCL } from '../../shared/models/apiCallsPayload';
import { CLNOfferInformationComponent } from '../transactions/offers/offer-information-modal/offer-information.component'; import { CLNOfferInformationComponent } from '../transactions/offers/offer-information-modal/offer-information.component';
@ -30,7 +30,7 @@ export class CLNEffects implements OnDestroy {
CHILD_API_URL = API_URL + '/cln'; CHILD_API_URL = API_URL + '/cln';
API_VERION = ''; API_VERION = '';
CLN_VERISON = ''; NODE_VERISON = '';
private flgInitialized = false; private flgInitialized = false;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()]; private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject()];
@ -97,7 +97,7 @@ export class CLNEffects implements OnDestroy {
map((info) => { map((info) => {
this.logger.info(info); this.logger.info(info);
this.API_VERION = info.api_version || ''; this.API_VERION = info.api_version || '';
this.CLN_VERISON = info.version || ''; this.NODE_VERISON = info.version || '';
if (info.chains && info.chains.length && info.chains[0] && if (info.chains && info.chains.length && info.chains[0] &&
(typeof info.chains[0] === 'object' && info.chains[0].hasOwnProperty('chain') && info?.chains[0].chain && (typeof info.chains[0] === 'object' && info.chains[0].hasOwnProperty('chain') && info?.chains[0].chain &&
(info?.chains[0].chain.toLowerCase().indexOf('bitcoin') < 0 && info?.chains[0].chain.toLowerCase().indexOf('liquid') < 0) (info?.chains[0].chain.toLowerCase().indexOf('bitcoin') < 0 && info?.chains[0].chain.toLowerCase().indexOf('liquid') < 0)
@ -331,7 +331,7 @@ export class CLNEffects implements OnDestroy {
mergeMap(() => { mergeMap(() => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchChannels', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchChannels', status: APICallStatusEnum.INITIATED } }));
const listChannelsEndpoint = const listChannelsEndpoint =
this.commonService.isVersionCompatible(this.CLN_VERISON, '23.02') && this.commonService.isVersionCompatible(this.NODE_VERISON, '23.02') &&
this.commonService.isVersionCompatible(this.API_VERION, '0.10.3') ? this.commonService.isVersionCompatible(this.API_VERION, '0.10.3') ?
'/listPeerChannels' : '/listChannels'; '/listPeerChannels' : '/listChannels';
return this.httpClient.get<Channel[]>(this.CHILD_API_URL + API_END_POINTS.CHANNELS_API + listChannelsEndpoint); return this.httpClient.get<Channel[]>(this.CHILD_API_URL + API_END_POINTS.CHANNELS_API + listChannelsEndpoint);

@ -39,20 +39,24 @@
</div> </div>
<mat-divider class="my-1" [inset]="true"></mat-divider> <mat-divider class="my-1" [inset]="true"></mat-divider>
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="100"> <div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">State</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Private</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.state | titlecase}}</span> <span class="overflow-wrap foreground-secondary-text">{{!channel.announceChannel ? 'Yes' : 'No'}}</span>
</div>
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Funder</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.isFunder ? 'Yes' : 'No'}}</span>
</div> </div>
</div> </div>
<mat-divider class="my-1" [inset]="true"></mat-divider> <mat-divider class="my-1" [inset]="true"></mat-divider>
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="50"> <div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Private</h4> <h4 fxLayoutAlign="start" class="font-bold-500">State</h4>
<span class="overflow-wrap foreground-secondary-text">{{!channel.announceChannel ? 'Yes' : 'No'}}</span> <span class="overflow-wrap foreground-secondary-text">{{channel.state | titlecase}}</span>
</div> </div>
<div fxFlex="50"> <div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Initiator</h4> <h4 fxLayoutAlign="start" class="font-bold-500">Buried</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.isInitiator ? 'Yes' : 'No'}}</span> <span class="overflow-wrap foreground-secondary-text">{{channel.buried ? 'Yes' : 'No'}}</span>
</div> </div>
</div> </div>
<mat-divider class="my-1" [inset]="true"></mat-divider> <mat-divider class="my-1" [inset]="true"></mat-divider>

@ -56,9 +56,13 @@
</div> </div>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="isInitiator"> <ng-container matColumnDef="isFunder">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Initiator</th> <th *matHeaderCellDef mat-header-cell mat-sort-header>Funder</th>
<td *matCellDef="let channel" mat-cell>{{channel?.isInitiator ? 'Yes' : 'No'}}</td> <td *matCellDef="let channel" mat-cell>{{channel?.isFunder ? 'Yes' : 'No'}}</td>
</ng-container>
<ng-container matColumnDef="buried">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Buried</th>
<td *matCellDef="let channel" mat-cell>{{channel?.buried ? 'Yes' : 'No'}}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="toLocal"> <ng-container matColumnDef="toLocal">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Local Balance (Sats)</th> <th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Local Balance (Sats)</th>
@ -70,6 +74,11 @@
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center"> <td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.toRemote | number:'1.0-0'}} </span></td> {{channel?.toRemote | number:'1.0-0'}} </span></td>
</ng-container> </ng-container>
<ng-container matColumnDef="feeRatePerKw">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Local Fee/KW</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.feeRatePerKw | number:'1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="balancedness"> <ng-container matColumnDef="balancedness">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Balance Score</th> <th *matHeaderCellDef mat-header-cell mat-sort-header>Balance Score</th>
<td *matCellDef="let channel" mat-cell> <td *matCellDef="let channel" mat-cell>

@ -52,9 +52,13 @@
</div> </div>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="isInitiator"> <ng-container matColumnDef="isFunder">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Initiator</th> <th *matHeaderCellDef mat-header-cell mat-sort-header>Funder</th>
<td *matCellDef="let channel" mat-cell>{{channel?.isInitiator ? 'Yes' : 'No'}}</td> <td *matCellDef="let channel" mat-cell>{{channel?.isFunder ? 'Yes' : 'No'}}</td>
</ng-container>
<ng-container matColumnDef="buried">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Buried</th>
<td *matCellDef="let channel" mat-cell>{{channel?.buried ? 'Yes' : 'No'}}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="feeBaseMsat"> <ng-container matColumnDef="feeBaseMsat">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Base Fee (mSats)</th> <th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Base Fee (mSats)</th>
@ -76,6 +80,11 @@
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center"> <td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.toRemote | number:'1.0-0'}} </span></td> {{channel?.toRemote | number:'1.0-0'}} </span></td>
</ng-container> </ng-container>
<ng-container matColumnDef="feeRatePerKw">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Fee/KW</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.feeRatePerKw | number:'1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="balancedness"> <ng-container matColumnDef="balancedness">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Balance Score</th> <th *matHeaderCellDef mat-header-cell mat-sort-header>Balance Score</th>
<td *matCellDef="let channel" mat-cell> <td *matCellDef="let channel" mat-cell>

@ -48,9 +48,13 @@
</div> </div>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="isInitiator"> <ng-container matColumnDef="isFunder">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Initiator</th> <th *matHeaderCellDef mat-header-cell mat-sort-header>Funder</th>
<td *matCellDef="let channel" mat-cell>{{channel?.isInitiator ? 'Yes' : 'No'}}</td> <td *matCellDef="let channel" mat-cell>{{channel?.isFunder ? 'Yes' : 'No'}}</td>
</ng-container>
<ng-container matColumnDef="buried">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Buried</th>
<td *matCellDef="let channel" mat-cell>{{channel?.buried ? 'Yes' : 'No'}}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="toLocal"> <ng-container matColumnDef="toLocal">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Local Balance (Sats)</th> <th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Local Balance (Sats)</th>
@ -62,6 +66,11 @@
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center"> <td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.toRemote | number:'1.0-0'}} </span></td> {{channel?.toRemote | number:'1.0-0'}} </span></td>
</ng-container> </ng-container>
<ng-container matColumnDef="feeRatePerKw">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Fee/KW</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.feeRatePerKw | number:'1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th *matHeaderCellDef mat-header-cell> <th *matHeaderCellDef mat-header-cell>
<div class="bordered-box table-actions-select" fxLayoutAlign="center center"> <div class="bordered-box table-actions-select" fxLayoutAlign="center center">

@ -3,7 +3,7 @@
} }
.info-graphics-container { .info-graphics-container {
max-height: 30rem; max-height: 60rem;
min-height: 30rem; min-height: 60rem;
overflow-x: hidden; overflow-x: hidden;
} }

@ -3,7 +3,7 @@
} }
.info-graphics-container { .info-graphics-container {
max-height: 30rem; max-height: 60rem;
min-height: 30rem; min-height: 60rem;
overflow-x: hidden; overflow-x: hidden;
} }

@ -1,6 +1,6 @@
<div fxLayout="row" fxLayoutAlign="start center" class="page-title-container"> <div fxLayout="row" fxLayoutAlign="start center" class="page-title-container">
<fa-icon class="page-title-img mr-1" [icon]="faInfinity"></fa-icon> <fa-icon class="page-title-img mr-1" [icon]="faInfinity"></fa-icon>
<span class="page-title">Loop (v{{loopInfo?.version || ' Unknown'}})</span> <span class="page-title">Loop</span>
</div> </div>
<div fxLayout="column" class="padding-gap-x"> <div fxLayout="column" class="padding-gap-x">
<mat-card> <mat-card>

@ -5,13 +5,13 @@ import { takeUntil, filter } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { faInfinity } from '@fortawesome/free-solid-svg-icons'; import { faInfinity } from '@fortawesome/free-solid-svg-icons';
import { LoopTypeEnum, UI_MESSAGES } from '../../../services/consts-enums-functions'; import { LoopTypeEnum } from '../../../services/consts-enums-functions';
import { LoopModalComponent } from './loop-modal/loop-modal.component'; import { LoopModalComponent } from './loop-modal/loop-modal.component';
import { LoopQuote, LoopSwapStatus } from '../../../models/loopModels'; import { LoopQuote, LoopSwapStatus } from '../../../models/loopModels';
import { LoopService } from '../../../services/loop.service'; import { LoopService } from '../../../services/loop.service';
import { RTLState } from '../../../../store/rtl.state'; import { RTLState } from '../../../../store/rtl.state';
import { openAlert, closeSpinner, openSpinner } from '../../../../store/rtl.actions'; import { openAlert } from '../../../../store/rtl.actions';
@Component({ @Component({
selector: 'rtl-loop', selector: 'rtl-loop',
@ -21,7 +21,6 @@ import { openAlert, closeSpinner, openSpinner } from '../../../../store/rtl.acti
export class LoopComponent implements OnInit, OnDestroy { export class LoopComponent implements OnInit, OnDestroy {
public faInfinity = faInfinity; public faInfinity = faInfinity;
public loopInfo: any = null;
private targetConf = 2; private targetConf = 2;
public inAmount = 250000; public inAmount = 250000;
public quotes: LoopQuote[] = []; public quotes: LoopQuote[] = [];
@ -33,26 +32,11 @@ export class LoopComponent implements OnInit, OnDestroy {
public flgLoading: Array<Boolean | 'error'> = [true]; public flgLoading: Array<Boolean | 'error'> = [true];
public links = [{ link: 'loopout', name: 'Loop Out' }, { link: 'loopin', name: 'Loop In' }]; public links = [{ link: 'loopout', name: 'Loop Out' }, { link: 'loopin', name: 'Loop In' }];
public activeTab = this.links[0]; public activeTab = this.links[0];
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject(), new Subject()]; private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private router: Router, private loopService: LoopService, private store: Store<RTLState>) { } constructor(private router: Router, private loopService: LoopService, private store: Store<RTLState>) { }
ngOnInit() { ngOnInit() {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.GET_LOOP_INFO }));
this.loopService.getLoopInfo().pipe(takeUntil(this.unSubs[4])).
subscribe({
next: (loopInfoResponse: any) => {
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.GET_LOOP_INFO }));
this.loopInfo = loopInfoResponse;
if (this.loopInfo && this.loopInfo.version) {
this.loopInfo.version = this.loopInfo.version.split(' ')[0];
}
},
error: (err) => {
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.GET_LOOP_INFO }));
this.loopInfo.version = ' Unknown';
}
});
this.loopService.listSwaps(); this.loopService.listSwaps();
const linkFound = this.links.find((link) => this.router.url.includes(link.link)); const linkFound = this.links.find((link) => this.router.url.includes(link.link));
this.activeTab = linkFound ? linkFound : this.links[0]; this.activeTab = linkFound ? linkFound : this.links[0];

@ -111,8 +111,10 @@ export interface Channel {
toRemote?: number; toRemote?: number;
shortChannelId?: string; shortChannelId?: string;
announceChannel?: boolean; announceChannel?: boolean;
isInitiator?: boolean; isFunder?: boolean;
buried?: boolean;
feeBaseMsat?: number; feeBaseMsat?: number;
feeRatePerKw?: number;
feeProportionalMillionths?: number; feeProportionalMillionths?: number;
balancedness?: number; balancedness?: number;
} }

@ -298,19 +298,11 @@ export class CommonService implements OnDestroy {
isVersionCompatible(currentVersion, checkVersion) { isVersionCompatible(currentVersion, checkVersion) {
// Check for newer CLN version style compatibility // Check for newer CLN version style compatibility
if (currentVersion) { if (currentVersion) {
const match = currentVersion.match(/v?(?<version>\d+(?:\.\d+)*)/); const versionsArr = currentVersion.trim()?.replace('v', '').split('-')[0].split('.') || [];
if (match && match.groups && match.groups.version) { const checkVersionsArr = checkVersion.split('.');
this.logger.info('Current Version: ' + match.groups.version); return (+versionsArr[0] > +checkVersionsArr[0]) ||
this.logger.info('Checking Compatiblility with Version: ' + checkVersion); (+versionsArr[0] === +checkVersionsArr[0] && +versionsArr[1] > +checkVersionsArr[1]) ||
const versionsArr = match.groups.version.split('.') || []; (+versionsArr[0] === +checkVersionsArr[0] && +versionsArr[1] === +checkVersionsArr[1] && +versionsArr[2] >= +checkVersionsArr[2]);
const checkVersionsArr = checkVersion.split('.');
return (+versionsArr[0] > +checkVersionsArr[0]) ||
(+versionsArr[0] === +checkVersionsArr[0] && +versionsArr[1] > +checkVersionsArr[1]) ||
(+versionsArr[0] === +checkVersionsArr[0] && +versionsArr[1] === +checkVersionsArr[1] && +versionsArr[2] >= +checkVersionsArr[2]);
} else {
this.logger.error('Invalid Version String: ' + currentVersion);
return false;
}
} }
return false; return false;
} }

@ -12,7 +12,7 @@ export const HOUR_SECONDS = 3600;
export const DEFAULT_INVOICE_EXPIRY = HOUR_SECONDS * 24 * 7; export const DEFAULT_INVOICE_EXPIRY = HOUR_SECONDS * 24 * 7;
export const VERSION = '0.14.1-beta'; export const VERSION = '0.14.0-beta';
export const API_URL = isDevMode() ? 'http://localhost:3000/rtl/api' : './api'; export const API_URL = isDevMode() ? 'http://localhost:3000/rtl/api' : './api';
@ -357,7 +357,6 @@ export const UI_MESSAGES = {
VERIFY_MESSAGE: 'Verifying Message...', VERIFY_MESSAGE: 'Verifying Message...',
BUMP_FEE: 'Bumping Fee...', BUMP_FEE: 'Bumping Fee...',
LEASE_UTXO: 'Leasing UTXO...', LEASE_UTXO: 'Leasing UTXO...',
GET_LOOP_INFO: 'Getting Loop Info...',
GET_LOOP_SWAPS: 'Getting List Swaps...', GET_LOOP_SWAPS: 'Getting List Swaps...',
GET_FORWARDING_HISTORY: 'Getting Forwarding History...', GET_FORWARDING_HISTORY: 'Getting Forwarding History...',
GET_LOOKUP_DETAILS: 'Getting Lookup Details...', GET_LOOKUP_DETAILS: 'Getting Lookup Details...',
@ -1196,20 +1195,20 @@ export const ECL_PAGE_DEFS: ECLPageDefinitions = {
peers_channels: { peers_channels: {
open_channels: { open_channels: {
maxColumns: 8, maxColumns: 8,
allowedColumns: [{ column:'shortChannelId' }, { column:'channelId' }, { column:'alias' }, { column:'nodeId' }, { column:'isInitiator', label: 'Initiator' }, allowedColumns: [{ column:'shortChannelId' }, { column:'channelId' }, { column:'alias' }, { column:'nodeId' }, { column:'isFunder', label: 'Funder' },
{ column:'feeBaseMsat', label: 'Base Fee' }, { column:'feeProportionalMillionths', label: 'Fee Rate' }, { column:'toLocal', label: 'Local Balance' }, { column:'toRemote', label: 'Remote Balance' }, { column:'buried' }, { column:'feeBaseMsat', label: 'Base Fee' }, { column:'feeProportionalMillionths', label: 'Fee Rate' }, { column:'toLocal', label: 'Local Balance' }, { column:'toRemote', label: 'Remote Balance' },
{ column:'balancedness', label: 'Balance Score' }] { column:'feeRatePerKw', label: 'Fee/KW' }, { column:'balancedness', label: 'Balance Score' }]
}, },
pending_channels: { pending_channels: {
maxColumns: 7, maxColumns: 7,
allowedColumns: [{ column:'state' }, { column:'channelId' }, { column:'alias' }, { column:'nodeId' }, { column:'isInitiator', label: 'Initiator' }, allowedColumns: [{ column:'state' }, { column:'channelId' }, { column:'alias' }, { column:'nodeId' }, { column:'isFunder', label: 'Funder' },
{ column:'toLocal', label: 'Local Balance' }, { column:'toRemote', label: 'Remote Balance' }] { column:'buried' }, { column:'toLocal', label: 'Local Balance' }, { column:'toRemote', label: 'Remote Balance' }, { column:'feeRatePerKw', label: 'Fee/KW' }]
}, },
inactive_channels: { inactive_channels: {
maxColumns: 8, maxColumns: 8,
allowedColumns: [{ column:'state' }, { column:'shortChannelId' }, { column:'channelId' }, { column:'alias' }, { column:'nodeId' }, allowedColumns: [{ column:'state' }, { column:'shortChannelId' }, { column:'channelId' }, { column:'alias' }, { column:'nodeId' },
{ column:'isInitiator', label: 'Initiator' }, { column:'toLocal', label: 'Local Balance' }, { column:'isFunder', label: 'Funder' }, { column:'buried' }, { column:'toLocal', label: 'Local Balance' },
{ column:'toRemote', label: 'Remote Balance' }, { column:'balancedness', label: 'Balance Score' }] { column:'toRemote', label: 'Remote Balance' }, { column:'feeRatePerKw', label: 'Fee/KW' }, { column:'balancedness', label: 'Balance Score' }]
}, },
peers: { peers: {
maxColumns: 4, maxColumns: 4,

@ -19,15 +19,10 @@ export class LoopService implements OnDestroy {
private loopUrl = ''; private loopUrl = '';
private swaps: LoopSwapStatus[] = []; private swaps: LoopSwapStatus[] = [];
public swapsChanged = new BehaviorSubject<LoopSwapStatus[]>([]); public swapsChanged = new BehaviorSubject<LoopSwapStatus[]>([]);
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject(), new Subject(), new Subject()]; private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private httpClient: HttpClient, private logger: LoggerService, private store: Store<RTLState>, private commonService: CommonService) { } constructor(private httpClient: HttpClient, private logger: LoggerService, private store: Store<RTLState>, private commonService: CommonService) { }
getLoopInfo() {
this.loopUrl = API_URL + API_END_POINTS.LOOP_API + '/info';
return this.httpClient.get<any>(this.loopUrl);
}
getSwapsList() { getSwapsList() {
return this.swaps; return this.swaps;
} }

Loading…
Cancel
Save