Merge pull request #1244 from Ride-The-Lightning/cln-msat-migration

Cln msatoshi migration
pull/1247/head^2
ShahanaFarooqui 12 months ago committed by GitHub
commit ed9634ef25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -4,21 +4,51 @@ import { Common } from '../../utils/common.js';
let options = null;
const logger = Logger;
const common = Common;
export const listPeerChannels = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Getting Peer Channels..' });
options = common.getOptions(req);
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/channel/listPeerChannels';
request(options).then((body) => {
body?.map((channel) => {
if (!channel.alias || channel.alias === '') {
channel.alias = channel.peer_id.substring(0, 20);
}
const local = channel.to_us_msat || 0;
const remote = (channel.total_msat - channel.to_us_msat) || 0;
const total = channel.total_msat || 0;
channel.balancedness = (total === 0) ? 1 : (1 - Math.abs((local - remote) / total)).toFixed(3);
return channel;
});
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Peer Channels List Received', data: body });
res.status(200).json(body);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Channels', 'List Peer Channels Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
});
};
export const listChannels = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Getting Channels..' });
options = common.getOptions(req);
if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/channel/listChannels';
if (common.isVersionCompatible(req.session.selectedNode.api_version, '0.10.2')) {
options.url = req.session.selectedNode.ln_server_url + '/v1/channel/listPeerChannels';
}
else {
options.url = req.session.selectedNode.ln_server_url + '/v1/channel/listChannels';
}
request(options).then((body) => {
body?.map((channel) => {
if (!channel.alias || channel.alias === '') {
channel.alias = channel.id.substring(0, 20);
}
const local = (channel.msatoshi_to_us) ? channel.msatoshi_to_us : 0;
const remote = (channel.msatoshi_to_them) ? channel.msatoshi_to_them : 0;
const total = channel.msatoshi_total ? channel.msatoshi_total : 0;
const local = (channel.msatoshi_to_us) ? channel.msatoshi_to_us : (channel.to_us_msat || 0);
const remote = (channel.msatoshi_to_them) ? channel.msatoshi_to_them : ((channel.total_msat - channel.to_us_msat) || 0);
const total = channel.msatoshi_total ? channel.msatoshi_total : (channel.total_msat || 0);
channel.balancedness = (total === 0) ? 1 : (1 - Math.abs((local - remote) / total)).toFixed(3);
return channel;
});

@ -1,9 +1,10 @@
import exprs from 'express';
const { Router } = exprs;
import { isAuthenticated } from '../../utils/authCheck.js';
import { listChannels, openChannel, setChannelFee, closeChannel, getLocalRemoteBalance, listForwards, funderUpdatePolicy, listForwardsPaginated } from '../../controllers/cln/channels.js';
import { listChannels, listPeerChannels, openChannel, setChannelFee, closeChannel, getLocalRemoteBalance, listForwards, funderUpdatePolicy, listForwardsPaginated } from '../../controllers/cln/channels.js';
const router = Router();
router.get('/listChannels', isAuthenticated, listChannels);
router.get('/listPeerChannels', isAuthenticated, listPeerChannels);
router.post('/', isAuthenticated, openChannel);
router.post('/setChannelFee', isAuthenticated, setChannelFee);
router.delete('/:channelId', isAuthenticated, closeChannel);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -10,9 +10,9 @@
<link i18n-rel="" rel="mask-icon" href="assets/images/favicon-light/safari-pinned-tab.svg" color="#5bbad5">
<meta i18n-content="" name="msapplication-TileColor" content="#da532c">
<meta i18n-content="" name="theme-color" content="#ffffff">
<style>html{width:100%;height:99%;line-height:1.5;overflow-x:hidden;font-family:Roboto,sans-serif!important;font-size:100%}@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.d31e61a01689a167.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.d31e61a01689a167.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.cf1ae92c15ddd814.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.cf1ae92c15ddd814.css"></noscript></head>
<body>
<rtl-app></rtl-app>
<script src="runtime.85c27805ea5ed7f0.js" type="module"></script><script src="polyfills.9720483e1820202a.js" type="module"></script><script src="main.209e81cddd0d5ce6.js" type="module"></script>
<script src="runtime.82293937345ce6e2.js" type="module"></script><script src="polyfills.9720483e1820202a.js" type="module"></script><script src="main.305260af7e1a40e5.js" type="module"></script>
</body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +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],c=!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):(c=!1,o<a&&(a=o));if(c){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:"836d81485f16d9bc",267:"8f996ec2b4b156e0",315:"9c8bec49097dc4f1",636:"c6beed2b2207416a"}[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,c;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||(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",f+o),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: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,s)=>n=e[i]=[l,s]);o.push(n[2]=a);var c=r.p+r.u(i),d=new Error;r.l(c,l=>{if(r.o(e,i)&&(0!==(n=e[i])&&(e[i]=void 0),n)){var s=l&&("load"===l.type?"missing":l.type),p=l&&l.target&&l.target.src;d.message="Loading chunk "+i+" failed.\n("+s+": "+p+")",d.name="ChunkLoadError",d.type=s,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,c]=o,l=0;if(n.some(p=>0!==e[p])){for(d in a)r.o(a,d)&&(r.m[d]=a[d]);if(c)var s=c(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(s)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(f.bind(null,0)),t.push=f.bind(null,t.push.bind(t))})()})();
(()=>{"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],c=!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):(c=!1,o<a&&(a=o));if(c){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:"836d81485f16d9bc",267:"8f996ec2b4b156e0",315:"2aa7cf820fb9df7e",636:"c6beed2b2207416a"}[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,c;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||(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",f+o),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: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,s)=>n=e[i]=[l,s]);o.push(n[2]=a);var c=r.p+r.u(i),d=new Error;r.l(c,l=>{if(r.o(e,i)&&(0!==(n=e[i])&&(e[i]=void 0),n)){var s=l&&("load"===l.type?"missing":l.type),p=l&&l.target&&l.target.src;d.message="Loading chunk "+i+" failed.\n("+s+": "+p+")",d.name="ChunkLoadError",d.type=s,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,c]=o,l=0;if(n.some(p=>0!==e[p])){for(d in a)r.o(a,d)&&(r.m[d]=a[d]);if(c)var s=c(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(s)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(f.bind(null,0)),t.push=f.bind(null,t.push.bind(t))})()})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -5,17 +5,43 @@ let options = null;
const logger: LoggerService = Logger;
const common: CommonService = Common;
export const listPeerChannels = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Getting Peer Channels..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/channel/listPeerChannels';
request(options).then((body) => {
body?.map((channel) => {
if (!channel.alias || channel.alias === '') { channel.alias = channel.peer_id.substring(0, 20); }
const local = channel.to_us_msat || 0;
const remote = (channel.total_msat - channel.to_us_msat) || 0;
const total = channel.total_msat || 0;
channel.balancedness = (total === 0) ? 1 : (1 - Math.abs((local - remote) / total)).toFixed(3);
return channel;
});
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Peer Channels List Received', data: body });
res.status(200).json(body);
}).catch((errRes) => {
const err = common.handleError(errRes, 'Channels', 'List Peer Channels Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error });
});
};
export const listChannels = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Channels', msg: 'Getting Channels..' });
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/channel/listChannels';
if (common.isVersionCompatible(req.session.selectedNode.api_version, '0.10.2')) {
options.url = req.session.selectedNode.ln_server_url + '/v1/channel/listPeerChannels';
} else {
options.url = req.session.selectedNode.ln_server_url + '/v1/channel/listChannels';
}
request(options).then((body) => {
body?.map((channel) => {
if (!channel.alias || channel.alias === '') { channel.alias = channel.id.substring(0, 20); }
const local = (channel.msatoshi_to_us) ? channel.msatoshi_to_us : 0;
const remote = (channel.msatoshi_to_them) ? channel.msatoshi_to_them : 0;
const total = channel.msatoshi_total ? channel.msatoshi_total : 0;
const local = (channel.msatoshi_to_us) ? channel.msatoshi_to_us : (channel.to_us_msat || 0);
const remote = (channel.msatoshi_to_them) ? channel.msatoshi_to_them : ((channel.total_msat - channel.to_us_msat) || 0);
const total = channel.msatoshi_total ? channel.msatoshi_total : (channel.total_msat || 0);
channel.balancedness = (total === 0) ? 1 : (1 - Math.abs((local - remote) / total)).toFixed(3);
return channel;
});

@ -1,11 +1,12 @@
import exprs from 'express';
const { Router } = exprs;
import { isAuthenticated } from '../../utils/authCheck.js';
import { listChannels, openChannel, setChannelFee, closeChannel, getLocalRemoteBalance, listForwards, funderUpdatePolicy, listForwardsPaginated } from '../../controllers/cln/channels.js';
import { listChannels, listPeerChannels, openChannel, setChannelFee, closeChannel, getLocalRemoteBalance, listForwards, funderUpdatePolicy, listForwardsPaginated } from '../../controllers/cln/channels.js';
const router = Router();
router.get('/listChannels', isAuthenticated, listChannels);
router.get('/listPeerChannels', isAuthenticated, listPeerChannels);
router.post('/', isAuthenticated, openChannel);
router.post('/setChannelFee', isAuthenticated, setChannelFee);
router.delete('/:channelId', isAuthenticated, closeChannel);

@ -32,6 +32,11 @@
<span class="foreground-secondary-text">{{lookupResult[0]?.base_fee_millisatoshi | number}}</span>
</div>
<mat-divider class="my-1"></mat-divider>
<div fxLayout="column">
<h4 class="font-bold-500">Fee/Millionth</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.fee_per_millionth | number}}</span>
</div>
<mat-divider class="my-1"></mat-divider>
<div fxLayout="column">
<h4 class="font-bold-500">Channel Flags</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.channel_flags | number}}</span>
@ -42,11 +47,6 @@
<span class="foreground-secondary-text">{{lookupResult[0]?.delay | number}}</span>
</div>
<mat-divider class="my-1"></mat-divider>
<div fxLayout="column">
<h4 class="font-bold-500">Fee/Millionth</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.fee_per_millionth | number}}</span>
</div>
<mat-divider class="my-1"></mat-divider>
<div fxLayout="column">
<h4 class="font-bold-500">Max Htlc (mSat)</h4>
<span class="foreground-secondary-text">{{lookupResult[0]?.htlc_maximum_msat | number}}</span>
@ -108,6 +108,11 @@
<span class="foreground-secondary-text">{{lookupResult[1]?.base_fee_millisatoshi | number}}</span>
</div>
<mat-divider class="my-1"></mat-divider>
<div fxLayout="column">
<h4 class="font-bold-500">Fee/Millionth</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.fee_per_millionth | number}}</span>
</div>
<mat-divider class="my-1"></mat-divider>
<div fxLayout="column">
<h4 class="font-bold-500">Channel Flags</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.channel_flags | number}}</span>
@ -118,11 +123,6 @@
<span class="foreground-secondary-text">{{lookupResult[1]?.delay | number}}</span>
</div>
<mat-divider class="my-1"></mat-divider>
<div fxLayout="column">
<h4 class="font-bold-500">Fee/Millionth</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.fee_per_millionth | number}}</span>
</div>
<mat-divider class="my-1"></mat-divider>
<div fxLayout="column">
<h4 class="font-bold-500">Max Htlc (mSat)</h4>
<span class="foreground-secondary-text">{{lookupResult[1]?.htlc_maximum_msat | number}}</span>

@ -38,10 +38,13 @@ export class CLNNodeLookupComponent implements OnInit, OnDestroy {
this.addresses.sort = this.sort;
this.addresses.sortingDataAccessor = (data: any, sortHeaderId: string) => ((data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null);
if (this.lookupResult.features && this.lookupResult.features.trim() !== '') {
this.lookupResult.features = this.lookupResult.features.substring(this.lookupResult.features.length - 40);
const featureHex = parseInt(this.lookupResult.features, 16);
NODE_FEATURES_CLN.forEach((feature) => {
if (!!(featureHex & ((1 << feature.range.min) | (1 << feature.range.max)))) {
this.featureDescriptions.push(feature.description + '\n');
if (featureHex & (1 << feature.range.min)) {
this.featureDescriptions.push('Mandatory: ' + feature.description + '\n');
} else if (featureHex & (1 << feature.range.max)) {
this.featureDescriptions.push('Optional: ' + feature.description + '\n');
}
});
}

@ -58,7 +58,7 @@
</ng-container>
<ng-container matColumnDef="msatoshi">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Amount (Sats)</th>
<td *matCellDef="let hop" mat-cell><span fxLayoutAlign="end center">{{hop?.msatoshi/1000 | number}}</span></td>
<td *matCellDef="let hop" mat-cell><span fxLayoutAlign="end center">{{((hop?.msatoshi/1000) || hop?.amount_msat/1000) | number}}</span></td>
</ng-container>
<ng-container matColumnDef="actions">
<th *matHeaderCellDef mat-header-cell>

@ -90,10 +90,9 @@ export class CLNQueryRoutesComponent implements OnInit, OnDestroy {
[{ key: 'id', value: selHop.id, title: 'ID', width: 100, type: DataTypeEnum.STRING }],
[{ key: 'channel', value: selHop.channel, title: 'Channel', width: 50, type: DataTypeEnum.STRING },
{ key: 'alias', value: selHop.alias, title: 'Peer Alias', width: 50, type: DataTypeEnum.STRING }],
[{ key: 'msatoshi', value: selHop.msatoshi, title: 'mSatoshi', width: 50, type: DataTypeEnum.NUMBER },
{ key: 'amount_msat', value: selHop.amount_msat, title: 'Amount mSat', width: 50, type: DataTypeEnum.STRING }],
[{ key: 'direction', value: selHop.direction, title: 'Direction', width: 50, type: DataTypeEnum.STRING },
{ key: 'delay', value: selHop.delay, title: 'Delay', width: 50, type: DataTypeEnum.NUMBER }]
[{ key: 'amount_msat', value: (selHop.msatoshi || selHop.amount_msat), title: 'Amount (mSat)', width: 34, type: selHop.msatoshi ? DataTypeEnum.STRING : DataTypeEnum.NUMBER },
{ key: 'direction', value: selHop.direction, title: 'Direction', width: 33, type: DataTypeEnum.STRING },
{ key: 'delay', value: selHop.delay, title: 'Delay', width: 33, type: DataTypeEnum.NUMBER }]
];
this.store.dispatch(openAlert({
payload: {

@ -1,17 +1,17 @@
<div *ngIf="errorMessage?.trim() === ''; else errorBlock" class="mt-1" fxLayout="column" fxFlex="100"fxLayoutAlign="space-between stretch">
<div>
<h4 fxLayoutAlign="start" class="dashboard-info-title">Lightning</h4>
<div class="overflow-wrap dashboard-info-value">{{balances.lightning | number}} Sats</div>
<div class="overflow-wrap dashboard-info-value">{{balances.lightning | number:'1.0-0'}} Sats</div>
<mat-progress-bar class="dashboard-progress-bar" mode="determinate" value="{{balances.lightning/balances.total*100}}"></mat-progress-bar>
</div>
<div>
<h4 fxLayoutAlign="start" class="dashboard-info-title">On-chain</h4>
<div class="overflow-wrap dashboard-info-value">{{balances.onchain | number}} Sats</div>
<div class="overflow-wrap dashboard-info-value">{{balances.onchain | number:'1.0-0'}} Sats</div>
<mat-progress-bar class="dashboard-progress-bar" mode="determinate" value="{{balances.onchain/balances.total*100}}"></mat-progress-bar>
</div>
<div>
<h4 fxLayoutAlign="start" class="dashboard-info-title">Total</h4>
<div class="overflow-wrap dashboard-info-value">{{balances.total | number}} Sats</div>
<div class="overflow-wrap dashboard-info-value">{{balances.total | number:'1.0-0'}} Sats</div>
</div>
</div>
<ng-template #errorBlock>

@ -15,18 +15,18 @@
<div class="channels-capacity-scroll" [perfectScrollbar]>
<div *ngIf="activeChannels && activeChannels.length > 0; else noChannelBlock" fxLayout="column"fxFlex="100">
<div *ngFor="let channel of activeChannels" class="mt-2">
<a class="dashboard-capacity-header" [routerLink]="['../connections/channels/open']" [state]="{filter: channel.id}" matTooltip="{{channel.alias || channel.id}}" matTooltipDisabled="{{(channel.alias || channel.id).length < 26}}">
{{(channel.alias || channel.id) | slice:0:24}}{{(channel.alias || channel.id).length > 25 ? '...' : ''}}
<a class="dashboard-capacity-header" [routerLink]="['../connections/channels/open']" [state]="{filter: channel.peer_id}" matTooltip="{{channel.alias || channel.peer_id}}" matTooltipDisabled="{{(channel.alias || channel.peer_id).length < 26}}">
{{(channel.alias || channel.peer_id) | slice:0:24}}{{(channel.alias || channel.peer_id).length > 25 ? '...' : ''}}
</a>
<div fxLayout="row" fxLayoutAlign="space-between start" class="w-100">
<mat-hint fxFlex="40" fxLayoutAlign="start center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Local:</strong>{{channel.msatoshi_to_us/1000 || 0 | number:'1.0-0'}} Sats</mat-hint>
<mat-hint fxFlex="40" fxLayoutAlign="start center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Local:</strong>{{channel.to_us_msat/1000 || 0 | number:'1.0-0'}} Sats</mat-hint>
<mat-hint fxFlex="20" fxLayoutAlign="center center" class="font-size-90 color-primary">
<fa-icon class="color-primary mr-3px" matTooltip="Balance Score" [icon]="faBalanceScale"></fa-icon>
({{channel.balancedness || 0 | number}})
</mat-hint>
<mat-hint fxFlex="40" fxLayoutAlign="end center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Remote:</strong>{{channel.msatoshi_to_them/1000 || 0 | number:'1.0-0'}} Sats</mat-hint>
<mat-hint fxFlex="40" fxLayoutAlign="end center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Remote:</strong>{{channel.to_them_msat/1000 || 0 | number:'1.0-0'}} Sats</mat-hint>
</div>
<mat-progress-bar class="dashboard-progress-bar" mode="determinate" value="{{channel.msatoshi_to_us && channel.msatoshi_to_us > 0 ? ((+channel.msatoshi_to_us/((+channel.msatoshi_to_us)+(+channel.msatoshi_to_them)))*100) : 0}}"></mat-progress-bar>
<mat-progress-bar class="dashboard-progress-bar" mode="determinate" value="{{channel.to_us_msat && channel.to_us_msat > 0 ? ((channel.to_us_msat/((channel.to_us_msat)+(channel.to_them_msat)))*100) : 0}}"></mat-progress-bar>
</div>
</div>
</div>

@ -8,15 +8,15 @@
<div fxLayout="column" fxFlex.gt-sm="88" fxFlex="84" fxLayoutAlign="start start" [perfectScrollbar]>
<div *ngIf="activeChannels && activeChannels.length > 0; else noChannelBlock" fxLayout="column" fxFlex="100"class="w-100">
<div *ngFor="let channel of activeChannels" class="mt-2">
<a class="dashboard-capacity-header" [routerLink]="['../connections/channels/open']" [state]="{filter: channel.id}" matTooltip="{{channel.alias || channel.id}}" matTooltipDisabled="{{(channel.alias || channel.id).length < 26}}">
{{(channel.alias || channel.id) | slice:0:24}}{{(channel.alias || channel.id).length > 25 ? '...' : ''}}
<a class="dashboard-capacity-header" [routerLink]="['../connections/channels/open']" [state]="{filter: channel.peer_id}" matTooltip="{{channel.alias || channel.peer_id}}" matTooltipDisabled="{{(channel.alias || channel.peer_id).length < 26}}">
{{(channel.alias || channel.peer_id) | slice:0:24}}{{(channel.alias || channel.peer_id).length > 25 ? '...' : ''}}
</a>
<div fxLayout="row" fxLayoutAlign="space-between start" class="w-100">
<mat-hint *ngIf="direction === 'In'" fxFlex="100" fxLayoutAlign="start center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Capacity: </strong>{{channel.msatoshi_to_them/1000 || 0 | number:'1.0-0'}} Sats</mat-hint>
<mat-hint *ngIf="direction === 'Out'" fxFlex="100" fxLayoutAlign="start center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Capacity: </strong>{{channel.msatoshi_to_us/1000 || 0 | number:'1.0-0'}} Sats</mat-hint>
<mat-hint *ngIf="direction === 'In'" fxFlex="100" fxLayoutAlign="start center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Capacity: </strong>{{channel.to_them_msat/1000 || 0 | number:'1.0-0'}} Sats</mat-hint>
<mat-hint *ngIf="direction === 'Out'" fxFlex="100" fxLayoutAlign="start center" class="font-size-90 color-primary"><strong class="font-weight-900 mr-5px">Capacity: </strong>{{channel.to_us_msat/1000 || 0 | number:'1.0-0'}} Sats</mat-hint>
</div>
<mat-progress-bar *ngIf="direction === 'In'" class="dashboard-progress-bar" mode="determinate" value="{{(totalLiquidity > 0) ? ((+channel.msatoshi_to_them/1000 || 0)/(totalLiquidity) * 100) : 0}}"></mat-progress-bar>
<mat-progress-bar *ngIf="direction === 'Out'" class="dashboard-progress-bar" mode="determinate" value="{{(totalLiquidity > 0) ? ((+channel.msatoshi_to_us/1000 || 0)/(totalLiquidity) * 100) : 0}}"></mat-progress-bar>
<mat-progress-bar *ngIf="direction === 'In'" class="dashboard-progress-bar" mode="determinate" value="{{(totalLiquidity > 0) ? ((channel.to_them_msat/1000 || 0)/(totalLiquidity) * 100) : 0}}"></mat-progress-bar>
<mat-progress-bar *ngIf="direction === 'Out'" class="dashboard-progress-bar" mode="determinate" value="{{(totalLiquidity > 0) ? ((channel.to_us_msat/1000 || 0)/(totalLiquidity) * 100) : 0}}"></mat-progress-bar>
</div>
</div>
</div>

@ -16,15 +16,15 @@
<div fxLayout="column" fxFlex="50" fxLayoutAlign="space-between stretch">
<div>
<h4 fxLayoutAlign="start" class="dashboard-info-title">Capacity</h4>
<div class="overflow-wrap dashboard-info-value">{{(channelsStatus?.active?.capacity || 0) | number}} Sats</div>
<div class="overflow-wrap dashboard-info-value">{{(channelsStatus?.active?.capacity || 0) | number:'1.0-0'}} Sats</div>
</div>
<div>
<h4 fxLayoutAlign="start" class="dashboard-info-title">Capacity</h4>
<div class="overflow-wrap dashboard-info-value">{{(channelsStatus?.pending?.capacity || 0) | number}} Sats</div>
<div class="overflow-wrap dashboard-info-value">{{(channelsStatus?.pending?.capacity || 0) | number:'1.0-0'}} Sats</div>
</div>
<div>
<h4 fxLayoutAlign="start" class="dashboard-info-title">Capacity</h4>
<div class="overflow-wrap dashboard-info-value">{{(channelsStatus?.inactive?.capacity || 0) | number}} Sats</div>
<div class="overflow-wrap dashboard-info-value">{{(channelsStatus?.inactive?.capacity || 0) | number:'1.0-0'}} Sats</div>
</div>
</div>
</div>

@ -155,11 +155,11 @@ export class CLNHomeComponent implements OnInit, OnDestroy {
this.totalOutboundLiquidity = 0;
this.activeChannels = channelsSeletor.activeChannels;
this.activeChannelsCapacity = JSON.parse(JSON.stringify(this.commonService.sortDescByKey(this.activeChannels, 'balancedness'))) || [];
this.allInboundChannels = JSON.parse(JSON.stringify(this.commonService.sortDescByKey(this.activeChannels?.filter((channel) => (channel.msatoshi_to_them ? channel.msatoshi_to_them > 0 : false)), 'msatoshi_to_them'))) || [];
this.allOutboundChannels = JSON.parse(JSON.stringify(this.commonService.sortDescByKey(this.activeChannels?.filter((channel) => (channel.msatoshi_to_us ? channel.msatoshi_to_us > 0 : false)), 'msatoshi_to_us'))) || [];
this.allInboundChannels = JSON.parse(JSON.stringify(this.commonService.sortDescByKey(this.activeChannels?.filter((channel) => (channel.to_them_msat ? channel.to_them_msat > 0 : false)), 'to_them_msat'))) || [];
this.allOutboundChannels = JSON.parse(JSON.stringify(this.commonService.sortDescByKey(this.activeChannels?.filter((channel) => (channel.to_us_msat ? channel.to_us_msat > 0 : false)), 'to_us_msat'))) || [];
this.activeChannels.forEach((channel) => {
this.totalInboundLiquidity = this.totalInboundLiquidity + Math.ceil((channel.msatoshi_to_them || 0) / 1000);
this.totalOutboundLiquidity = this.totalOutboundLiquidity + Math.floor((channel.msatoshi_to_us || 0) / 1000);
this.totalInboundLiquidity = this.totalInboundLiquidity + Math.ceil((channel.to_them_msat || 0) / 1000);
this.totalOutboundLiquidity = this.totalOutboundLiquidity + Math.floor((channel.to_us_msat || 0) / 1000);
});
this.channelsStatus.active.channels = channelsSeletor.activeChannels.length || 0;
this.channelsStatus.pending.channels = channelsSeletor.pendingChannels.length || 0;
@ -205,8 +205,8 @@ export class CLNHomeComponent implements OnInit, OnDestroy {
if (this.sortField === 'Balance Score') {
this.sortField = 'Capacity';
this.activeChannelsCapacity = this.activeChannels.sort((a, b) => {
const x = (a.msatoshi_to_us ? +a.msatoshi_to_us : 0) + (a.msatoshi_to_them ? +a.msatoshi_to_them : 0);
const y = (b.msatoshi_to_them ? +b.msatoshi_to_them : 0) + (b.msatoshi_to_them ? +b.msatoshi_to_them : 0);
const x = (a.to_us_msat ? +a.to_us_msat : 0) + (a.to_them_msat ? +a.to_them_msat : 0);
const y = (b.to_them_msat ? +b.to_them_msat : 0) + (b.to_them_msat ? +b.to_them_msat : 0);
return ((x > y) ? -1 : ((x < y) ? 1 : 0));
});
} else {

@ -230,8 +230,10 @@ export class CLNLiquidityAdsListComponent implements OnInit, OnDestroy {
if (lqNode.features && lqNode.features.trim() !== '') {
const featureHex = parseInt(lqNode.features, 16);
NODE_FEATURES_CLN.forEach((feature) => {
if (!!(featureHex & ((1 << feature.range.min) | (1 << feature.range.max)))) {
featureDescriptions.push(feature.description);
if (featureHex & (1 << feature.range.min)) {
featureDescriptions.push('Mandatory: ' + feature.description);
} else if (featureHex & (1 << feature.range.max)) {
featureDescriptions.push('Optional: ' + feature.description);
}
});
}

@ -1,62 +1,92 @@
<div *ngIf="errorMessage?.trim() === ''; else errorBlock" fxLayout="column" fxLayout.gt-xs="row" fxFlex="100" fxLayoutAlign="stretch stretch">
<div fxLayout="column" fxFlex="50" fxLayoutAlign="space-between stretch" class="mt-2">
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Opening
<mat-icon matTooltip="Default feerate for fundchannel and withdraw" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.opening | number}}</div>
<div *ngIf="errorMessage?.trim() === ''; else errorBlock" fxLayout="column" fxFlex="100" fxLayoutAlign="stretch stretch">
<div fxLayout="column" fxLayout.gt-xs="row" fxFlex="100" fxLayoutAlign="stretch stretch">
<div fxLayout="column" fxFlex="50" fxLayoutAlign="space-between stretch" class="mt-2">
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Opening
<mat-icon matTooltip="Default feerate for fundchannel and withdraw" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.opening | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Mutual Close
<mat-icon matTooltip="Feerate to aim for in cooperative shutdown. Note that since mutual close is a negotiation, the actual feerate used in mutual close will be somewhere between this and the corresponding mutual close feerate of the peer" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.mutual_close | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Unilateral Close
<mat-icon matTooltip="Feerate for commitment transaction in a live channel which we originally funded" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.unilateral_close | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Delayed To Us
<mat-icon matTooltip="Feerate for returning unilateral close funds to our wallet" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.delayed_to_us | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Minimum Acceptable
<mat-icon matTooltip="The smallest feerate that you can use, usually the minimum relayed feerate of the backend" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.min_acceptable | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Maximum Acceptable
<mat-icon matTooltip="The largest feerate we will accept from remote negotiations. If a peer attempts to set the feerate higher than this we will unilaterally close the channel (or simply forget it if it's not open yet)" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.max_acceptable | number}}</div>
</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Mutual Close
<mat-icon matTooltip="Feerate to aim for in cooperative shutdown. Note that since mutual close is a negotiation, the actual feerate used in mutual close will be somewhere between this and the corresponding mutual close feerate of the peer" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.mutual_close | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Unilateral Close
<mat-icon matTooltip="Feerate for commitment transaction in a live channel which we originally funded" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.unilateral_close | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Delayed To Us
<mat-icon matTooltip="Feerate for returning unilateral close funds to our wallet" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.delayed_to_us | number}}</div>
</div>
</div>
<div fxLayout="column" fxFlex="50" fxLayoutAlign="space-between stretch" class="my-2">
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Minimum Acceptable
<mat-icon matTooltip="The smallest feerate that you can use, usually the minimum relayed feerate of the backend" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.min_acceptable | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Maximum Acceptable
<mat-icon matTooltip="The largest feerate we will accept from remote negotiations. If a peer attempts to set the feerate higher than this we will unilaterally close the channel (or simply forget it if it's not open yet)" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.max_acceptable | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
HTLC Resolution
<mat-icon matTooltip="Feerate for returning unilateral close HTLC outputs to our wallet" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.htlc_resolution | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Penalty
<mat-icon matTooltip="Feerate to start at when penalizing a cheat attempt" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.penalty | number}}</div>
<div fxLayout="column" fxFlex="50" fxLayoutAlign="space-between stretch" class="mt-2">
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
HTLC Resolution
<mat-icon matTooltip="Feerate for returning unilateral close HTLC outputs to our wallet" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.htlc_resolution | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Penalty
<mat-icon matTooltip="Feerate to start at when penalizing a cheat attempt" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.penalty | number}}</div>
</div>
<div *ngIf="perkbw?.estimates && perkbw?.estimates.length && perkbw?.estimates.length > 3">
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
2 Blocks
<mat-icon matTooltip="Fee rate estimate for 2 blocks" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.estimates[0].smoothed_feerate | number}}</div>
</div>
<div *ngIf="perkbw?.estimates && perkbw?.estimates.length && perkbw?.estimates.length > 3">
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
6 Blocks
<mat-icon matTooltip="Fee rate estimate for 6 blocks" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.estimates[1].smoothed_feerate | number}}</div>
</div>
<div *ngIf="perkbw?.estimates && perkbw?.estimates.length && perkbw?.estimates.length > 3">
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
12 Blocks
<mat-icon matTooltip="Fee rate estimate for 12 blocks" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.estimates[2].smoothed_feerate | number}}</div>
</div>
<div *ngIf="perkbw?.estimates && perkbw?.estimates.length && perkbw?.estimates.length > 3">
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
100 Blocks
<mat-icon matTooltip="Fee rate estimate for 100 blocks" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{perkbw?.estimates[3].smoothed_feerate | number}}</div>
</div>
</div>
</div>
</div>

@ -1,3 +1,3 @@
.fee-rate-list .mat-list-item {
height: 44px;
}
height: 44px;
}

@ -13,14 +13,15 @@ export class CLNFeeRatesComponent implements AfterContentChecked {
@Input() feeRates: FeeRates;
@Input() errorMessage: string;
perkbw: FeeRatePerObj = {};
displayedColumns: string[] = ['blockcount', 'feerate'];
constructor() { }
ngAfterContentChecked() {
if (this.feeRateStyle === feeRateStyle.KB) {
this.perkbw = this.feeRates.perkb!;
this.perkbw = this.feeRates.perkb || {};
} else if (this.feeRateStyle === feeRateStyle.KW) {
this.perkbw = this.feeRates.perkw!;
this.perkbw = this.feeRates.perkw || {};
}
}

@ -54,28 +54,28 @@ export class CLNNetworkInfoComponent implements OnInit, OnDestroy {
{ id: 'node', icon: this.faServer, title: 'Node Information', cols: 6, rows: 3 },
{ id: 'status', icon: this.faNetworkWired, title: 'Channels', cols: 6, rows: 3 },
{ id: 'fee', icon: this.faBolt, title: 'Routing Fee', cols: 6, rows: 1 },
{ id: 'feeRatesKB', icon: this.faServer, title: 'Fee Rate Per KB', cols: 4, rows: 4 },
{ id: 'feeRatesKW', icon: this.faNetworkWired, title: 'Fee Rate Per KW', cols: 4, rows: 4 },
{ id: 'onChainFeeEstimates', icon: this.faLink, title: 'Onchain Fee Estimates (Sats)', cols: 4, rows: 4 }
{ id: 'feeRatesKB', icon: this.faServer, title: 'Fee Rate Per KB', cols: 4, rows: 6 },
{ id: 'feeRatesKW', icon: this.faNetworkWired, title: 'Fee Rate Per KW', cols: 4, rows: 6 },
{ id: 'onChainFeeEstimates', icon: this.faLink, title: 'Onchain Fee Estimates (Sats)', cols: 4, rows: 6 }
];
this.nodeCardsOperator = [
{ id: 'feeRatesKB', icon: this.faServer, title: 'Fee Rate Per KB', cols: 4, rows: 4 },
{ id: 'feeRatesKW', icon: this.faNetworkWired, title: 'Fee Rate Per KW', cols: 4, rows: 4 },
{ id: 'onChainFeeEstimates', icon: this.faLink, title: 'Onchain Fee Estimates (Sats)', cols: 4, rows: 4 }
{ id: 'feeRatesKB', icon: this.faServer, title: 'Fee Rate Per KB', cols: 4, rows: 6 },
{ id: 'feeRatesKW', icon: this.faNetworkWired, title: 'Fee Rate Per KW', cols: 4, rows: 6 },
{ id: 'onChainFeeEstimates', icon: this.faLink, title: 'Onchain Fee Estimates (Sats)', cols: 4, rows: 6 }
];
} else {
this.nodeCardsMerchant = [
{ id: 'node', icon: this.faServer, title: 'Node Information', cols: 2, rows: 3 },
{ id: 'status', icon: this.faNetworkWired, title: 'Channels', cols: 2, rows: 3 },
{ id: 'fee', icon: this.faBolt, title: 'Routing Fee', cols: 2, rows: 3 },
{ id: 'feeRatesKB', icon: this.faServer, title: 'Fee Rate Per KB', cols: 2, rows: 4 },
{ id: 'feeRatesKW', icon: this.faNetworkWired, title: 'Fee Rate Per KW', cols: 2, rows: 4 },
{ id: 'onChainFeeEstimates', icon: this.faLink, title: 'Onchain Fee Estimates (Sats)', cols: 2, rows: 4 }
{ id: 'feeRatesKB', icon: this.faServer, title: 'Fee Rate Per KB', cols: 2, rows: 6 },
{ id: 'feeRatesKW', icon: this.faNetworkWired, title: 'Fee Rate Per KW', cols: 2, rows: 6 },
{ id: 'onChainFeeEstimates', icon: this.faLink, title: 'Onchain Fee Estimates (Sats)', cols: 2, rows: 6 }
];
this.nodeCardsOperator = [
{ id: 'feeRatesKB', icon: this.faServer, title: 'Fee Rate Per KB', cols: 2, rows: 4 },
{ id: 'feeRatesKW', icon: this.faNetworkWired, title: 'Fee Rate Per KW', cols: 2, rows: 4 },
{ id: 'onChainFeeEstimates', icon: this.faLink, title: 'Onchain Fee Estimates (Sats)', cols: 2, rows: 4 }
{ id: 'feeRatesKB', icon: this.faServer, title: 'Fee Rate Per KB', cols: 2, rows: 6 },
{ id: 'feeRatesKW', icon: this.faNetworkWired, title: 'Fee Rate Per KW', cols: 2, rows: 6 },
{ id: 'onChainFeeEstimates', icon: this.faLink, title: 'Onchain Fee Estimates (Sats)', cols: 2, rows: 6 }
];
}
}

@ -1,58 +1,60 @@
<div *ngIf="errorMessage?.trim() === ''; else errorBlock" fxLayout="column" fxLayout.gt-xs="row" fxFlex="100" fxLayoutAlign="stretch stretch">
<div fxLayout="column" fxFlex="50" fxLayoutAlign="space-between stretch" class="mt-2">
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Opening Channel
<mat-icon matTooltip="Estimated cost of typical channel open" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{feeRates?.onchain_fee_estimates?.opening_channel_satoshis | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Mutual Close
<mat-icon matTooltip="Estimated cost of typical channel close" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{feeRates?.onchain_fee_estimates?.mutual_close_satoshis | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Unilateral Close
<mat-icon matTooltip="Estimated cost of typical unilateral close (without HTLCs)" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{feeRates?.onchain_fee_estimates?.unilateral_close_satoshis | number}}</div>
</div>
<div fxFlex="12">
<h4 fxLayoutAlign="start start" class="dashboard-info-title"></h4>
<div class="overflow-wrap dashboard-info-value"></div>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="stretch stretch">
<div *ngIf="errorMessage?.trim() === ''; else errorBlock" fxLayout="column" fxLayout.gt-xs="row" fxFlex="62" fxLayoutAlign="stretch stretch">
<div fxLayout="column" fxFlex="50" fxLayoutAlign="space-between stretch" class="mt-2">
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Opening Channel
<mat-icon matTooltip="Estimated cost of typical channel open" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{feeRates?.onchain_fee_estimates?.opening_channel_satoshis | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Mutual Close
<mat-icon matTooltip="Estimated cost of typical channel close" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{feeRates?.onchain_fee_estimates?.mutual_close_satoshis | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
Unilateral Close
<mat-icon matTooltip="Estimated cost of typical unilateral close (without HTLCs)" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{feeRates?.onchain_fee_estimates?.unilateral_close_satoshis | number}}</div>
</div>
<div fxFlex="12">
<h4 fxLayoutAlign="start start" class="dashboard-info-title"></h4>
<div class="overflow-wrap dashboard-info-value"></div>
</div>
</div>
<div fxLayout="column" fxFlex="50" fxLayoutAlign="space-between stretch" class="mt-2">
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
HTLC Timeout
<mat-icon matTooltip="Estimated cost of typical HTLC timeout transaction" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{feeRates?.onchain_fee_estimates?.htlc_timeout_satoshis | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
HTLC Success
<mat-icon matTooltip="Estimated cost of typical HTLC fulfillment transaction" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{feeRates?.onchain_fee_estimates?.htlc_success_satoshis | number}}</div>
</div>
<div fxFlex="12">
<h4 fxLayoutAlign="start start" class="dashboard-info-title"></h4>
<div class="overflow-wrap dashboard-info-value"></div>
</div>
<div fxFlex="12">
<h4 fxLayoutAlign="start start" class="dashboard-info-title"></h4>
<div class="overflow-wrap dashboard-info-value"></div>
</div>
</div>
</div>
<div fxLayout="column" fxFlex="50" fxLayoutAlign="space-between stretch" class="mt-2">
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
HTLC Timeout
<mat-icon matTooltip="Estimated cost of typical HTLC timeout transaction" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{feeRates?.onchain_fee_estimates?.htlc_timeout_satoshis | number}}</div>
</div>
<div>
<h4 fxLayoutAlign="start start" class="dashboard-info-title">
HTLC Success
<mat-icon matTooltip="Estimated cost of typical HTLC fulfillment transaction" matTooltipPosition="below" class="info-icon info-icon-primary">info_outline</mat-icon>
</h4>
<div class="overflow-wrap dashboard-info-value">{{feeRates?.onchain_fee_estimates?.htlc_success_satoshis | number}}</div>
<ng-template #errorBlock>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between" class="p-2">
<p>{{errorMessage}}</p>
</div>
<div fxFlex="12">
<h4 fxLayoutAlign="start start" class="dashboard-info-title"></h4>
<div class="overflow-wrap dashboard-info-value"></div>
</div>
<div fxFlex="12">
<h4 fxLayoutAlign="start start" class="dashboard-info-title"></h4>
<div class="overflow-wrap dashboard-info-value"></div>
</div>
</div>
</ng-template>
</div>
<ng-template #errorBlock>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between" class="p-2">
<p>{{errorMessage}}</p>
</div>
</ng-template>

@ -64,7 +64,7 @@
<mat-label>Coin Selection</mat-label>
<mat-select tabindex="8" multiple [(value)]="selUTXOs" (selectionChange)="onUTXOSelectionChange($event)">
<mat-select-trigger>{{totalSelectedUTXOAmount | number}} Sats ({{selUTXOs.length > 1 ? selUTXOs.length + ' UTXOs' : '1 UTXO'}})</mat-select-trigger>
<mat-option *ngFor="let utxo of utxos" [value]="utxo">{{utxo.value | number}} Sats</mat-option>
<mat-option *ngFor="let utxo of utxos" [value]="utxo">{{utxo.amount_msat/1000 | number:'1.0-0'}} Sats</mat-option>
</mat-select>
</mat-form-field>
<div fxFlex="60" fxLayout="row" fxLayoutAlign="start center">

@ -285,7 +285,7 @@ export class CLNOnChainSendModalComponent implements OnInit, OnDestroy {
onUTXOSelectionChange(event: any) {
if (this.selUTXOs.length && this.selUTXOs.length > 0) {
this.totalSelectedUTXOAmount = this.selUTXOs?.reduce((total, curr) => (total + (curr.value || 0)), 0);
this.totalSelectedUTXOAmount = this.selUTXOs?.reduce((total, curr) => (total + ((curr.amount_msat || 0) / 1000)), 0);
if (this.flgUseAllBalance) {
this.onUTXOAllBalanceChange();
}

@ -31,7 +31,7 @@ export class CLNUTXOTablesComponent implements OnInit, OnDestroy {
subscribe((utxosSeletor: { utxos: UTXO[], apiCallStatus: ApiCallStatusPayload }) => {
if (utxosSeletor.utxos && utxosSeletor.utxos.length > 0) {
this.numUtxos = utxosSeletor.utxos.length || 0;
this.numDustUtxos = utxosSeletor.utxos?.filter((utxo) => +(utxo.value || 0) < this.DUST_AMOUNT).length || 0;
this.numDustUtxos = utxosSeletor.utxos?.filter((utxo) => (+(utxo.amount_msat || 0) / 1000) < this.DUST_AMOUNT).length || 0;
}
this.logger.info(utxosSeletor);
});

@ -21,7 +21,7 @@
<ng-container matColumnDef="is_dust">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before" matTooltip="Dust/Nondust"></th>
<td *matCellDef="let utxo" mat-cell>
<span *ngIf="numDustUTXOs > 0 && !isDustUTXO && utxo.value < dustAmount; else emptySpace" matTooltip="Risk of dust attack" matTooltipPosition="right">
<span *ngIf="numDustUTXOs > 0 && !isDustUTXO && (utxo?.amount_msat / 1000) < dustAmount; else emptySpace" matTooltip="Risk of dust attack" matTooltipPosition="right">
<mat-icon fxLayoutAlign="start center" color="warn" class="small-icon">warning</mat-icon>
</span>
</td>
@ -65,8 +65,8 @@
<ng-container matColumnDef="value">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Value (Sats)</th>
<td *matCellDef="let utxo" mat-cell>
<span *ngIf="utxo.value > 0 || utxo.value === 0" fxLayoutAlign="end center">{{utxo.value | number}}</span>
<span *ngIf="utxo.value < 0" fxLayoutAlign="end center" class="red">({{utxo.value * -1 | number}})</span>
<span *ngIf="utxo.amount_msat > 0 || utxo.amount_msat === 0" fxLayoutAlign="end center">{{utxo.amount_msat / 1000 | number:'1.0-0'}}</span>
<span *ngIf="utxo.amount_msat < 0" fxLayoutAlign="end center" class="red">({{utxo.amount_msat / 1000 * -1 | number:'1.0-0'}})</span>
</td>
</ng-container>
<ng-container matColumnDef="blockheight">

@ -87,7 +87,7 @@ export class CLNOnChainUtxosComponent implements OnInit, AfterViewInit, OnDestro
this.errorMessage = !this.apiCallStatus.message ? '' : (typeof (this.apiCallStatus.message) === 'object') ? JSON.stringify(this.apiCallStatus.message) : this.apiCallStatus.message;
}
if (utxosSelector.utxos && utxosSelector.utxos.length > 0) {
this.dustUtxos = utxosSelector.utxos?.filter((utxo) => +(utxo.value || 0) < this.dustAmount);
this.dustUtxos = utxosSelector.utxos?.filter((utxo) => +(utxo.amount_msat || 0) / 1000 < this.dustAmount);
this.utxos = utxosSelector.utxos;
if (this.isDustUTXO) {
if (this.dustUtxos && this.dustUtxos.length > 0 && this.sort && this.paginator && this.displayedColumns.length > 0) {
@ -122,7 +122,7 @@ export class CLNOnChainUtxosComponent implements OnInit, AfterViewInit, OnDestro
const reorderedUTXO = [
[{ key: 'txid', value: selUtxo.txid, title: 'Transaction ID', width: 100 }],
[{ key: 'output', value: selUtxo.output, title: 'Output', width: 50, type: DataTypeEnum.NUMBER },
{ key: 'value', value: selUtxo.value, title: 'Value (Sats)', width: 50, type: DataTypeEnum.NUMBER }],
{ key: 'amount_msat', value: (selUtxo.amount_msat || 0) / 1000, title: 'Value (Sats)', width: 50, type: DataTypeEnum.NUMBER }],
[{ key: 'status', value: this.commonService.titleCase(selUtxo.status || ''), title: 'Status', width: 50, type: DataTypeEnum.STRING },
{ key: 'blockheight', value: selUtxo.blockheight, title: 'Blockheight', width: 50, type: DataTypeEnum.NUMBER }],
[{ key: 'address', value: selUtxo.address, title: 'Address', width: 100 }]
@ -156,13 +156,17 @@ export class CLNOnChainUtxosComponent implements OnInit, AfterViewInit, OnDestro
break;
case 'is_dust':
rowToFilter = (rowData?.value || 0) < this.dustAmount ? 'dust' : 'nondust';
rowToFilter = (rowData?.amount_msat || 0) / 1000 < this.dustAmount ? 'dust' : 'nondust';
break;
case 'status':
rowToFilter = rowData?.status?.toLowerCase() || '';
break;
case 'value':
rowToFilter = (rowData?.value || ((rowData?.amount_msat || 0) / 1000)).toString();
break;
default:
rowToFilter = typeof rowData[this.selFilterBy] === 'undefined' ? '' : typeof rowData[this.selFilterBy] === 'string' ? rowData[this.selFilterBy].toLowerCase() : typeof rowData[this.selFilterBy] === 'boolean' ? (rowData[this.selFilterBy] ? 'yes' : 'no') : rowData[this.selFilterBy].toString();
break;
@ -176,7 +180,8 @@ export class CLNOnChainUtxosComponent implements OnInit, AfterViewInit, OnDestro
this.listUTXOs.sort = this.sort;
this.listUTXOs.sortingDataAccessor = (data: UTXO, sortHeaderId: string) => {
switch (sortHeaderId) {
case 'is_dust': return +(data.value || 0) < this.dustAmount;
case 'is_dust': return (+(data.amount_msat || 0) / 1000) < this.dustAmount;
case 'value': return data.value || (+(data.amount_msat || 0) / 1000);
default: return (data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null;
}
};

@ -32,49 +32,63 @@
<div fxLayout="row">
<div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Peer Public Key</h4>
<span class="foreground-secondary-text">{{channel.id}}</span>
<span class="foreground-secondary-text">{{channel.peer_id}}</span>
</div>
</div>
<mat-divider class="my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="25">
<h4 fxLayoutAlign="start" class="font-bold-500">mSatoshi to Us</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.msatoshi_to_us | number}}</span>
</div>
<div fxFlex="25">
<h4 fxLayoutAlign="start" class="font-bold-500">Spendable (mSats)</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.spendable_msatoshi | number}}</span>
<div fxFlex="33">
<h4 fxLayoutAlign="start" class="font-bold-500">State</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel?.state | camelcaseWithReplace:'_'}}</span>
</div>
<div fxFlex="25">
<h4 fxLayoutAlign="start" class="font-bold-500">Total (mSats)</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.msatoshi_total | number}}</span>
<div fxFlex="33">
<h4 fxLayoutAlign="start" class="font-bold-500">Connected</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.peer_connected ? 'Yes' : 'No'}}</span>
</div>
<div fxFlex="25">
<h4 fxLayoutAlign="start" class="font-bold-500">State</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.state}}</span>
<div fxFlex="34">
<h4 fxLayoutAlign="start" class="font-bold-500">Private</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.private ? 'Yes' : 'No'}}</span>
</div>
</div>
<mat-divider class="my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="25">
<h4 fxLayoutAlign="start" class="font-bold-500">Our Reserve (Sats)</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.our_channel_reserve_satoshis | number}}</span>
<div fxFlex="33">
<h4 fxLayoutAlign="start" class="font-bold-500">Remote Balance (Sats)</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.to_them_msat / 1000 | number:'1.0-0'}}</span>
</div>
<div fxFlex="25">
<h4 fxLayoutAlign="start" class="font-bold-500">Their Reserve (Sats)</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.their_channel_reserve_satoshis | number}}</span>
<div fxFlex="33">
<h4 fxLayoutAlign="start" class="font-bold-500">Local Balance (Sats)</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.to_us_msat / 1000 | number:'1.0-0'}}</span>
</div>
<div fxFlex="25">
<h4 fxLayoutAlign="start" class="font-bold-500">Connected</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.peer_connected ? 'Yes' : 'No'}}</span>
</div>
<div fxFlex="25">
<h4 fxLayoutAlign="start" class="font-bold-500">Private</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.private ? 'Yes' : 'No'}}</span>
<div fxFlex="34">
<h4 fxLayoutAlign="start" class="font-bold-500">Total (Sats)</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.total_msat / 1000 | number:'1.0-0'}}</span>
</div>
</div>
<mat-divider class="my-1"></mat-divider>
<div *ngIf="showAdvanced">
<div fxLayout="row">
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Receivable (Sats)</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.receivable_msat / 1000 | number:'1.0-0'}}</span>
</div>
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Spendable (Sats)</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.spendable_msat / 1000 | number:'1.0-0'}}</span>
</div>
</div>
<mat-divider class="my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Their Reserve (Sats)</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.their_reserve_msat / 1000 | number:'1.0-2'}}</span>
</div>
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Our Reserve (Sats)</h4>
<span class="overflow-wrap foreground-secondary-text">{{channel.our_reserve_msat / 1000 | number:'1.0-2'}}</span>
</div>
</div>
<mat-divider class="my-1"></mat-divider>
<div fxLayout="row">
<div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Funding Transaction ID</h4>

@ -71,32 +71,32 @@
<ng-container matColumnDef="our_channel_reserve_satoshis">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Local Reserve (Sats)</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.our_channel_reserve_satoshis | number:'1.0-0'}} </span></td>
{{channel?.our_reserve_msat | number:'1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="their_channel_reserve_satoshis">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Remote Reserve (Sats)</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.their_channel_reserve_satoshis | number:'1.0-0'}} </span></td>
{{channel?.their_reserve_msat | number:'1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="msatoshi_total">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Total (Sats)</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.msatoshi_total/1000 | number:channel?.msatoshi_to_us < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
{{channel?.total_msat/1000 | number:channel?.to_us_msat < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="spendable_msatoshi">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Spendable (Sats)</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.spendable_msatoshi/1000 | number:channel?.msatoshi_to_us < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
{{channel?.spendable_msat/1000 | number:channel?.to_us_msat < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="msatoshi_to_us">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Local Balance (Sats)</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.msatoshi_to_us/1000 | number:channel?.msatoshi_to_us < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
{{channel?.to_us_msat/1000 | number:channel?.to_us_msat < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="msatoshi_to_them">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Remote Balance (Sats)</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.msatoshi_to_them/1000 | number:channel?.msatoshi_to_them < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
{{channel?.to_them_msat/1000 | number:channel?.to_them_msat < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="balancedness">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Balance Score</th>
@ -104,7 +104,7 @@
<div fxLayout="row">
<mat-hint fxFlex="100" fxLayoutAlign="center center" class="font-size-80">{{channel.balancedness || 0 | number}}</mat-hint>
</div>
<mat-progress-bar mode="determinate" value="{{channel.msatoshi_to_us && channel.msatoshi_to_us > 0 ? ((+channel.msatoshi_to_us/((+channel.msatoshi_to_us)+(+channel.msatoshi_to_them)))*100) : 0}}"></mat-progress-bar>
<mat-progress-bar mode="determinate" value="{{channel.to_us_msat && channel.to_us_msat > 0 ? ((channel.to_us_msat/((channel.to_us_msat)+(channel.to_them_msat)))*100) : 0}}"></mat-progress-bar>
</td>
</ng-container>
<ng-container matColumnDef="actions">

@ -158,7 +158,6 @@ export class CLNChannelOpenTableComponent implements OnInit, AfterViewInit, OnDe
return;
}
if (channelToUpdate === 'all') {
const confirmationMsg = [];
this.store.dispatch(openConfirmation({
payload: {
data: {
@ -166,7 +165,7 @@ export class CLNChannelOpenTableComponent implements OnInit, AfterViewInit, OnDe
alertTitle: 'Update Fee Policy',
noBtnText: 'Cancel',
yesBtnText: 'Update All',
message: confirmationMsg,
message: [],
titleMessage: 'Update fee policy for all channels',
flgShowInput: true,
getInputs: [
@ -288,9 +287,10 @@ export class CLNChannelOpenTableComponent implements OnInit, AfterViewInit, OnDe
rowToFilter = ((rowData.peer_connected) ? 'connected' : 'disconnected') + (rowData.channel_id ? rowData.channel_id.toLowerCase() : '') +
(rowData.short_channel_id ? rowData.short_channel_id.toLowerCase() : '') + (rowData.id ? rowData.id.toLowerCase() : '') + (rowData.alias ? rowData.alias.toLowerCase() : '') +
(rowData.private ? 'private' : 'public') + (rowData.state ? rowData.state.toLowerCase() : '') +
(rowData.funding_txid ? rowData.funding_txid.toLowerCase() : '') + (rowData.msatoshi_to_us ? rowData.msatoshi_to_us : '') +
(rowData.msatoshi_total ? rowData.msatoshi_total : '') + (rowData.their_channel_reserve_satoshis ? rowData.their_channel_reserve_satoshis : '') +
(rowData.our_channel_reserve_satoshis ? rowData.our_channel_reserve_satoshis : '') + (rowData.spendable_msatoshi ? rowData.spendable_msatoshi : '');
(rowData.funding_txid ? rowData.funding_txid.toLowerCase() : '') + (rowData.to_them_msat ? rowData.to_them_msat : '') +
(rowData.to_us_msat ? rowData.to_us_msat : '') + (rowData.total_msat ? rowData.total_msat : '') +
(rowData.their_reserve_msat ? rowData.their_reserve_msat : '') + (rowData.our_reserve_msat ? rowData.our_reserve_msat : '') +
(rowData.spendable_msat ? rowData.spendable_msat : '');
break;
case 'private':
@ -302,10 +302,19 @@ export class CLNChannelOpenTableComponent implements OnInit, AfterViewInit, OnDe
break;
case 'msatoshi_total':
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['total_msat'] || 0)) / 1000)?.toString() || '';
break;
case 'spendable_msatoshi':
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['spendable_msat'] || 0)) / 1000)?.toString() || '';
break;
case 'msatoshi_to_us':
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['to_us_msat'] || 0)) / 1000)?.toString() || '';
break;
case 'msatoshi_to_them':
rowToFilter = ((+(rowData[this.selFilterBy] || 0)) / 1000)?.toString() || '';
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['to_them_msat'] || 0)) / 1000)?.toString() || '';
break;
default:
@ -319,7 +328,24 @@ export class CLNChannelOpenTableComponent implements OnInit, AfterViewInit, OnDe
loadChannelsTable(mychannels) {
this.channels = new MatTableDataSource<Channel>([...mychannels]);
this.channels.sort = this.sort;
this.channels.sortingDataAccessor = (data: any, sortHeaderId: string) => ((data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null);
this.channels.sortingDataAccessor = (data: any, sortHeaderId: string) => {
switch (sortHeaderId) {
case 'msatoshi_total':
return data['msatoshi_total'] || data['total_msat'];
case 'spendable_msatoshi':
return data['spendable_msatoshi'] || data['spendable_msat'];
case 'msatoshi_to_us':
return data['msatoshi_to_us'] || data['to_us_msat'];
case 'msatoshi_to_them':
return data['msatoshi_to_them'] || data['to_them_msat'];
default:
return (data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null;
}
};
this.channels.paginator = this.paginator;
this.setFilterPredicate();
this.applyFilter();

@ -67,32 +67,32 @@
<ng-container matColumnDef="our_channel_reserve_satoshis">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Local Reserve (Sats)</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.our_channel_reserve_satoshis | number:'1.0-0'}} </span></td>
{{channel?.our_reserve_msat | number:'1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="their_channel_reserve_satoshis">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Remote Reserve (Sats)</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.their_channel_reserve_satoshis | number:'1.0-0'}} </span></td>
{{channel?.their_reserve_msat | number:'1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="msatoshi_total">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Total (Sats)</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.msatoshi_total/1000 | number:channel?.msatoshi_to_us < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
{{channel?.total_msat/1000 | number:channel?.to_us_msat < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="spendable_msatoshi">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Spendable (Sats)</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.spendable_msatoshi/1000 | number:channel?.msatoshi_to_us < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
{{channel?.spendable_msat/1000 | number:channel?.to_us_msat < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="msatoshi_to_us">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Local Balance (Sats)</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.msatoshi_to_us/1000 | number:channel?.msatoshi_to_us < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
{{channel?.to_us_msat/1000 | number:channel?.to_us_msat < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="msatoshi_to_them">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Remote Balance (Sats)</th>
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">
{{channel?.msatoshi_to_them/1000 | number:channel?.msatoshi_to_them < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
{{channel?.to_them_msat/1000 | number:channel?.to_them_msat < 1000 ? '1.0-4' : '1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="actions">
<th *matHeaderCellDef mat-header-cell>

@ -183,9 +183,9 @@ export class CLNChannelPendingTableComponent implements OnInit, AfterViewInit, O
rowToFilter = ((rowData.peer_connected) ? 'connected' : 'disconnected') + (rowData.channel_id ? rowData.channel_id.toLowerCase() : '') +
(rowData.short_channel_id ? rowData.short_channel_id.toLowerCase() : '') + (rowData.id ? rowData.id.toLowerCase() : '') + (rowData.alias ? rowData.alias.toLowerCase() : '') +
(rowData.private ? 'private' : 'public') + ((rowData.state && this.CLNChannelPendingState[rowData.state]) ? this.CLNChannelPendingState[rowData.state].toLowerCase() : '') +
(rowData.funding_txid ? rowData.funding_txid.toLowerCase() : '') + (rowData.msatoshi_to_us ? rowData.msatoshi_to_us : '') +
(rowData.msatoshi_total ? rowData.msatoshi_total : '') + (rowData.their_channel_reserve_satoshis ? rowData.their_channel_reserve_satoshis : '') +
(rowData.our_channel_reserve_satoshis ? rowData.our_channel_reserve_satoshis : '') + (rowData.spendable_msatoshi ? rowData.spendable_msatoshi : '');
(rowData.funding_txid ? rowData.funding_txid.toLowerCase() : '') + (rowData.to_us_msat ? rowData.to_us_msat : '') + (rowData.to_them_msat ? rowData.to_them_msat : '') +
(rowData.total_msat ? rowData.total_msat : '') + (rowData.their_reserve_msat ? rowData.their_reserve_msat : '') +
(rowData.our_reserve_msat ? rowData.our_reserve_msat : '') + (rowData.spendable_msat ? rowData.spendable_msat : '');
break;
case 'private':
@ -197,10 +197,19 @@ export class CLNChannelPendingTableComponent implements OnInit, AfterViewInit, O
break;
case 'msatoshi_total':
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['total_msat'] || 0)) / 1000)?.toString() || '';
break;
case 'spendable_msatoshi':
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['spendable_msat'] || 0)) / 1000)?.toString() || '';
break;
case 'msatoshi_to_us':
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['to_us_msat'] || 0)) / 1000)?.toString() || '';
break;
case 'msatoshi_to_them':
rowToFilter = ((+(rowData[this.selFilterBy] || 0)) / 1000)?.toString() || '';
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['to_them_msat'] || 0)) / 1000)?.toString() || '';
break;
case 'state':
@ -220,6 +229,18 @@ export class CLNChannelPendingTableComponent implements OnInit, AfterViewInit, O
this.channels.sort = this.sort;
this.channels.sortingDataAccessor = (data: any, sortHeaderId: string) => {
switch (sortHeaderId) {
case 'msatoshi_total':
return data['msatoshi_total'] || data['total_msat'];
case 'spendable_msatoshi':
return data['spendable_msatoshi'] || data['spendable_msat'];
case 'msatoshi_to_us':
return data['msatoshi_to_us'] || data['to_us_msat'];
case 'msatoshi_to_them':
return data['msatoshi_to_them'] || data['to_them_msat'];
case 'state':
return this.CLNChannelPendingState[data.state];

@ -71,7 +71,7 @@
<mat-label>Coin Selection</mat-label>
<mat-select tabindex="6" multiple [(value)]="selUTXOs" (selectionChange)="onUTXOSelectionChange($event)">
<mat-select-trigger>{{totalSelectedUTXOAmount | number}} Sats ({{selUTXOs.length > 1 ? selUTXOs.length + ' UTXOs' : '1 UTXO'}})</mat-select-trigger>
<mat-option *ngFor="let utxo of utxos" [value]="utxo">{{utxo.value | number}} Sats</mat-option>
<mat-option *ngFor="let utxo of utxos" [value]="utxo">{{utxo.amount_msat / 1000 | number:'1.0-0'}} Sats</mat-option>
</mat-select>
</mat-form-field>
<div fxFlex="41" fxLayout="row" fxLayoutAlign="start center">

@ -132,9 +132,9 @@ export class CLNRoutingReportComponent implements OnInit, OnDestroy {
}
this.filteredEventsBySelectedPeriod?.map((event) => {
const monthNumber = event.received_time ? new Date((+event.received_time) * 1000).getMonth() : 12;
feeReport[monthNumber].value = event.fee ? feeReport[monthNumber].value + (+event.fee / 1000) : feeReport[monthNumber].value;
feeReport[monthNumber].extra.totalEvents = feeReport[monthNumber].extra.totalEvents + 1;
this.totalFeeMsat = event.fee ? (this.totalFeeMsat ? this.totalFeeMsat : 0) + +event.fee : this.totalFeeMsat;
feeReport[monthNumber].value = feeReport[monthNumber].value + (+(event.fee || event.fee_msat || 0) / 1000);
this.totalFeeMsat = (this.totalFeeMsat || 0) + +(event.fee || event.fee_msat || 0);
return this.filteredEventsBySelectedPeriod;
});
} else {
@ -143,9 +143,9 @@ export class CLNRoutingReportComponent implements OnInit, OnDestroy {
}
this.filteredEventsBySelectedPeriod?.map((event) => {
const dateNumber = event.received_time ? Math.floor((+event.received_time - startDateInSeconds) / this.secondsInADay) : 0;
feeReport[dateNumber].value = event.fee ? feeReport[dateNumber].value + (+event.fee / 1000) : feeReport[dateNumber].value;
feeReport[dateNumber].extra.totalEvents = feeReport[dateNumber].extra.totalEvents + 1;
this.totalFeeMsat = event.fee ? (this.totalFeeMsat ? this.totalFeeMsat : 0) + +event.fee : this.totalFeeMsat;
feeReport[dateNumber].value = feeReport[dateNumber].value + (+(event.fee || event.fee_msat || 0) / 1000);
this.totalFeeMsat = (this.totalFeeMsat || 0) + +(event.fee || event.fee_msat || 0);
return this.filteredEventsBySelectedPeriod;
});
}
@ -163,8 +163,8 @@ export class CLNRoutingReportComponent implements OnInit, OnDestroy {
this.filteredEventsBySelectedPeriod?.map((event) => {
const monthNumber = event.received_time ? new Date((+event.received_time) * 1000).getMonth() : 12;
eventsReport[monthNumber].value = eventsReport[monthNumber].value + 1;
eventsReport[monthNumber].extra.totalFees = event.fee ? eventsReport[monthNumber].extra.totalFees + (+event.fee / 1000) : eventsReport[monthNumber].extra.totalFees;
this.totalFeeMsat = event.fee ? (this.totalFeeMsat ? this.totalFeeMsat : 0) + +event.fee : this.totalFeeMsat;
eventsReport[monthNumber].extra.totalFees = eventsReport[monthNumber].extra.totalFees + (+(event.fee || event.fee_msat || 0) / 1000);
this.totalFeeMsat = (this.totalFeeMsat || 0) + +(event.fee || event.fee_msat || 0);
return this.filteredEventsBySelectedPeriod;
});
} else {
@ -174,8 +174,8 @@ export class CLNRoutingReportComponent implements OnInit, OnDestroy {
this.filteredEventsBySelectedPeriod?.map((event) => {
const dateNumber = event.received_time ? Math.floor((+event.received_time - startDateInSeconds) / this.secondsInADay) : 0;
eventsReport[dateNumber].value = eventsReport[dateNumber].value + 1;
eventsReport[dateNumber].extra.totalFees = event.fee ? eventsReport[dateNumber].extra.totalFees + (+event.fee / 1000) : eventsReport[dateNumber].extra.totalFees;
this.totalFeeMsat = event.fee ? (this.totalFeeMsat ? this.totalFeeMsat : 0) + +event.fee : this.totalFeeMsat;
eventsReport[dateNumber].extra.totalFees = eventsReport[dateNumber].extra.totalFees + (+(event.fee || event.fee_msat || 0) / 1000);
this.totalFeeMsat = (this.totalFeeMsat || 0) + +(event.fee || event.fee_msat || 0);
return this.filteredEventsBySelectedPeriod;
});
}

@ -122,15 +122,15 @@ export class CLNTransactionsReportComponent implements OnInit, OnDestroy {
}
filteredPayments?.map((payment) => {
const monthNumber = new Date((payment.created_at || 0) * 1000).getMonth();
this.transactionsReportSummary.amountPaidSelectedPeriod = this.transactionsReportSummary.amountPaidSelectedPeriod + (payment.msatoshi_sent || 0);
transactionsReport[monthNumber].series[0].value = transactionsReport[monthNumber].series[0].value + ((payment.msatoshi_sent || 0) / 1000);
this.transactionsReportSummary.amountPaidSelectedPeriod = this.transactionsReportSummary.amountPaidSelectedPeriod + (payment.msatoshi_sent || payment.amount_sent_msat || 0);
transactionsReport[monthNumber].series[0].value = transactionsReport[monthNumber].series[0].value + ((payment.msatoshi_sent || payment.amount_sent_msat || 0) / 1000);
transactionsReport[monthNumber].series[0].extra.total = transactionsReport[monthNumber].series[0].extra.total + 1;
return this.transactionsReportSummary;
});
filteredInvoices?.map((invoice) => {
const monthNumber = new Date(+(invoice.paid_at || 0) * 1000).getMonth();
this.transactionsReportSummary.amountReceivedSelectedPeriod = this.transactionsReportSummary.amountReceivedSelectedPeriod + (invoice.msatoshi_received || 0);
transactionsReport[monthNumber].series[1].value = transactionsReport[monthNumber].series[1].value + ((invoice.msatoshi_received || 0) / 1000);
this.transactionsReportSummary.amountReceivedSelectedPeriod = this.transactionsReportSummary.amountReceivedSelectedPeriod + (invoice.msatoshi_received || invoice.amount_received_msat || 0);
transactionsReport[monthNumber].series[1].value = transactionsReport[monthNumber].series[1].value + ((invoice.msatoshi_received || invoice.amount_received_msat || 0) / 1000);
transactionsReport[monthNumber].series[1].extra.total = transactionsReport[monthNumber].series[1].extra.total + 1;
return this.transactionsReportSummary;
});
@ -140,15 +140,15 @@ export class CLNTransactionsReportComponent implements OnInit, OnDestroy {
}
filteredPayments?.map((payment) => {
const dateNumber = Math.floor((+(payment.created_at || 0) - startDateInSeconds) / this.secondsInADay);
this.transactionsReportSummary.amountPaidSelectedPeriod = this.transactionsReportSummary.amountPaidSelectedPeriod + (payment.msatoshi_sent || 0);
transactionsReport[dateNumber].series[0].value = transactionsReport[dateNumber].series[0].value + ((payment.msatoshi_sent || 0) / 1000);
this.transactionsReportSummary.amountPaidSelectedPeriod = this.transactionsReportSummary.amountPaidSelectedPeriod + (payment.msatoshi_sent || payment.amount_sent_msat || 0);
transactionsReport[dateNumber].series[0].value = transactionsReport[dateNumber].series[0].value + ((payment.msatoshi_sent || payment.amount_sent_msat || 0) / 1000);
transactionsReport[dateNumber].series[0].extra.total = transactionsReport[dateNumber].series[0].extra.total + 1;
return this.transactionsReportSummary;
});
filteredInvoices?.map((invoice) => {
const dateNumber = Math.floor((+(invoice.paid_at || 0) - startDateInSeconds) / this.secondsInADay);
this.transactionsReportSummary.amountReceivedSelectedPeriod = this.transactionsReportSummary.amountReceivedSelectedPeriod + (invoice.msatoshi_received || 0);
transactionsReport[dateNumber].series[1].value = transactionsReport[dateNumber].series[1].value + ((invoice.msatoshi_received || 0) / 1000);
this.transactionsReportSummary.amountReceivedSelectedPeriod = this.transactionsReportSummary.amountReceivedSelectedPeriod + (invoice.msatoshi_received || invoice.amount_received_msat || 0);
transactionsReport[dateNumber].series[1].value = transactionsReport[dateNumber].series[1].value + ((invoice.msatoshi_received || invoice.amount_received_msat || 0) / 1000);
transactionsReport[dateNumber].series[1].extra.total = transactionsReport[dateNumber].series[1].extra.total + 1;
return this.transactionsReportSummary;
});

@ -58,15 +58,36 @@
</ng-container>
<ng-container matColumnDef="in_msatoshi">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Amount In (Sats)</th>
<td *matCellDef="let fhEvent" mat-cell><span fxLayoutAlign="end center">{{fhEvent?.in_msatoshi/1000 | number:fhEvent?.in_msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
<td *matCellDef="let fhEvent" mat-cell>
<span *ngIf="fhEvent?.in_msatoshi" fxLayoutAlign="end center">
{{fhEvent?.in_msatoshi/1000 | number:fhEvent?.in_msatoshi < 1000 ? '1.0-4' : '1.0-0'}}
</span>
<span *ngIf="!fhEvent?.in_msatoshi && fhEvent?.in_msat" fxLayoutAlign="end center">
{{fhEvent?.in_msat/1000 | number:fhEvent?.in_msat < 1000 ? '1.0-4' : '1.0-0'}}
</span>
</td>
</ng-container>
<ng-container matColumnDef="out_msatoshi">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Amount Out (Sats)</th>
<td *matCellDef="let fhEvent" mat-cell><span fxLayoutAlign="end center">{{fhEvent?.out_msatoshi/1000 | number:fhEvent?.out_msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
<td *matCellDef="let fhEvent" mat-cell>
<span *ngIf="fhEvent?.out_msatoshi" fxLayoutAlign="end center">
{{fhEvent?.out_msatoshi/1000 | number:fhEvent?.out_msatoshi < 1000 ? '1.0-4' : '1.0-0'}}
</span>
<span *ngIf="!fhEvent?.out_msatoshi && fhEvent?.out_msat" fxLayoutAlign="end center">
{{fhEvent?.out_msat/1000 | number:fhEvent?.out_msat < 1000 ? '1.0-4' : '1.0-0'}}
</span>
</td>
</ng-container>
<ng-container matColumnDef="fee">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Fee (mSats)</th>
<td *matCellDef="let fhEvent" mat-cell><span fxLayoutAlign="end center">{{fhEvent?.fee | number:'1.0-0'}}</span></td>
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Fee (mSat)</th>
<td *matCellDef="let fhEvent" mat-cell>
<span *ngIf="fhEvent?.fee" fxLayoutAlign="end center">
{{fhEvent?.fee | number:'1.0-0'}}
</span>
<span *ngIf="!fhEvent?.fee && fhEvent?.fee_msat" fxLayoutAlign="end center">
{{fhEvent?.fee_msat | number:'1.0-0'}}
</span>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th *matHeaderCellDef mat-header-cell>

@ -107,9 +107,9 @@ export class CLNFailedTransactionsComponent implements OnInit, AfterViewInit, On
{ key: 'resolved_time', value: selFEvent.resolved_time, title: 'Resolved Time', width: 50, type: DataTypeEnum.DATE_TIME }],
[{ key: 'in_channel_alias', value: selFEvent.in_channel_alias, title: 'Inbound Channel', width: 50, type: DataTypeEnum.STRING },
{ key: 'out_channel_alias', value: selFEvent.out_channel_alias, title: 'Outbound Channel', width: 50, type: DataTypeEnum.STRING }],
[{ key: 'in_msatoshi', value: selFEvent.in_msatoshi, title: 'Amount In (mSats)', width: 33, type: DataTypeEnum.NUMBER },
{ key: 'out_msatoshi', value: selFEvent.out_msatoshi, title: 'Amount Out (mSats)', width: 33, type: DataTypeEnum.NUMBER },
{ key: 'fee', value: selFEvent.fee, title: 'Fee (mSats)', width: 34, type: DataTypeEnum.NUMBER }]
[{ key: 'in_msatoshi', value: (selFEvent.in_msatoshi || selFEvent.in_msat), title: 'Amount In (mSats)', width: 33, type: DataTypeEnum.NUMBER },
{ key: 'out_msatoshi', value: (selFEvent.out_msatoshi || selFEvent.out_msat), title: 'Amount Out (mSats)', width: 33, type: DataTypeEnum.NUMBER },
{ key: 'fee', value: (selFEvent.fee || selFEvent.fee_msat), title: 'Fee (mSats)', width: 34, type: DataTypeEnum.NUMBER }]
];
if (selFEvent.payment_hash) {
reorderedFHEvent?.unshift([{ key: 'payment_hash', value: selFEvent.payment_hash, title: 'Payment Hash', width: 100, type: DataTypeEnum.STRING }]);
@ -139,12 +139,12 @@ export class CLNFailedTransactionsComponent implements OnInit, AfterViewInit, On
let rowToFilter = '';
switch (this.selFilterBy) {
case 'all':
rowToFilter = (rowData.received_time ? this.datePipe.transform(new Date(rowData.received_time * 1000), 'dd/MMM/YYYY HH:mm')!.toLowerCase() : '') +
(rowData.resolved_time ? this.datePipe.transform(new Date(rowData.resolved_time * 1000), 'dd/MMM/y HH:mm')?.toLowerCase() : '') +
(rowData.payment_hash ? rowData.payment_hash.toLowerCase() : '') +
(rowData.in_channel ? rowData.in_channel.toLowerCase() : '') + (rowData.out_channel ? rowData.out_channel.toLowerCase() : '') +
(rowData.in_channel_alias ? rowData.in_channel_alias.toLowerCase() : '') + (rowData.out_channel_alias ? rowData.out_channel_alias.toLowerCase() : '') +
(rowData.in_msatoshi ? (rowData.in_msatoshi / 1000) : '') + (rowData.out_msatoshi ? (rowData.out_msatoshi / 1000) : '') + (rowData.fee ? rowData.fee : '');
rowToFilter = (rowData.received_time ? this.datePipe.transform(new Date(rowData.received_time * 1000), 'dd/MMM/y HH:mm')?.toLowerCase() + ' ' : '') +
(rowData.resolved_time ? this.datePipe.transform(new Date(rowData.resolved_time * 1000), 'dd/MMM/y HH:mm')?.toLowerCase() + ' ' : '') +
(rowData.in_channel ? rowData.in_channel.toLowerCase() + ' ' : '') + (rowData.out_channel ? rowData.out_channel.toLowerCase() + ' ' : '') +
(rowData.in_channel_alias ? rowData.in_channel_alias.toLowerCase() + ' ' : '') + (rowData.out_channel_alias ? rowData.out_channel_alias.toLowerCase() + ' ' : '') +
(rowData.in_msatoshi ? (rowData.in_msatoshi / 1000) + ' ' : '') + (rowData.out_msatoshi ? (rowData.out_msatoshi / 1000) + ' ' : '') + (rowData.fee ? rowData.fee + ' ' : '') +
(rowData.in_msat ? (+rowData.in_msat / 1000) + ' ' : '') + (rowData.out_msat ? (+rowData.out_msat / 1000) + ' ' : '') + (rowData.fee_msat ? rowData.fee_msat + ' ' : '');
break;
case 'received_time':
@ -152,9 +152,16 @@ export class CLNFailedTransactionsComponent implements OnInit, AfterViewInit, On
rowToFilter = this.datePipe.transform(new Date((rowData[this.selFilterBy] || 0) * 1000), 'dd/MMM/y HH:mm')?.toLowerCase() || '';
break;
case 'fee':
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['fee_msat'] || 0)))?.toString() || '';
break;
case 'in_msatoshi':
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['in_msat'] || 0)) / 1000)?.toString() || '';
break;
case 'out_msatoshi':
rowToFilter = ((+(rowData[this.selFilterBy] || 0)) / 1000)?.toString() || '';
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['out_msat'] || 0)) / 1000)?.toString() || '';
break;
default:
@ -168,7 +175,21 @@ export class CLNFailedTransactionsComponent implements OnInit, AfterViewInit, On
loadFailedEventsTable(forwardingEvents: ForwardingEvent[]) {
this.failedForwardingEvents = new MatTableDataSource<ForwardingEvent>([...forwardingEvents]);
this.failedForwardingEvents.sort = this.sort;
this.failedForwardingEvents.sortingDataAccessor = (data: any, sortHeaderId: string) => ((data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null);
this.failedForwardingEvents.sortingDataAccessor = (data: any, sortHeaderId: string) => {
switch (sortHeaderId) {
case 'in_msatoshi':
return data['in_msatoshi'] || data['in_msat'];
case 'out_msatoshi':
return data['out_msatoshi'] || data['out_msat'];
case 'fee':
return data['fee'] || data['fee_msat'];
default:
return (data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null;
}
};
this.failedForwardingEvents.paginator = this.paginator;
this.setFilterPredicate();
this.applyFilter();

@ -60,15 +60,36 @@
</ng-container>
<ng-container matColumnDef="in_msatoshi">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Amount In (Sats)</th>
<td *matCellDef="let fhEvent" mat-cell><span fxLayoutAlign="end center">{{fhEvent?.in_msatoshi/1000 | number:fhEvent?.in_msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
<td *matCellDef="let fhEvent" mat-cell>
<span *ngIf="fhEvent?.in_msatoshi" fxLayoutAlign="end center">
{{fhEvent?.in_msatoshi/1000 | number:fhEvent?.in_msatoshi < 1000 ? '1.0-4' : '1.0-0'}}
</span>
<span *ngIf="!fhEvent?.in_msatoshi && fhEvent?.in_msat" fxLayoutAlign="end center">
{{fhEvent?.in_msat/1000 | number:fhEvent?.in_msat < 1000 ? '1.0-4' : '1.0-0'}}
</span>
</td>
</ng-container>
<ng-container matColumnDef="out_msatoshi">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Amount Out (Sats)</th>
<td *matCellDef="let fhEvent" mat-cell><span fxLayoutAlign="end center">{{fhEvent?.out_msatoshi/1000 | number:fhEvent?.out_msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
<td *matCellDef="let fhEvent" mat-cell>
<span *ngIf="fhEvent?.out_msatoshi" fxLayoutAlign="end center">
{{fhEvent?.out_msatoshi/1000 | number:fhEvent?.out_msatoshi < 1000 ? '1.0-4' : '1.0-0'}}
</span>
<span *ngIf="!fhEvent?.out_msatoshi && fhEvent?.out_msat" fxLayoutAlign="end center">
{{fhEvent?.out_msat/1000 | number:fhEvent?.out_msat < 1000 ? '1.0-4' : '1.0-0'}}
</span>
</td>
</ng-container>
<ng-container matColumnDef="fee">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Fee (mSat)</th>
<td *matCellDef="let fhEvent" mat-cell><span fxLayoutAlign="end center">{{fhEvent?.fee | number}}</span></td>
<td *matCellDef="let fhEvent" mat-cell>
<span *ngIf="fhEvent?.fee" fxLayoutAlign="end center">
{{fhEvent?.fee | number}}
</span>
<span *ngIf="!fhEvent?.fee && fhEvent?.fee_msat" fxLayoutAlign="end center">
{{fhEvent?.fee_msat | number}}
</span>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th *matHeaderCellDef mat-header-cell>

@ -129,16 +129,18 @@ export class CLNForwardingHistoryComponent implements OnInit, OnChanges, AfterVi
onForwardingEventClick(selFEvent: ForwardingEvent, event: any) {
const reorderedFHEvent = [
[{ key: 'payment_hash', value: selFEvent.payment_hash, title: 'Payment Hash', width: 100, type: DataTypeEnum.STRING }],
[{ key: 'status', value: 'Settled', title: 'Status', width: 50, type: DataTypeEnum.STRING },
{ key: 'fee', value: selFEvent.fee, title: 'Fee (mSats)', width: 50, type: DataTypeEnum.NUMBER }],
{ key: 'fee', value: (selFEvent.fee || selFEvent.fee_msat), title: 'Fee (mSats)', width: 50, type: DataTypeEnum.NUMBER }],
[{ key: 'received_time', value: selFEvent.received_time, title: 'Received Time', width: 50, type: DataTypeEnum.DATE_TIME },
{ key: 'resolved_time', value: selFEvent.resolved_time, title: 'Resolved Time', width: 50, type: DataTypeEnum.DATE_TIME }],
[{ key: 'in_channel', value: selFEvent.in_channel_alias, title: 'Inbound Channel', width: 50, type: DataTypeEnum.STRING },
{ key: 'out_channel', value: selFEvent.out_channel_alias, title: 'Outbound Channel', width: 50, type: DataTypeEnum.STRING }],
[{ key: 'in_msatoshi', value: selFEvent.in_msatoshi, title: 'In (mSats)', width: 50, type: DataTypeEnum.NUMBER },
{ key: 'out_msatoshi', value: selFEvent.out_msatoshi, title: 'Out (mSats)', width: 50, type: DataTypeEnum.NUMBER }]
[{ key: 'in_msatoshi', value: (selFEvent.in_msatoshi || selFEvent.in_msat), title: 'In (mSats)', width: 50, type: DataTypeEnum.NUMBER },
{ key: 'out_msatoshi', value: (selFEvent.out_msatoshi || selFEvent.out_msat), title: 'Out (mSats)', width: 50, type: DataTypeEnum.NUMBER }]
];
if (selFEvent.payment_hash) {
reorderedFHEvent.unshift([{ key: 'payment_hash', value: selFEvent.payment_hash, title: 'Payment Hash', width: 100, type: DataTypeEnum.STRING }]);
}
this.store.dispatch(openAlert({
payload: {
data: {
@ -170,7 +172,8 @@ export class CLNForwardingHistoryComponent implements OnInit, OnChanges, AfterVi
(rowData.resolved_time ? this.datePipe.transform(new Date(rowData.resolved_time * 1000), 'dd/MMM/y HH:mm')?.toLowerCase() + ' ' : '') +
(rowData.in_channel ? rowData.in_channel.toLowerCase() + ' ' : '') + (rowData.out_channel ? rowData.out_channel.toLowerCase() + ' ' : '') +
(rowData.in_channel_alias ? rowData.in_channel_alias.toLowerCase() + ' ' : '') + (rowData.out_channel_alias ? rowData.out_channel_alias.toLowerCase() + ' ' : '') +
(rowData.in_msatoshi ? (rowData.in_msatoshi / 1000) + ' ' : '') + (rowData.out_msatoshi ? (rowData.out_msatoshi / 1000) + ' ' : '') + (rowData.fee ? rowData.fee + ' ' : '');
(rowData.in_msatoshi ? (rowData.in_msatoshi / 1000) + ' ' : '') + (rowData.out_msatoshi ? (rowData.out_msatoshi / 1000) + ' ' : '') + (rowData.fee ? rowData.fee + ' ' : '') +
(rowData.in_msat ? (+rowData.in_msat / 1000) + ' ' : '') + (rowData.out_msat ? (+rowData.out_msat / 1000) + ' ' : '') + (rowData.fee_msat ? rowData.fee_msat + ' ' : '');
break;
case 'received_time':
@ -178,9 +181,16 @@ export class CLNForwardingHistoryComponent implements OnInit, OnChanges, AfterVi
rowToFilter = this.datePipe.transform(new Date((rowData[this.selFilterBy] || 0) * 1000), 'dd/MMM/y HH:mm')?.toLowerCase() || '';
break;
case 'fee':
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['fee_msat'] || 0)))?.toString() || '';
break;
case 'in_msatoshi':
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['in_msat'] || 0)) / 1000)?.toString() || '';
break;
case 'out_msatoshi':
rowToFilter = ((+(rowData[this.selFilterBy] || 0)) / 1000)?.toString() || '';
rowToFilter = ((+(rowData[this.selFilterBy] || rowData['out_msat'] || 0)) / 1000)?.toString() || '';
break;
default:
@ -194,7 +204,21 @@ export class CLNForwardingHistoryComponent implements OnInit, OnChanges, AfterVi
loadForwardingEventsTable(forwardingEvents: ForwardingEvent[]) {
this.forwardingHistoryEvents = new MatTableDataSource<ForwardingEvent>([...forwardingEvents]);
this.forwardingHistoryEvents.sort = this.sort;
this.forwardingHistoryEvents.sortingDataAccessor = (data: any, sortHeaderId: string) => ((data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null);
this.forwardingHistoryEvents.sortingDataAccessor = (data: any, sortHeaderId: string) => {
switch (sortHeaderId) {
case 'in_msatoshi':
return data['in_msatoshi'] || data['in_msat'];
case 'out_msatoshi':
return data['out_msatoshi'] || data['out_msat'];
case 'fee':
return data['fee'] || data['fee_msat'];
default:
return (data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null;
}
};
this.forwardingHistoryEvents.paginator = this.paginator;
this.setFilterPredicate();
this.applyFilter();

@ -54,7 +54,14 @@
</ng-container>
<ng-container matColumnDef="in_msatoshi">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Amount In (Sats)</th>
<td *matCellDef="let fhEvent" mat-cell><span fxLayoutAlign="end center">{{fhEvent?.in_msatoshi/1000 | number:fhEvent?.in_msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
<td *matCellDef="let fhEvent" mat-cell>
<span *ngIf="fhEvent?.in_msatoshi" fxLayoutAlign="end center">
{{fhEvent?.in_msatoshi/1000 | number:fhEvent?.in_msatoshi < 1000 ? '1.0-4' : '1.0-0'}}
</span>
<span *ngIf="!fhEvent?.in_msatoshi && fhEvent?.in_msat" fxLayoutAlign="end center">
{{fhEvent?.in_msat/1000 | number:fhEvent?.in_msat < 1000 ? '1.0-4' : '1.0-0'}}
</span>
</td>
</ng-container>
<ng-container matColumnDef="style">
<th *matHeaderCellDef mat-header-cell mat-sort-header>Style</th>

@ -106,7 +106,7 @@ export class CLNLocalFailedTransactionsComponent implements OnInit, AfterViewIni
const reorderedFHEvent = [
[{ key: 'received_time', value: selFEvent.received_time, title: 'Received Time', width: 50, type: DataTypeEnum.DATE_TIME },
{ key: 'in_channel_alias', value: selFEvent.in_channel_alias, title: 'Inbound Channel', width: 50, type: DataTypeEnum.STRING }],
[{ key: 'in_msatoshi', value: selFEvent.in_msatoshi, title: 'Amount In (mSats)', width: 100, type: DataTypeEnum.NUMBER }],
[{ key: 'in_msatoshi', value: (selFEvent.in_msatoshi || selFEvent.in_msat), title: 'Amount In (mSats)', width: 100, type: DataTypeEnum.NUMBER }],
[{ key: 'failreason', value: selFEvent.failreason ? this.CLNFailReason[selFEvent.failreason] : '', title: 'Reason for Failure', width: 100, type: DataTypeEnum.STRING }]
];
this.store.dispatch(openAlert({
@ -137,7 +137,7 @@ export class CLNLocalFailedTransactionsComponent implements OnInit, AfterViewIni
rowToFilter = (rowData.received_time ? this.datePipe.transform(new Date(rowData.received_time * 1000), 'dd/MMM/y HH:mm')?.toLowerCase() : '') +
(rowData.in_channel_alias ? rowData.in_channel_alias.toLowerCase() : '') +
((rowData.failreason && this.CLNFailReason[rowData.failreason]) ? this.CLNFailReason[rowData.failreason].toLowerCase() : '') +
(rowData.in_msatoshi ? (rowData.in_msatoshi / 1000) : '');
(rowData.in_msatoshi ? (rowData.in_msatoshi / 1000) : '') + (rowData.in_msat ? rowData.in_msat : '');
break;
case 'received_time':
@ -145,7 +145,7 @@ export class CLNLocalFailedTransactionsComponent implements OnInit, AfterViewIni
break;
case 'in_msatoshi':
rowToFilter = ((+(rowData.in_msatoshi || 0)) / 1000)?.toString() || '';
rowToFilter = ((rowData['in_msatoshi'] || +(rowData['in_msat'] || 0)) / 1000)?.toString() || '';
break;
case 'failreason':
@ -165,6 +165,9 @@ export class CLNLocalFailedTransactionsComponent implements OnInit, AfterViewIni
this.failedLocalForwardingEvents.sort = this.sort;
this.failedLocalForwardingEvents.sortingDataAccessor = (data: LocalFailedEvent, sortHeaderId: string) => {
switch (sortHeaderId) {
case 'in_msatoshi':
return data['in_msatoshi'] || data['in_msat'];
case 'failreason':
return data.failreason ? this.CLNFailReason[data.failreason] : '';

@ -5,16 +5,6 @@
<div fxLayout="column" fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch" class="page-sub-title-container w-100" [ngClass]="{'mt-2': screenSize === screenSizeEnum.XS, 'mt-1': screenSize === screenSizeEnum.SM}">
<div fxFlex="70">Incoming</div>
<div fxFlex.gt-xs="30" fxLayoutAlign.gt-xs="space-between center" fxLayout="row" fxLayoutAlign="space-between stretch">
<!-- <mat-form-field fxLayout="column" fxFlex="49">
<mat-label>Filter By</mat-label>
<mat-select tabindex="1" [(ngModel)]="selFilterByIn" (selectionChange)="selFilterIn=''; applyIncomingFilter()" name="filterByIn">
<perfect-scrollbar><mat-option *ngFor="let column of ['all'].concat(displayedColumns.slice(0, -1))" [value]="column">{{getLabel(column)}}</mat-option></perfect-scrollbar>
</mat-select>
</mat-form-field>
<mat-form-field fxLayout="column" fxFlex="49">
<mat-label>Filter</mat-label>
<input matInput [(ngModel)]="selFilterIn" (input)="applyIncomingFilter()" (keyup)="applyIncomingFilter()" name="filterin">
</mat-form-field> -->
</div>
</div>
<div fxLayout="column" fxLayoutAlign="start stretch" fxFlex="100" class="table-container" [perfectScrollbar]>

@ -132,29 +132,6 @@ export class CLNRoutingPeersComponent implements OnInit, OnChanges, AfterViewIni
setFilterPredicate() {
this.routingPeersIncoming.filterPredicate = (rpIn: RoutingPeer, fltr: string) => JSON.stringify(rpIn).toLowerCase().includes(fltr);
this.routingPeersOutgoing.filterPredicate = (rpOut: RoutingPeer, fltr: string) => JSON.stringify(rpOut).toLowerCase().includes(fltr);
// this.routingPeersIncoming.filterPredicate = (rowData: RoutingPeer, fltr: string) => {
// let rowToFilter = '';
// switch (this.selFilterBy) {
// case 'all':
// for (let i = 0; i < this.displayedColumns.length - 1; i++) {
// rowToFilter = rowToFilter + (
// (this.displayedColumns[i] === '') ?
// (rowData ? rowData..toLowerCase() : '') :
// (rowData[this.displayedColumns[i]] ? rowData[this.displayedColumns[i]].toLowerCase() : '')
// ) + ', ';
// }
// break;
// case '':
// rowToFilter = (rowData ? rowData..toLowerCase() : '');
// break;
// default:
// rowToFilter = (rowData[this.selFilterBy] ? rowData[this.selFilterBy].toLowerCase() : '');
// break;
// }
// return rowToFilter.includes(fltr);
// };
}
loadRoutingPeersTable(events: ForwardingEvent[]) {
@ -187,18 +164,18 @@ export class CLNRoutingPeersComponent implements OnInit, OnChanges, AfterViewIni
const incoming: any = incomingResults?.find((result) => result.channel_id === event.in_channel);
const outgoing: any = outgoingResults?.find((result) => result.channel_id === event.out_channel);
if (!incoming) {
incomingResults.push({ channel_id: event.in_channel, alias: event.in_channel_alias, events: 1, total_amount: event.in_msatoshi, total_fee: ((event.in_msatoshi || 0) - (event.out_msatoshi || 0)) });
incomingResults.push({ channel_id: event.in_channel, alias: event.in_channel_alias, events: 1, total_amount: (event.in_msatoshi || +(event.in_msat || 0)), total_fee: ((event.in_msatoshi || +(event.in_msat || 0)) - (event.out_msatoshi || +(event.out_msat || 0))) });
} else {
incoming.events++;
incoming.total_amount = +incoming.total_amount + +(event.in_msatoshi || 0);
incoming.total_fee = +incoming.total_fee + ((event.in_msatoshi || 0) - (event.out_msatoshi || 0));
incoming.total_amount = +incoming.total_amount + +(event.in_msatoshi || event.in_msat || 0);
incoming.total_fee = +incoming.total_fee + ((event.in_msatoshi || +(event.in_msat || 0)) - (event.out_msatoshi || +(event.out_msat || 0)));
}
if (!outgoing) {
outgoingResults.push({ channel_id: event.out_channel, alias: event.out_channel_alias, events: 1, total_amount: event.out_msatoshi, total_fee: ((event.in_msatoshi || 0) - (event.out_msatoshi || 0)) });
outgoingResults.push({ channel_id: event.out_channel, alias: event.out_channel_alias, events: 1, total_amount: (event.out_msatoshi || +(event.out_msat || 0)), total_fee: ((event.in_msatoshi || +(event.in_msat || 0)) - (event.out_msatoshi || +(event.out_msat || 0))) });
} else {
outgoing.events++;
outgoing.total_amount = +outgoing.total_amount + +(event.out_msatoshi || 0);
outgoing.total_fee = +outgoing.total_fee + ((event.in_msatoshi || 0) - (event.out_msatoshi || 0));
outgoing.total_amount = +outgoing.total_amount + +(event.out_msatoshi || event.out_msat || 0);
outgoing.total_fee = +outgoing.total_fee + ((event.in_msatoshi || +(event.in_msat || 0)) - (event.out_msatoshi || +(event.out_msat || 0)));
}
});
return [this.commonService.sortDescByKey(incomingResults, 'total_fee'), this.commonService.sortDescByKey(outgoingResults, 'total_fee')];

@ -326,14 +326,21 @@ export class CLNEffects implements OnDestroy {
ofType(CLNActions.FETCH_CHANNELS_CLN),
mergeMap(() => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchChannels', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get<Channel[]>(this.CHILD_API_URL + API_END_POINTS.CHANNELS_API + '/listChannels');
return this.httpClient.get<Channel[]>(this.CHILD_API_URL + API_END_POINTS.CHANNELS_API + '/listPeerChannels');
}),
map((channels: Channel[]) => {
this.logger.info(channels);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchChannels', status: APICallStatusEnum.COMPLETED } }));
// this.store.dispatch(getForwardingHistory({ payload: { status: CLNForwardingEventsStatusEnum.SETTLED } }));
const sortedChannels = { activeChannels: <Channel[]>[], pendingChannels: <Channel[]>[], inactiveChannels: <Channel[]>[] };
channels.forEach((channel) => {
if (channel.id) { channel.peer_id = channel.id; }
if (channel.connected) { channel.peer_connected = channel.connected; }
if (channel.msatoshi_to_us) { channel.to_us_msat = channel.msatoshi_to_us; }
if (channel.msatoshi_to_them) { channel.to_them_msat = channel.msatoshi_to_them; }
if (channel.msatoshi_total) { channel.total_msat = channel.msatoshi_total; }
if (channel.their_channel_reserve_satoshis) { channel.their_reserve_msat = +channel.their_channel_reserve_satoshis; }
if (channel.our_channel_reserve_satoshis) { channel.our_reserve_msat = +channel.our_channel_reserve_satoshis; }
if (channel.spendable_msatoshi) { channel.spendable_msat = +channel.spendable_msatoshi; }
if (channel.state === 'CHANNELD_NORMAL') {
if (channel.peer_connected) {
sortedChannels.activeChannels.push(channel);
@ -722,6 +729,7 @@ export class CLNEffects implements OnDestroy {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SaveNewInvoice', status: APICallStatusEnum.COMPLETED } }));
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.ADD_INVOICE }));
postRes.msatoshi = action.payload.amount;
postRes.amount_msat = action.payload.amount;
postRes.label = action.payload.label;
postRes.expires_at = Math.round((new Date().getTime() / 1000) + action.payload.expiry);
postRes.description = action.payload.description;
@ -926,6 +934,11 @@ export class CLNEffects implements OnDestroy {
map((utxos: any) => {
this.logger.info(utxos);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'FetchUTXOs', status: APICallStatusEnum.COMPLETED } }));
utxos.outputs.forEach((output) => { // For backward compatibility
if (output.value) {
output.amount_msat = output.value;
}
});
return {
type: CLNActions.SET_UTXOS_CLN,
payload: utxos.outputs || []

@ -99,7 +99,7 @@ export class CLNCreateInvoiceComponent implements OnInit, OnDestroy {
pipe(takeUntil(this.unSubs[3])).
subscribe({
next: (data) => {
this.invoiceValueHint = '= ' + data.symbol + this.decimalPipe.transform(data.OTHER, CURRENCY_UNIT_FORMATS.OTHER) + ' ' + data.unit;
this.invoiceValueHint = '= ' + this.decimalPipe.transform(data.OTHER, CURRENCY_UNIT_FORMATS.OTHER) + ' ' + data.unit;
}, error: (err) => {
this.invoiceValueHint = 'Conversion Error: ' + err;
}

@ -33,7 +33,7 @@
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">{{screenSize === screenSizeEnum.XS ? 'Amount' : 'Amount Requested'}}</h4>
<span class="foreground-secondary-text">
{{(invoice?.msatoshi/1000 || 0) | number}} Sats<ng-container *ngIf="!invoice?.msatoshi || invoice?.msatoshi === '0'"> (zero amount) </ng-container>
{{(invoice?.amount_msat/1000 || 0) | number}} Sats<ng-container *ngIf="!invoice?.amount_msat || invoice?.amount_msat === '0'"> (zero amount) </ng-container>
</span>
</div>
<div fxFlex="50">
@ -42,11 +42,11 @@
<ng-container *ngIf="invoice?.status === 'paid'">
<div *ngIf="flgInvoicePaid" class="invoice-animation-container">
<div class="invoice-animation-div">
<span class="wiggle">{{invoice?.msatoshi_received/1000 | number}} Sats</span>
<span class="wiggle">{{invoice?.amount_received_msat/1000 | number}} Sats</span>
<span *ngFor="let i of [].constructor(35)" class="particles-circle"></span>
</div>
</div>
<div *ngIf="!flgInvoicePaid">{{invoice?.msatoshi_received/1000 | number}} Sats</div>
<div *ngIf="!flgInvoicePaid">{{invoice?.amount_received_msat/1000 | number}} Sats</div>
</ng-container>
<ng-container *ngIf="invoice?.status !== 'paid'">
<span *ngIf="invoice?.status !== 'unpaid' || !flgVersionCompatible">-</span>

@ -97,11 +97,11 @@
</ng-container>
<ng-container matColumnDef="msatoshi">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Amount (Sats)</th>
<td *matCellDef="let invoice" mat-cell><span fxLayoutAlign="end center">{{invoice?.msatoshi/1000 | number:invoice?.msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
<td *matCellDef="let invoice" mat-cell><span fxLayoutAlign="end center">{{invoice?.amount_msat/1000 | number:invoice?.amount_msat < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
</ng-container>
<ng-container matColumnDef="msatoshi_received">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Amount Settled (Sats)</th>
<td *matCellDef="let invoice" mat-cell><span fxLayoutAlign="end center">{{invoice?.msatoshi_received/1000 | number:invoice?.msatoshi_received < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
<td *matCellDef="let invoice" mat-cell><span fxLayoutAlign="end center">{{invoice?.amount_received_msat/1000 | number:invoice?.amount_received_msat < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
</ng-container>
<ng-container matColumnDef="actions">
<th *matHeaderCellDef mat-header-cell>

@ -175,7 +175,7 @@ export class CLNLightningInvoicesTableComponent implements OnInit, AfterViewInit
onInvoiceClick(selInvoice: Invoice) {
const reCreatedInvoice: Invoice = {
msatoshi: selInvoice.msatoshi,
amount_msat: selInvoice.amount_msat,
label: selInvoice.label,
expires_at: selInvoice.expires_at,
paid_at: selInvoice.paid_at,
@ -183,7 +183,7 @@ export class CLNLightningInvoicesTableComponent implements OnInit, AfterViewInit
payment_hash: selInvoice.payment_hash,
description: selInvoice.description,
status: selInvoice.status,
msatoshi_received: selInvoice.msatoshi_received
amount_received_msat: selInvoice.amount_received_msat
};
this.store.dispatch(openAlert({
payload: {
@ -237,8 +237,11 @@ export class CLNLightningInvoicesTableComponent implements OnInit, AfterViewInit
break;
case 'msatoshi':
rowToFilter = ((rowData['msatoshi'] || rowData['amount_msat'] || 0) / 1000)?.toString() || '';
break;
case 'msatoshi_received':
rowToFilter = ((+(rowData[this.selFilterBy] || 0)) / 1000)?.toString() || '';
rowToFilter = ((rowData['msatoshi_received'] || rowData['amount_received_msat'] || 0) / 1000)?.toString() || '';
break;
default:
@ -256,7 +259,7 @@ export class CLNLightningInvoicesTableComponent implements OnInit, AfterViewInit
pipe(takeUntil(this.unSubs[6])).
subscribe({
next: (data) => {
this.invoiceValueHint = '= ' + data.symbol + this.decimalPipe.transform(data.OTHER, CURRENCY_UNIT_FORMATS.OTHER) + ' ' + data.unit;
this.invoiceValueHint = '= ' + this.decimalPipe.transform(data.OTHER, CURRENCY_UNIT_FORMATS.OTHER) + ' ' + data.unit;
}, error: (err) => {
this.invoiceValueHint = 'Conversion Error: ' + err;
}
@ -275,7 +278,18 @@ export class CLNLightningInvoicesTableComponent implements OnInit, AfterViewInit
loadInvoicesTable(invs: Invoice[]) {
this.invoices = (invs) ? new MatTableDataSource<Invoice>([...invs]) : new MatTableDataSource([]);
this.invoices.sort = this.sort;
this.invoices.sortingDataAccessor = (data: any, sortHeaderId: string) => ((data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null);
this.invoices.sortingDataAccessor = (data: any, sortHeaderId: string) => {
switch (sortHeaderId) {
case 'msatoshi':
return data['msatoshi'] || data['amount_msat'];
case 'msatoshi_received':
return data['msatoshi_received'] || data['amount_received_msat'];
default:
return (data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null;
}
};
this.invoices.paginator = this.paginator;
this.applyFilter();
this.setFilterPredicate();

@ -82,7 +82,7 @@ export class CLNCreateOfferComponent implements OnInit, OnDestroy {
pipe(takeUntil(this.unSubs[3])).
subscribe({
next: (data) => {
this.offerValueHint = '= ' + data.symbol + this.decimalPipe.transform(data.OTHER, CURRENCY_UNIT_FORMATS.OTHER) + ' ' + data.unit;
this.offerValueHint = '= ' + this.decimalPipe.transform(data.OTHER, CURRENCY_UNIT_FORMATS.OTHER) + ' ' + data.unit;
}, error: (err) => {
this.offerValueHint = 'Conversion Error: ' + err;
}

@ -22,7 +22,7 @@
<div fxFlex="50">
<h4 fxLayoutAlign="start" class="font-bold-500">Amount Requested (Sats)</h4>
<span class="foreground-secondary-text">
{{ !offerDecoded?.offer_amount_msat || offerDecoded?.offer_amount === 0 ? 'Open Offer' : ((offerDecoded?.offer_amount / 1000) | number) }}
{{ !offerDecoded?.offer_amount_msat || offerDecoded?.offer_amount_msat === 0 ? 'Open Offer' : (((offerDecoded?.offer_amount || offerDecoded?.offer_amount_msat) / 1000) | number) }}
</span>
</div>
<div fxFlex="50">

@ -47,10 +47,10 @@ export class CLNOfferInformationComponent implements OnInit, OnDestroy {
pipe(takeUntil(this.unSubs[1])).subscribe((decodedOffer: OfferRequest) => {
this.offerDecoded = decodedOffer;
if (this.offerDecoded.offer_id && !this.offerDecoded.offer_amount_msat) {
this.offerDecoded.offer_amount_msat = '0msat';
this.offerDecoded.offer_amount_msat = 0;
this.offerDecoded.offer_amount = 0;
} else {
this.offerDecoded.offer_amount = this.offerDecoded.offer_amount ? +this.offerDecoded.offer_amount : this.offerDecoded.offer_amount_msat ? +this.offerDecoded.offer_amount_msat.slice(0, -4) : null;
this.offerDecoded.offer_amount = this.offerDecoded.offer_amount || this.offerDecoded.offer_amount_msat || null;
}
});
}

@ -180,10 +180,10 @@ export class CLNOffersTableComponent implements OnInit, AfterViewInit, OnDestroy
this.dataService.decodePayment(selOffer.bolt12!, false).
pipe(take(1)).subscribe((offerDecoded: OfferRequest) => {
if (offerDecoded.offer_id && !offerDecoded.offer_amount_msat) {
offerDecoded.offer_amount_msat = '0msat';
offerDecoded.offer_amount_msat = 0;
offerDecoded.offer_amount = 0;
} else {
offerDecoded.offer_amount = offerDecoded.offer_amount ? +offerDecoded.offer_amount : offerDecoded.offer_amount_msat ? +offerDecoded.offer_amount_msat.slice(0, -4) : null;
offerDecoded.offer_amount = offerDecoded.offer_amount || offerDecoded.offer_amount_msat || null;
}
const documentDefinition = {
pageSize: 'A5',

@ -96,11 +96,11 @@
</ng-container>
<ng-container matColumnDef="msatoshi_sent">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Sats Sent</th>
<td *matCellDef="let payment" mat-cell><span fxLayoutAlign="end center">{{payment?.msatoshi_sent/1000 | number:payment?.msatoshi_sent < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
<td *matCellDef="let payment" mat-cell><span fxLayoutAlign="end center">{{payment?.amount_sent_msat/1000 | number:payment?.amount_sent_msat < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
</ng-container>
<ng-container matColumnDef="msatoshi">
<th *matHeaderCellDef mat-header-cell mat-sort-header arrowPosition="before">Sats Received</th>
<td *matCellDef="let payment" mat-cell><span fxLayoutAlign="end center">{{payment?.msatoshi/1000 | number:payment?.msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
<td *matCellDef="let payment" mat-cell><span fxLayoutAlign="end center">{{payment?.amount_msat/1000 | number:payment?.amount_msat < 1000 ? '1.0-4' : '1.0-0'}}</span></td>
</ng-container>
<ng-container matColumnDef="actions">
<th *matHeaderCellDef mat-header-cell>
@ -218,20 +218,20 @@
</ng-container>
<ng-container matColumnDef="group_msatoshi_sent">
<td *matCellDef="let payment" mat-cell>
<span fxLayoutAlign="end center" class="mpp-row-span">{{payment?.msatoshi_sent/1000 | number:payment?.msatoshi_sent < 1000 ? '1.0-4' : '1.0-0'}}</span>
<span fxLayoutAlign="end center" class="mpp-row-span">{{payment?.amount_sent_msat/1000 | number:payment?.amount_sent_msat < 1000 ? '1.0-4' : '1.0-0'}}</span>
<span *ngIf="payment.is_expanded">
<span *ngFor="let mpp of payment?.mpps" fxLayoutAlign="end center" class="mpp-row-span">
{{mpp.msatoshi_sent/1000 | number:mpp.msatoshi_sent < 1000 ? '1.0-4' : '1.0-0'}}
{{mpp.amount_sent_msat/1000 | number:mpp.amount_sent_msat < 1000 ? '1.0-4' : '1.0-0'}}
</span>
</span>
</td>
</ng-container>
<ng-container matColumnDef="group_msatoshi">
<td *matCellDef="let payment" mat-cell>
<span fxLayoutAlign="end center" class="mpp-row-span">{{payment?.msatoshi/1000 | number:payment?.msatoshi < 1000 ? '1.0-4' : '1.0-0'}}</span>
<span fxLayoutAlign="end center" class="mpp-row-span">{{payment?.amount_msat/1000 | number:payment?.amount_msat < 1000 ? '1.0-4' : '1.0-0'}}</span>
<span *ngIf="payment.is_expanded">
<span *ngFor="let mpp of payment?.mpps" fxLayoutAlign="end center" class="mpp-row-span">
{{mpp.msatoshi/1000 | number:mpp.msatoshi < 1000 ? '1.0-4' : '1.0-0'}}
{{mpp.amount_msat/1000 | number:mpp.amount_msat < 1000 ? '1.0-4' : '1.0-0'}}
</span>
</span>
</td>

@ -147,8 +147,8 @@ export class CLNLightningPaymentsComponent implements OnInit, AfterViewInit, OnD
pipe(takeUntil(this.unSubs[4])).subscribe((decodedPayment: PayRequest) => {
this.paymentDecoded = decodedPayment;
if (this.paymentDecoded.created_at) {
if (!this.paymentDecoded.msatoshi) {
this.paymentDecoded.msatoshi = 0;
if (!this.paymentDecoded.amount_msat) {
this.paymentDecoded.amount_msat = 0;
}
this.sendPayment();
} else {
@ -160,7 +160,7 @@ export class CLNLightningPaymentsComponent implements OnInit, AfterViewInit, OnD
sendPayment() {
this.newlyAddedPayment = this.paymentDecoded?.payment_hash || '';
if (!this.paymentDecoded.msatoshi || this.paymentDecoded.msatoshi === 0) {
if (!this.paymentDecoded.amount_msat || this.paymentDecoded.amount_msat === 0) {
const reorderedPaymentDecoded = [
[{ key: 'payment_hash', value: this.paymentDecoded.payment_hash, title: 'Payment Hash', width: 100 }],
[{ key: 'payee', value: this.paymentDecoded.payee, title: 'Payee', width: 100 }],
@ -190,7 +190,7 @@ export class CLNLightningPaymentsComponent implements OnInit, AfterViewInit, OnD
pipe(take(1)).
subscribe((confirmRes) => {
if (confirmRes) {
this.paymentDecoded.msatoshi = confirmRes[0].inputValue;
this.paymentDecoded.amount_msat = confirmRes[0].inputValue;
this.store.dispatch(sendPayment({ payload: { uiMessage: UI_MESSAGES.SEND_PAYMENT, paymentType: PaymentTypes.INVOICE, invoice: this.paymentRequest, amount: confirmRes[0].inputValue * 1000, fromDialog: false } }));
this.resetData();
}
@ -201,7 +201,7 @@ export class CLNLightningPaymentsComponent implements OnInit, AfterViewInit, OnD
[{ key: 'payee', value: this.paymentDecoded.payee, title: 'Payee', width: 100 }],
[{ key: 'description', value: this.paymentDecoded.description, title: 'Description', width: 100 }],
[{ key: 'created_at', value: this.paymentDecoded.created_at, title: 'Creation Date', width: 50, type: DataTypeEnum.DATE_TIME },
{ key: 'num_satoshis', value: this.paymentDecoded.msatoshi / 1000, title: 'Amount (Sats)', width: 50, type: DataTypeEnum.NUMBER }],
{ key: 'num_satoshis', value: this.paymentDecoded.amount_msat / 1000, title: 'Amount (Sats)', width: 50, type: DataTypeEnum.NUMBER }],
[{ key: 'expiry', value: this.paymentDecoded.expiry, title: 'Expiry', width: 50, type: DataTypeEnum.NUMBER },
{ key: 'min_finaltv_expiry', value: this.paymentDecoded.min_final_cltv_expiry, title: 'CLTV Expiry', width: 50 }]
];
@ -234,22 +234,22 @@ export class CLNLightningPaymentsComponent implements OnInit, AfterViewInit, OnD
this.dataService.decodePayment(this.paymentRequest, false).
pipe(takeUntil(this.unSubs[5])).subscribe((decodedPayment: PayRequest) => {
this.paymentDecoded = decodedPayment;
if (this.paymentDecoded.msatoshi) {
if (this.paymentDecoded.amount_msat) {
if (this.selNode?.fiatConversion) {
this.commonService.convertCurrency(this.paymentDecoded.msatoshi ? this.paymentDecoded.msatoshi / 1000 : 0, CurrencyUnitEnum.SATS, CurrencyUnitEnum.OTHER, (this.selNode.currencyUnits && this.selNode.currencyUnits.length > 2 ? this.selNode.currencyUnits[2] : ''), this.selNode.fiatConversion).
this.commonService.convertCurrency(this.paymentDecoded.amount_msat ? this.paymentDecoded.amount_msat / 1000 : 0, CurrencyUnitEnum.SATS, CurrencyUnitEnum.OTHER, (this.selNode.currencyUnits && this.selNode.currencyUnits.length > 2 ? this.selNode.currencyUnits[2] : ''), this.selNode.fiatConversion).
pipe(takeUntil(this.unSubs[6])).
subscribe({
next: (data) => {
this.paymentDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.paymentDecoded.msatoshi ?
this.paymentDecoded.msatoshi / 1000 : 0) + ' Sats (' + data.symbol + this.decimalPipe.transform((data.OTHER ? data.OTHER : 0),
CURRENCY_UNIT_FORMATS.OTHER) + ') | Memo: ' + this.paymentDecoded.description;
this.paymentDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.paymentDecoded.amount_msat ?
this.paymentDecoded.amount_msat / 1000 : 0) + ' Sats (' + this.decimalPipe.transform((data.OTHER ? data.OTHER : 0),
CURRENCY_UNIT_FORMATS.OTHER) + ' ' + data.unit + ') | Memo: ' + this.paymentDecoded.description;
}, error: (error) => {
this.paymentDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.paymentDecoded.msatoshi ? this.paymentDecoded.msatoshi / 1000 : 0) +
this.paymentDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.paymentDecoded.amount_msat ? this.paymentDecoded.amount_msat / 1000 : 0) +
' Sats | Memo: ' + this.paymentDecoded.description + '. Unable to convert currency.';
}
});
} else {
this.paymentDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.paymentDecoded.msatoshi ? this.paymentDecoded.msatoshi / 1000 : 0) +
this.paymentDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.paymentDecoded.amount_msat ? this.paymentDecoded.amount_msat / 1000 : 0) +
' Sats | Memo: ' + this.paymentDecoded.description;
}
} else {
@ -282,8 +282,8 @@ export class CLNLightningPaymentsComponent implements OnInit, AfterViewInit, OnD
{ key: 'destination', value: selPayment.destination, title: 'Destination', width: 80, type: DataTypeEnum.STRING }],
[{ key: 'created_at', value: selPayment.created_at, title: 'Creation Date', width: 50, type: DataTypeEnum.DATE_TIME },
{ key: 'status', value: this.titleCasePipe.transform(selPayment.status), title: 'Status', width: 50, type: DataTypeEnum.STRING }],
[{ key: 'msatoshi', value: selPayment.msatoshi, title: 'Amount (mSats)', width: 50, type: DataTypeEnum.NUMBER },
{ key: 'msatoshi_sent', value: selPayment.msatoshi_sent, title: 'Amount Sent (mSats)', width: 50, type: DataTypeEnum.NUMBER }]
[{ key: 'amount_msat', value: selPayment.amount_msat, title: 'Amount (mSats)', width: 50, type: DataTypeEnum.NUMBER },
{ key: 'amount_sent_msat', value: selPayment.amount_sent_msat, title: 'Amount Sent (mSats)', width: 50, type: DataTypeEnum.NUMBER }]
];
if (selPayment.bolt11 && selPayment.bolt11 !== '') {
reorderedPayment?.unshift([{ key: 'bolt11', value: selPayment.bolt11, title: 'Bolt 11', width: 100, type: DataTypeEnum.STRING }]);
@ -337,8 +337,11 @@ export class CLNLightningPaymentsComponent implements OnInit, AfterViewInit, OnD
break;
case 'msatoshi_sent':
rowToFilter = ((rowData['msatoshi_sent'] || rowData['amount_sent_msat'] || 0) / 1000)?.toString() || '';
break;
case 'msatoshi':
rowToFilter = ((+(rowData[this.selFilterBy] || 0)) / 1000)?.toString() || '';
rowToFilter = ((rowData['msatoshi'] || rowData['amount_msat'] || 0) / 1000)?.toString() || '';
break;
case 'type':
@ -356,7 +359,18 @@ export class CLNLightningPaymentsComponent implements OnInit, AfterViewInit, OnD
loadPaymentsTable(payments: Payment[]) {
this.payments = (payments) ? new MatTableDataSource<Payment>([...payments]) : new MatTableDataSource([]);
this.payments.sort = this.sort;
this.payments.sortingDataAccessor = (data: any, sortHeaderId: string) => ((data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null);
this.payments.sortingDataAccessor = (data: any, sortHeaderId: string) => {
switch (sortHeaderId) {
case 'msatoshi_sent':
return data['msatoshi_sent'] || data['amount_sent_msat'];
case 'msatoshi':
return data['msatoshi'] || data['amount_msat'];
default:
return (data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null;
}
};
this.payments.paginator = this.paginator;
this.setFilterPredicate();
this.applyFilter();

@ -132,7 +132,7 @@ export class CLNLightningSendPaymentsComponent implements OnInit, OnDestroy {
}
if (action.type === CLNActions.UPDATE_API_CALL_STATUS_CLN && action.payload.status === APICallStatusEnum.ERROR) {
if (action.payload.action === 'SendPayment') {
delete this.paymentDecoded.msatoshi;
delete this.paymentDecoded.amount_msat;
this.paymentError = action.payload.message;
}
if (action.payload.action === 'DecodePayment') {
@ -292,14 +292,14 @@ export class CLNLightningSendPaymentsComponent implements OnInit, OnDestroy {
onAmountChange(event: any) {
if (this.paymentType === PaymentTypes.INVOICE) {
delete this.paymentDecoded.msatoshi;
this.paymentDecoded.msatoshi = +event.target.value;
delete this.paymentDecoded.amount_msat;
this.paymentDecoded.amount_msat = +event.target.value;
}
if (this.paymentType === PaymentTypes.OFFER) {
delete this.offerDecoded.offer_amount;
delete this.offerDecoded.offer_amount_msat;
this.offerDecoded.offer_amount = +event.target.value * 1000;
this.offerDecoded.offer_amount_msat = event.target.value + 'msat';
this.offerDecoded.offer_amount_msat = event.target.value;
}
}
@ -312,7 +312,7 @@ export class CLNLightningSendPaymentsComponent implements OnInit, OnDestroy {
setOfferDecodedDetails() {
if (this.offerDecoded.offer_id && !this.offerDecoded.offer_amount_msat) {
this.offerDecoded.offer_amount_msat = '0msat';
this.offerDecoded.offer_amount_msat = 0;
this.offerDecoded.offer_amount = 0;
this.zeroAmtOffer = true;
this.offerDescription = this.offerDecoded.offer_description || '';
@ -320,7 +320,7 @@ export class CLNLightningSendPaymentsComponent implements OnInit, OnDestroy {
this.offerDecodedHint = 'Zero Amount Offer | Description: ' + this.offerDecoded.offer_description;
} else {
this.zeroAmtOffer = false;
this.offerDecoded.offer_amount = this.offerDecoded.offer_amount ? +this.offerDecoded.offer_amount : this.offerDecoded.offer_amount_msat ? +this.offerDecoded.offer_amount_msat.slice(0, -4) : null;
this.offerDecoded.offer_amount = this.offerDecoded.offer_amount || this.offerDecoded.offer_amount_msat || null;
this.offerAmount = this.offerDecoded.offer_amount ? this.offerDecoded.offer_amount / 1000 : 0;
this.offerDescription = this.offerDecoded.offer_description || '';
this.offerIssuer = this.offerDecoded.offer_issuer ? this.offerDecoded.offer_issuer : '';
@ -329,7 +329,7 @@ export class CLNLightningSendPaymentsComponent implements OnInit, OnDestroy {
pipe(takeUntil(this.unSubs[7])).
subscribe({
next: (data) => {
this.offerDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.offerAmount) + ' Sats (' + data.symbol + this.decimalPipe.transform((data.OTHER ? data.OTHER : 0), CURRENCY_UNIT_FORMATS.OTHER) + ') | Description: ' + this.offerDecoded.offer_description;
this.offerDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.offerAmount) + ' Sats (' + this.decimalPipe.transform((data.OTHER ? data.OTHER : 0), CURRENCY_UNIT_FORMATS.OTHER) + ' ' + data.unit + ') | Description: ' + this.offerDecoded.offer_description;
}, error: (error) => {
this.offerDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.offerAmount) + ' Sats | Description: ' + this.offerDecoded.offer_description + '. Unable to convert currency.';
}
@ -341,24 +341,25 @@ export class CLNLightningSendPaymentsComponent implements OnInit, OnDestroy {
}
setPaymentDecodedDetails() {
if (this.paymentDecoded.created_at && !this.paymentDecoded.msatoshi) {
this.paymentDecoded.msatoshi = 0;
if (this.paymentDecoded.created_at && !this.paymentDecoded.amount_msat) {
this.paymentDecoded.amount_msat = 0;
this.zeroAmtInvoice = true;
this.paymentDecodedHint = 'Zero Amount Invoice | Memo: ' + this.paymentDecoded.description;
} else {
this.zeroAmtInvoice = false;
if (this.selNode && this.selNode.fiatConversion) {
this.commonService.convertCurrency(this.paymentDecoded.msatoshi ? this.paymentDecoded.msatoshi / 1000 : 0, CurrencyUnitEnum.SATS, CurrencyUnitEnum.OTHER, (this.selNode.currencyUnits && this.selNode.currencyUnits.length > 2 ? this.selNode.currencyUnits[2] : ''), this.selNode.fiatConversion).
this.commonService.convertCurrency(this.paymentDecoded.amount_msat ? this.paymentDecoded.amount_msat / 1000 : 0, CurrencyUnitEnum.SATS, CurrencyUnitEnum.OTHER, (this.selNode.currencyUnits && this.selNode.currencyUnits.length > 2 ? this.selNode.currencyUnits[2] : ''), this.selNode.fiatConversion).
pipe(takeUntil(this.unSubs[8])).
subscribe({
next: (data) => {
this.paymentDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.paymentDecoded.msatoshi ? this.paymentDecoded.msatoshi / 1000 : 0) + ' Sats (' + data.symbol + this.decimalPipe.transform((data.OTHER ? data.OTHER : 0), CURRENCY_UNIT_FORMATS.OTHER) + ') | Memo: ' + this.paymentDecoded.description;
this.paymentDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.paymentDecoded.amount_msat ? this.paymentDecoded.amount_msat / 1000 : 0) + ' Sats (' +
this.decimalPipe.transform((data.OTHER ? data.OTHER : 0), CURRENCY_UNIT_FORMATS.OTHER) + ' ' + data.unit + ') | Memo: ' + this.paymentDecoded.description;
}, error: (error) => {
this.paymentDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.paymentDecoded.msatoshi ? this.paymentDecoded.msatoshi / 1000 : 0) + ' Sats | Memo: ' + this.paymentDecoded.description + '. Unable to convert currency.';
this.paymentDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.paymentDecoded.amount_msat ? this.paymentDecoded.amount_msat / 1000 : 0) + ' Sats | Memo: ' + this.paymentDecoded.description + '. Unable to convert currency.';
}
});
} else {
this.paymentDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.paymentDecoded.msatoshi ? this.paymentDecoded.msatoshi / 1000 : 0) + ' Sats | Memo: ' + this.paymentDecoded.description;
this.paymentDecodedHint = 'Sending: ' + this.decimalPipe.transform(this.paymentDecoded.amount_msat ? this.paymentDecoded.amount_msat / 1000 : 0) + ' Sats | Memo: ' + this.paymentDecoded.description;
}
}
}

@ -77,12 +77,12 @@ export interface Invoice {
bolt11?: string;
bolt12?: string;
payment_hash?: string;
msatoshi?: number;
amount_msat?: string;
msatoshi?: number; // For backward compatibility
amount_msat?: number;
status?: string;
pay_index?: number;
msatoshi_received?: number;
amount_received_msat?: string;
msatoshi_received?: number; // For backward compatibility
amount_received_msat?: number;
paid_at?: number;
payment_preimage?: string;
description?: string;
@ -138,14 +138,14 @@ export interface Hop {
}
export interface MPP {
amount_msat?: string;
amount_sent_msat?: string;
bolt11?: string;
created_at?: number;
destination?: string;
id?: number;
msatoshi?: number;
msatoshi_sent?: number;
msatoshi?: number; // For Backward compatibility
amount_msat?: number;
msatoshi_sent?: number; // For Backward compatibility
amount_sent_msat?: number;
payment_hash?: string;
payment_preimage?: string;
status?: string;
@ -153,15 +153,15 @@ export interface MPP {
}
export interface Payment {
amount_msat?: string;
amount_sent_msat?: string;
bolt11?: string;
bolt12?: string;
created_at?: number;
destination?: string;
id?: number;
msatoshi?: number;
msatoshi_sent?: number;
msatoshi?: number; // For Backward compatibility
amount_msat?: number;
msatoshi_sent?: number; // For Backward compatibility
amount_sent_msat?: number;
payment_hash?: string;
payment_preimage?: string;
status?: string;
@ -180,7 +180,7 @@ export interface PayRequest {
expiry?: number;
payee?: string;
msatoshi?: number;
amount_msat?: string;
amount_msat?: number;
description?: string;
min_final_cltv_expiry?: number;
payment_hash?: string;
@ -212,8 +212,8 @@ interface Recurrence {
export interface OfferRequest {
offer_id?: string;
offer_amount?: number | null;
offer_amount_msat?: string;
offer_amount?: number | null; // For Backward compatibility
offer_amount_msat?: number;
type?: string;
valid?: boolean;
offer_node_id?: string;
@ -253,11 +253,11 @@ export interface ForwardingEvent {
in_channel_alias?: string;
out_channel_alias?: string;
in_msatoshi?: number;
in_msat?: string;
in_msat?: string | number;
out_msatoshi?: number;
out_msat?: string;
out_msat?: string | number;
fee?: number;
fee_msat?: string;
fee_msat?: string | number;
status?: string;
received_time?: number;
resolved_time?: number;
@ -288,7 +288,7 @@ export interface Routes {
channel?: string;
direction?: number;
msatoshi?: number;
amount_msat?: string;
amount_msat?: number;
delay?: number;
alias?: string;
}
@ -308,22 +308,34 @@ export interface ChannelHTLC {
}
export interface Channel {
id?: string;
id?: string; // For Backward compatibility
peer_id?: string;
alias?: string;
connected?: boolean; // For Backward compatibility
peer_connected?: boolean;
state?: string;
short_channel_id?: string;
channel_id?: string;
funding_txid?: string;
private?: boolean;
msatoshi_to_us?: number;
msatoshi_to_them?: number;
msatoshi_total?: number;
their_channel_reserve_satoshis?: string;
our_channel_reserve_satoshis?: string;
spendable_msatoshi?: string;
msatoshi_to_us?: number; // For Backward compatibility
to_us_msat?: number;
msatoshi_to_them?: number; // For Backward compatibility
to_them_msat?: number;
msatoshi_total?: number; // For Backward compatibility
total_msat?: number;
their_channel_reserve_satoshis?: string; // For Backward compatibility
their_reserve_msat?: number;
our_channel_reserve_satoshis?: string; // For Backward compatibility
our_reserve_msat?: number;
spendable_msatoshi?: string; // For Backward compatibility
spendable_msat?: number;
direction?: number;
htlcs?: ChannelHTLC[];
receivable_msat?: number;
fee_base_msat?: number;
fee_proportional_millionths?: number;
dust_limit_msat?: number;
balancedness?: number; // Between 0-1-0
}
@ -366,6 +378,12 @@ export interface LookupNode {
};
}
export interface FeeBlockEstimates {
blockcount?: number;
feerate?: number;
smoothed_feerate?: number;
}
export interface FeeRatePerObj {
min_acceptable?: number;
max_acceptable?: number;
@ -375,6 +393,8 @@ export interface FeeRatePerObj {
delayed_to_us?: number;
htlc_resolution?: number;
penalty?: number;
floor?: number;
estimates?: FeeBlockEstimates[];
}
export interface OnChainFeeEstimates {
@ -394,7 +414,8 @@ export interface FeeRates {
export interface UTXO {
txid?: string;
output?: number;
value?: number;
value?: number; // For Backward compatibility
amount_msat?: number;
status?: string;
blockheight?: string;
scriptpubkey?: string;

@ -645,7 +645,9 @@ export const NODE_FEATURES_CLN = [
{ range: { min: 18, max: 19 }, description: 'Node can create large channels' },
{ range: { min: 20, max: 21 }, description: 'Anchor outputs' },
{ range: { min: 22, max: 23 }, description: 'Anchor commitment type with zero fee HTLC transactions' },
{ range: { min: 26, max: 27 }, description: 'Future segwit versions allowed in shutdown' }
{ range: { min: 26, max: 27 }, description: 'Future segwit versions allowed in shutdown' },
{ range: { min: 30, max: 31 }, description: 'AMP support' },
{ range: { min: 44, max: 45 }, description: 'Explicit commitment type' }
];
export enum NodeFeaturesECL {

@ -8,7 +8,7 @@ html {
line-height: 1.5;
overflow-x: hidden;
font-family: $font-family !important;
font-size: 100%;
font-size: 95%;
@include for_screensize(tab-port) {
font-size: 90%;
}
@ -1039,6 +1039,10 @@ mat-card-content.mat-mdc-card-content:first-child {
}
}
.mat-mdc-form-field-infix {
width: 14rem !important;
}
.flex-ellipsis {
flex: 1;
white-space: nowrap;
@ -1490,8 +1494,14 @@ mat-cell:last-of-type, .mdc-data-table__header-cell:last-of-type, mat-footer-cel
}
}
.dashboard-card .mat-mdc-card-header {
padding: 16px 0 0 16px
.dashboard-card {
margin-bottom: 0;
& .mat-mdc-card-header {
padding: 16px 0 0 16px
}
& .mat-mdc-card-content.dashboard-card-content {
margin-bottom: 0;
}
}
.dashboard-tabs-group.mat-mdc-tab-group {
@ -1577,6 +1587,10 @@ mat-cell:last-of-type, .mdc-data-table__header-cell:last-of-type, mat-footer-cel
}
}
.mat-mdc-tooltip-panel {
max-width: 25rem !important;
}
.ngx-charts-tooltip-content {
&.type-tooltip {
background: rgba(50, 50, 50, 0.9) !important;

@ -22,7 +22,7 @@
$hover-background-dark: rgba(255, 255, 255, 0.06);
.mat-primary {
color: $primary-darker;
color: $primary-darker !important;
}
.mat-sidenav-container .mat-sidenav-content {
@ -178,6 +178,9 @@
}
button.mdc-button.mat-mdc-button-base.mat-mdc-outlined-button{
border-color: $foreground-disabled;
&.mat-warn {
border-color: $warn-color;
}
}
.mat-mdc-select-arrow svg {
fill: $foreground-base;
@ -380,6 +383,8 @@
}
.material-icons {
&.info-icon {
font-size: 100%;
margin: 0 0.25rem;
color: $primary-darker;
&.info-icon-primary {
color: $primary-darker;

@ -99,8 +99,11 @@
color: $accent-color;
}
}
button.mdc-button.mat-mdc-button-base.mat-mdc-outlined-button{
button.mdc-button.mat-mdc-button-base.mat-mdc-outlined-button {
border-color: $primary-color;
&.mat-warn {
border-color: $warn-color;
}
}
.mat-tree-node:hover, .mat-nested-tree-node-parent:hover, .mat-select-panel .mat-option:hover, .mat-menu-panel .mat-menu-content .mat-menu-item:hover,
@ -118,10 +121,6 @@
}
}
.mat-mdc-progress-spinner .mdc-circular-progress__determinate-circle, .mat-mdc-progress-spinner .mdc-circular-progress__indeterminate-circle-graphic {
stroke: $background-color;
}
.spinner-container h2 {
color: $background-color;
}
@ -311,6 +310,8 @@
.material-icons {
&.mat-icon-no-color, &.info-icon {
font-size: 100%;
margin: 0 0.25rem;
color: $foreground-secondary-text;
&.info-icon-primary {
color: $primary-color;

Loading…
Cancel
Save