Liquidity Ads Page except channel count and capacity filters

Liquidity Ads Page except channel count and capacity filters
pull/1032/head
Shahana Farooqui 2 years ago committed by ShahanaFarooqui
parent 9da3eed1b6
commit c7fd9fad08

@ -71,15 +71,14 @@ export const listNodes = (req, res, next) => {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.ln_server_url + '/v1/network/listNodes' + (req.query !== {} ? (JSON.stringify(req.query).replace('{', '?').replace('}', '').replace(/:/g, '=').replace(/,/g, '&').replace(/"/g, '')) : '');
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Network', msg: 'List Nodes URL' + options.url });
request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'List Nodes Finished', data: body });
body.forEach((node, i) => {
node.option_will_fund.lease_fee_base_msat = (node.option_will_fund && node.option_will_fund.lease_fee_base_msat && typeof node.option_will_fund.lease_fee_base_msat === 'string' && node.option_will_fund.lease_fee_base_msat.includes('msat')) ? node.option_will_fund.lease_fee_base_msat.replace('msat', '') : node.option_will_fund.lease_fee_base_msat;
node.option_will_fund.channel_fee_max_base_msat = (node.option_will_fund && node.option_will_fund.channel_fee_max_base_msat && typeof node.option_will_fund.channel_fee_max_base_msat === 'string' && node.option_will_fund.channel_fee_max_base_msat.includes('msat')) ? node.option_will_fund.channel_fee_max_base_msat.replace('msat', '') : node.option_will_fund.channel_fee_max_base_msat;
// TO BE REMOVED
node.channelCount = +(Math.random() * 10).toFixed(0);
node.nodeCapacity = +(Math.random() * 1000000).toFixed(0);
// TO BE REMOVED
body.forEach((node) => {
if (node.option_will_fund) {
node.option_will_fund.lease_fee_base_msat = (node.option_will_fund.lease_fee_base_msat && typeof node.option_will_fund.lease_fee_base_msat === 'string' && node.option_will_fund.lease_fee_base_msat.includes('msat')) ? node.option_will_fund.lease_fee_base_msat.replace('msat', '') : node.option_will_fund.lease_fee_base_msat;
node.option_will_fund.channel_fee_max_base_msat = (node.option_will_fund.channel_fee_max_base_msat && typeof node.option_will_fund.channel_fee_max_base_msat === 'string' && node.option_will_fund.channel_fee_max_base_msat.includes('msat')) ? node.option_will_fund.channel_fee_max_base_msat.replace('msat', '') : node.option_will_fund.channel_fee_max_base_msat;
}
return node;
});
res.status(200).json(body);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -13,6 +13,6 @@
<style>@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}html{width:100%;height:99%;line-height:1.5;overflow-x:hidden;font-family:Roboto,sans-serif!important;font-size:62.5%}body{box-sizing:border-box;height:100%;margin:0;overflow:hidden}*{margin:0;padding:0}</style><link rel="stylesheet" href="styles.2872d180f488fe2c.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.2872d180f488fe2c.css"></noscript></head>
<body>
<rtl-app></rtl-app>
<script src="runtime.ecf038df3dc1dad4.js" type="module"></script><script src="polyfills.c0773154203456c6.js" type="module"></script><script src="main.26417b52daa70815.js" type="module"></script>
<script src="runtime.dae90b7a05c6a024.js" type="module"></script><script src="polyfills.c0773154203456c6.js" type="module"></script><script src="main.1300125d72833537.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={},g={};function r(e){var n=g[e];if(void 0!==n)return n.exports;var t=g[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=(n,t,f,o)=>{if(!t){var a=1/0;for(i=0;i<e.length;i++){for(var[t,f,o]=e[i],c=!0,u=0;u<t.length;u++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[u]))?t.splice(u--,1):(c=!1,o<a&&(a=o));if(c){e.splice(i--,1);var d=f();void 0!==d&&(n=d)}}return n}o=o||0;for(var i=e.length;i>0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,f,o]},r.n=e=>{var n=e&&e.__esModule?()=>e.default:()=>e;return r.d(n,{a:n}),n},r.d=(e,n)=>{for(var t in n)r.o(n,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:n[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((n,t)=>(r.f[t](e,n),n),[])),r.u=e=>e+"."+{404:"ecea7accd2beec12",636:"7f276612476ed267",893:"355edadcb4ce94f4",924:"ebace471eb0d0c1c"}[e]+".js",r.miniCssF=e=>{},r.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),(()=>{var e={},n="RTLApp:";r.l=(t,f,o,i)=>{if(e[t])e[t].push(f);else{var a,c;if(void 0!==o)for(var u=document.getElementsByTagName("script"),d=0;d<u.length;d++){var l=u[d];if(l.getAttribute("src")==t||l.getAttribute("data-webpack")==n+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",n+o),a.src=r.tu(t)),e[t]=[f];var s=(m,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(_=>_(b)),m)return m(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=>{"undefined"!=typeof Symbol&&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:n=>n},"undefined"!=typeof trustedTypes&&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=(f,o)=>{var i=r.o(e,f)?e[f]:void 0;if(0!==i)if(i)o.push(i[2]);else if(666!=f){var a=new Promise((l,s)=>i=e[f]=[l,s]);o.push(i[2]=a);var c=r.p+r.u(f),u=new Error;r.l(c,l=>{if(r.o(e,f)&&(0!==(i=e[f])&&(e[f]=void 0),i)){var s=l&&("load"===l.type?"missing":l.type),p=l&&l.target&&l.target.src;u.message="Loading chunk "+f+" failed.\n("+s+": "+p+")",u.name="ChunkLoadError",u.type=s,u.request=p,i[1](u)}},"chunk-"+f,f)}else e[f]=0},r.O.j=f=>0===e[f];var n=(f,o)=>{var u,d,[i,a,c]=o,l=0;if(i.some(p=>0!==e[p])){for(u in a)r.o(a,u)&&(r.m[u]=a[u]);if(c)var s=c(r)}for(f&&f(o);l<i.length;l++)r.o(e,d=i[l])&&e[d]&&e[d][0](),e[d]=0;return r.O(s)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(n.bind(null,0)),t.push=n.bind(null,t.push.bind(t))})()})();
(()=>{"use strict";var e,v={},g={};function r(e){var n=g[e];if(void 0!==n)return n.exports;var t=g[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=(n,t,f,o)=>{if(!t){var a=1/0;for(i=0;i<e.length;i++){for(var[t,f,o]=e[i],s=!0,u=0;u<t.length;u++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[u]))?t.splice(u--,1):(s=!1,o<a&&(a=o));if(s){e.splice(i--,1);var d=f();void 0!==d&&(n=d)}}return n}o=o||0;for(var i=e.length;i>0&&e[i-1][2]>o;i--)e[i]=e[i-1];e[i]=[t,f,o]},r.n=e=>{var n=e&&e.__esModule?()=>e.default:()=>e;return r.d(n,{a:n}),n},r.d=(e,n)=>{for(var t in n)r.o(n,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:n[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((n,t)=>(r.f[t](e,n),n),[])),r.u=e=>e+"."+{564:"d41ab2b8bdd42ac9",636:"f8c5bc0215761948",893:"355edadcb4ce94f4",924:"ff524ffae95c311b"}[e]+".js",r.miniCssF=e=>{},r.o=(e,n)=>Object.prototype.hasOwnProperty.call(e,n),(()=>{var e={},n="RTLApp:";r.l=(t,f,o,i)=>{if(e[t])e[t].push(f);else{var a,s;if(void 0!==o)for(var u=document.getElementsByTagName("script"),d=0;d<u.length;d++){var l=u[d];if(l.getAttribute("src")==t||l.getAttribute("data-webpack")==n+o){a=l;break}}a||(s=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",n+o),a.src=r.tu(t)),e[t]=[f];var c=(m,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(_=>_(b)),m)return m(b)},p=setTimeout(c.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=c.bind(null,a.onerror),a.onload=c.bind(null,a.onload),s&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&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:n=>n},"undefined"!=typeof trustedTypes&&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=(f,o)=>{var i=r.o(e,f)?e[f]:void 0;if(0!==i)if(i)o.push(i[2]);else if(666!=f){var a=new Promise((l,c)=>i=e[f]=[l,c]);o.push(i[2]=a);var s=r.p+r.u(f),u=new Error;r.l(s,l=>{if(r.o(e,f)&&(0!==(i=e[f])&&(e[f]=void 0),i)){var c=l&&("load"===l.type?"missing":l.type),p=l&&l.target&&l.target.src;u.message="Loading chunk "+f+" failed.\n("+c+": "+p+")",u.name="ChunkLoadError",u.type=c,u.request=p,i[1](u)}},"chunk-"+f,f)}else e[f]=0},r.O.j=f=>0===e[f];var n=(f,o)=>{var u,d,[i,a,s]=o,l=0;if(i.some(p=>0!==e[p])){for(u in a)r.o(a,u)&&(r.m[u]=a[u]);if(s)var c=s(r)}for(f&&f(o);l<i.length;l++)r.o(e,d=i[l])&&e[d]&&e[d][0](),e[d]=0;return r.O(c)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(n.bind(null,0)),t.push=n.bind(null,t.push.bind(t))})()})();

@ -66,15 +66,14 @@ export const listNodes = (req, res, next) => {
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/network/listNodes' + (req.query !== {} ? (JSON.stringify(req.query).replace('{', '?').replace('}', '').replace(/:/g, '=').replace(/,/g, '&').replace(/"/g, '')) : '');
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Network', msg: 'List Nodes URL' + options.url });
request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Network', msg: 'List Nodes Finished', data: body });
body.forEach((node, i) => {
node.option_will_fund.lease_fee_base_msat = (node.option_will_fund && node.option_will_fund.lease_fee_base_msat && typeof node.option_will_fund.lease_fee_base_msat === 'string' && node.option_will_fund.lease_fee_base_msat.includes('msat')) ? node.option_will_fund.lease_fee_base_msat.replace('msat', '') : node.option_will_fund.lease_fee_base_msat;
node.option_will_fund.channel_fee_max_base_msat = (node.option_will_fund && node.option_will_fund.channel_fee_max_base_msat && typeof node.option_will_fund.channel_fee_max_base_msat === 'string' && node.option_will_fund.channel_fee_max_base_msat.includes('msat')) ? node.option_will_fund.channel_fee_max_base_msat.replace('msat', '') : node.option_will_fund.channel_fee_max_base_msat;
// TO BE REMOVED
node.channelCount = +(Math.random() * 10).toFixed(0);
node.nodeCapacity = +(Math.random() * 1000000).toFixed(0);
// TO BE REMOVED
body.forEach((node) => {
if (node.option_will_fund) {
node.option_will_fund.lease_fee_base_msat = (node.option_will_fund.lease_fee_base_msat && typeof node.option_will_fund.lease_fee_base_msat === 'string' && node.option_will_fund.lease_fee_base_msat.includes('msat')) ? node.option_will_fund.lease_fee_base_msat.replace('msat', '') : node.option_will_fund.lease_fee_base_msat;
node.option_will_fund.channel_fee_max_base_msat = (node.option_will_fund.channel_fee_max_base_msat && typeof node.option_will_fund.channel_fee_max_base_msat === 'string' && node.option_will_fund.channel_fee_max_base_msat.includes('msat')) ? node.option_will_fund.channel_fee_max_base_msat.replace('msat', '') : node.option_will_fund.channel_fee_max_base_msat;
}
return node;
});
res.status(200).json(body);

@ -19,21 +19,17 @@
</span>
</div>
<mat-form-field fxFlex="34">
<input autoFocus matInput placeholder="Channel Amount (Sats)" name="channelAmount" [(ngModel)]="channelAmount" tabindex="1" type="number" step="1000" required>
<input autoFocus matInput placeholder="Channel Amount (Sats)" name="channelAmount" [(ngModel)]="channelAmount" (keyup)="onCalculateOpeningFee()" tabindex="1" type="number" step="10000" required>
<mat-error *ngIf="!channelAmount">Channel amount is required.</mat-error>
</mat-form-field>
<mat-form-field fxFlex="34">
<input matInput placeholder="Channel Opening Fee Rate (Sats/vByte)" name="channelOpeningFeeRate" [(ngModel)]="channelOpeningFeeRate" type="number" step="1" tabindex="2" required>
<input matInput placeholder="Channel Opening Fee Rate (Sats/vByte)" name="channelOpeningFeeRate" [(ngModel)]="channelOpeningFeeRate" (keyup)="onCalculateOpeningFee()" type="number" step="10" tabindex="2" required>
<mat-error *ngIf="!channelOpeningFeeRate">Channel opening fee rate is required.</mat-error>
</mat-form-field>
</div>
<div fxLayout="row" class="my-1">
<button class="mr-1" mat-stroked-button color="primary" tabindex="3" type="reset" (click)="onReset()">Clear</button>
<button mat-flat-button color="primary" (click)="onRecalculate()" tabindex="4" type="submit">Recalculate</button>
</div>
</form>
<mat-divider [inset]="true" class="my-2"></mat-divider>
<form fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row wrap" #formFilter="ngForm">
<!-- <mat-divider [inset]="true" class="my-2"></mat-divider> -->
<!-- <form fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row wrap" #formFilter="ngForm">
<div fxLayout="column" fxLayout.gt-sm="row wrap" fxFlex="100" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start start" class="page-sub-title-container mt-1">
<div fxFlex="30">
<span class="page-title">
@ -49,8 +45,8 @@
<input matInput placeholder="Channel Count" name="channelCount" [(ngModel)]="channelCount" (keyup)="onFilter()" type="number" step="1" min="0" tabindex="6">
</mat-form-field>
</div>
</form>
<div [perfectScrollbar] fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container">
</form> -->
<div [perfectScrollbar] fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container mt-2">
<mat-progress-bar *ngIf="apiCallStatus.status === apiCallStatusEnum.INITIATED" mode="indeterminate"></mat-progress-bar>
<table mat-table #table [dataSource]="liquidityNodes" matSort [ngClass]="{'overflow-auto error-border': errorMessage !== '','overflow-auto': true}">
<ng-container matColumnDef="alias">
@ -59,30 +55,31 @@
{{lqNode?.alias}}
</td>
</ng-container>
<ng-container matColumnDef="capacity">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Capacity </th>
<td mat-cell *matCellDef="let lqNode"><span fxLayoutAlign="end center">
{{lqNode?.option_will_fund?.lease_fee_basis | number:'1.0-0'}} </span></td>
</ng-container>
<ng-container matColumnDef="numChannels">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Channels </th>
<td mat-cell *matCellDef="let lqNode"><span fxLayoutAlign="end center">
{{lqNode?.option_will_fund?.lease_fee_basis | number:'1.0-0'}} </span></td>
<ng-container matColumnDef="capacityChannels">
<th mat-header-cell *matHeaderCellDef> Capacity/Channels </th>
<td mat-cell *matCellDef="let lqNode">
{{lqNode?.nodeCapacity/100000000 | number:'1.0-2'}} BTC / {{lqNode?.channelCount | number:'1.0-0'}}
</td>
</ng-container>
<ng-container matColumnDef="leaseFeeBasis">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Lease Fee </th>
<td mat-cell *matCellDef="let lqNode"><span fxLayoutAlign="end center">
{{lqNode?.option_will_fund?.lease_fee_basis | number:'1.0-0'}} </span></td>
<ng-container matColumnDef="leaseFee">
<th mat-header-cell *matHeaderCellDef> Lease Fee </th>
<td mat-cell *matCellDef="let lqNode">
{{lqNode?.option_will_fund?.lease_fee_base_msat/1000 | number:'1.0-0'}} Sats + {{(lqNode?.option_will_fund?.lease_fee_basis/100) | number:'1.2-2'}}%
</td>
</ng-container>
<ng-container matColumnDef="routingFee">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Routing Fee </th>
<td mat-cell *matCellDef="let lqNode"><span fxLayoutAlign="end center">
{{lqNode?.option_will_fund?.lease_fee_basis | number:'1.0-0'}} </span></td>
<th mat-header-cell *matHeaderCellDef> Routing Fee </th>
<td mat-cell *matCellDef="let lqNode">
{{lqNode?.option_will_fund?.channel_fee_max_base_msat/1000 | number:'1.0-0'}} Sats + {{lqNode?.option_will_fund?.channel_fee_max_proportional_thousandths * 1000 | number:'1.0-0'}} ppm
</td>
</ng-container>
<ng-container matColumnDef="channelOpenFee">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Channel Open Fee </th>
<td mat-cell *matCellDef="let lqNode"><span fxLayoutAlign="end center">
{{lqNode?.option_will_fund?.lease_fee_basis | number:'1.0-0'}} </span></td>
<ng-container matColumnDef="channelOpeningFee">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> Channel Opening Fee </th>
<td mat-cell *matCellDef="let lqNode">
<span fxLayoutAlign="end center">
{{lqNode.channelOpeningFee | number:'1.0-0'}} Sats
</span>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="px-3">

@ -1,10 +1,17 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { SharedModule } from '../../../shared/shared.module';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { RootReducer } from '../../../store/rtl.reducers';
import { LNDReducer } from '../../../lnd/store/lnd.reducers';
import { CLNReducer } from '../../../cln/store/cln.reducers';
import { ECLReducer } from '../../../eclair/store/ecl.reducers';
import { DataService } from '../../../shared/services/data.service';
import { CommonService } from '../../../shared/services/common.service';
import { mockDataService } from '../../../shared/test-helpers/mock-services';
import { RTLEffects } from '../../../store/rtl.effects';
import { mockCLEffects, mockDataService, mockECLEffects, mockLNDEffects, mockRTLEffects } from '../../../shared/test-helpers/mock-services';
import { CLNLiquidityAdsListComponent } from './liquidity-ads-list.component';
@ -17,11 +24,14 @@ describe('CLNLiquidityAdsListComponent', () => {
declarations: [CLNLiquidityAdsListComponent],
imports: [
BrowserAnimationsModule,
SharedModule
SharedModule,
StoreModule.forRoot({ root: RootReducer, lnd: LNDReducer, cln: CLNReducer, ecl: ECLReducer }),
EffectsModule.forRoot([mockRTLEffects, mockLNDEffects, mockCLEffects, mockECLEffects])
],
providers: [
CommonService,
{ provide: DataService, useClass: mockDataService }
{ provide: DataService, useClass: mockDataService },
{ provide: RTLEffects, useClass: mockRTLEffects }
]
}).
compileComponents();

@ -1,5 +1,5 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Subject } from 'rxjs';
import { Subject, combineLatest } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { MatTableDataSource } from '@angular/material/table';
@ -11,14 +11,14 @@ import { DataService } from '../../../shared/services/data.service';
import { LoggerService } from '../../../shared/services/logger.service';
import { CommonService } from '../../../shared/services/common.service';
import { AlertTypeEnum, APICallStatusEnum, DataTypeEnum, getPaginatorLabel, PAGE_SIZE, PAGE_SIZE_OPTIONS, ScreenSizeEnum } from '../../../shared/services/consts-enums-functions';
import { Balance, GetInfo, LookupNode } from '../../../shared/models/clnModels';
import { GetInfo, LookupNode } from '../../../shared/models/clnModels';
import { ApiCallStatusPayload } from '../../../shared/models/apiCallsPayload';
import { openAlert, openConfirmation } from '../../../store/rtl.actions';
import { RTLState } from '../../../store/rtl.state';
import { RTLEffects } from '../../../store/rtl.effects';
import { CLNOpenLiquidityChannelComponent } from '../open-liquidity-channel-modal/open-liquidity-channel-modal.component';
import { nodeInfoAndNodeSettingsAndBalance } from '../../store/cln.selector';
import { SelNodeChild } from '../../../shared/models/RTLconfig';
@Component({
selector: 'rtl-cln-liquidity-ads-list',
@ -40,7 +40,7 @@ export class CLNLiquidityAdsListComponent implements OnInit, OnDestroy {
public totalBalance = 0;
public information: GetInfo;
public channelAmount = 100000;
public channelOpeningFeeRate = 2;
public channelOpeningFeeRate = 10;
public nodeCapacity = 500000;
public channelCount = 5;
public liquidityNodesData: LookupNode[] = [];
@ -62,55 +62,64 @@ export class CLNLiquidityAdsListComponent implements OnInit, OnDestroy {
this.screenSize = this.commonService.getScreenSize();
if (this.screenSize === ScreenSizeEnum.XS) {
this.flgSticky = false;
this.displayedColumns = ['alias', 'capacity', 'actions'];
this.displayedColumns = ['alias', 'channelOpeningFee', 'actions'];
} else if (this.screenSize === ScreenSizeEnum.SM) {
this.flgSticky = false;
this.displayedColumns = ['alias', 'capacity', 'numChannels', 'leaseFeeBasis', 'routingFee', 'channelOpenFee', 'actions'];
this.displayedColumns = ['alias', 'leaseFee', 'routingFee', 'channelOpeningFee', 'actions'];
// this.displayedColumns = ['alias', 'capacityChannels', 'leaseFee', 'routingFee', 'channelOpeningFee', 'actions'];
} else if (this.screenSize === ScreenSizeEnum.MD) {
this.flgSticky = false;
this.displayedColumns = ['alias', 'capacity', 'numChannels', 'leaseFeeBasis', 'routingFee', 'channelOpenFee', 'actions'];
this.displayedColumns = ['alias', 'leaseFee', 'routingFee', 'channelOpeningFee', 'actions'];
// this.displayedColumns = ['alias', 'capacityChannels', 'leaseFee', 'routingFee', 'channelOpeningFee', 'actions'];
} else {
this.flgSticky = true;
this.displayedColumns = ['alias', 'capacity', 'numChannels', 'leaseFeeBasis', 'routingFee', 'channelOpenFee', 'actions'];
this.displayedColumns = ['alias', 'leaseFee', 'routingFee', 'channelOpeningFee', 'actions'];
// this.displayedColumns = ['alias', 'capacityChannels', 'leaseFee', 'routingFee', 'channelOpeningFee', 'actions'];
}
}
ngOnInit(): void {
this.dataService.listNetworkNodes('?liquidity_ads=yes').pipe(takeUntil(this.unSubs[0])).subscribe({
next: (res: any) => {
this.logger.info('Received Liquidity Ads Enabled Nodes: ' + JSON.stringify(res));
this.apiCallStatus.status = APICallStatusEnum.COMPLETED;
this.liquidityNodesData = res;
this.loadLiqNodesTable(this.liquidityNodesData);
}, error: (err) => {
this.logger.error('Liquidity Ads Nodes Error: ' + JSON.stringify(err));
this.apiCallStatus.status = APICallStatusEnum.ERROR;
this.errorMessage = JSON.stringify(err);
}
});
this.store.select(nodeInfoAndNodeSettingsAndBalance).pipe(takeUntil(this.unSubs[1])).
subscribe((infoSettingsBalSelector: { information: GetInfo, nodeSettings: SelNodeChild, balance: Balance }) => {
this.information = infoSettingsBalSelector.information;
this.totalBalance = infoSettingsBalSelector.balance.totalBalance;
this.logger.info(infoSettingsBalSelector);
combineLatest([this.store.select(nodeInfoAndNodeSettingsAndBalance), this.dataService.listNetworkNodes('?liquidity_ads=yes')]).pipe(takeUntil(this.unSubs[0])).
subscribe({
next: ([infoSettingsBalSelector, nodeListRes]) => {
this.information = infoSettingsBalSelector.information;
this.totalBalance = infoSettingsBalSelector.balance.totalBalance;
this.logger.info(infoSettingsBalSelector);
if (nodeListRes && !(<any[]>nodeListRes).length) { nodeListRes = []; }
this.logger.info('Received Liquidity Ads Enabled Nodes: ' + JSON.stringify(nodeListRes));
this.apiCallStatus.status = APICallStatusEnum.COMPLETED;
this.liquidityNodesData = (<LookupNode[]>nodeListRes).filter((node) => node.nodeid !== this.information.id);
this.onCalculateOpeningFee();
this.loadLiqNodesTable(this.liquidityNodesData);
}, error: (err) => {
this.logger.error('Liquidity Ads Nodes Error: ' + JSON.stringify(err));
this.apiCallStatus.status = APICallStatusEnum.ERROR;
this.errorMessage = JSON.stringify(err);
}
});
}
onRecalculate() {
onCalculateOpeningFee() {
this.liquidityNodesData.forEach((lqNode) => {
if (lqNode.option_will_fund) {
lqNode.channelOpeningFee = (+(lqNode.option_will_fund.lease_fee_base_msat) / 1000) + (this.channelAmount * (+lqNode.option_will_fund.lease_fee_basis) / 10000) + ((+lqNode.option_will_fund.funding_weight / 4) * this.channelOpeningFeeRate);
}
});
if (this.paginator) { this.paginator.firstPage(); }
}
onFilter() {
this.liquidityNodes.filter = 'Changed';
}
// onFilter() {
// this.liquidityNodes.filter = 'Changed';
// }
loadLiqNodesTable(liqNodes: LookupNode[]) {
this.liquidityNodes = new MatTableDataSource<LookupNode>([...liqNodes]);
this.liquidityNodes.sortingDataAccessor = (data: any, sortHeaderId: string) => ((data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null);
this.liquidityNodes.sort = this.sort;
this.liquidityNodes.filterPredicate = (node: LookupNode, fltr: string) => node.channelCount >= this.channelCount && node.nodeCapacity >= this.nodeCapacity;
this.liquidityNodes.paginator = this.paginator;
this.onFilter();
if (this.sort) { this.sort.sort({ id: 'channelOpeningFee', start: 'asc', disableClear: true }); }
// this.liquidityNodes.filterPredicate = (node: LookupNode, fltr: string) => node.channelCount >= this.channelCount && node.nodeCapacity >= this.nodeCapacity;
// this.onFilter();
}
onOpenChannel(lqNode: LookupNode) {
@ -143,10 +152,9 @@ export class CLNLiquidityAdsListComponent implements OnInit, OnDestroy {
[{ key: 'nodeid', value: lqNode.nodeid, title: 'Node ID', width: 100, type: DataTypeEnum.STRING }],
[{ key: 'base_fee', value: (lqNode.option_will_fund.lease_fee_base_msat / 1000), title: 'Lease Base Fee (Sats)', width: 50, type: DataTypeEnum.NUMBER },
{ key: 'fee_basis', value: lqNode.option_will_fund.lease_fee_basis, title: 'Lease Base Basis (bps)', width: 50, type: DataTypeEnum.NUMBER }],
[{ key: 'lease_fee_rate', value: '-000', title: 'Lease Fee Rate (ppm)', width: 50, type: DataTypeEnum.NUMBER },
{ key: 'funding_rate', value: lqNode.option_will_fund.funding_weight, title: 'Channel Open Funding Rate', width: 50, type: DataTypeEnum.NUMBER }],
[{ key: 'channel_max_base', value: (lqNode.option_will_fund.channel_fee_max_base_msat / 1000), title: 'Max Channel Routing Base Fee (Sats)', width: 50, type: DataTypeEnum.NUMBER },
{ key: 'channel_max_rate', value: lqNode.option_will_fund.channel_fee_max_proportional_thousandths, title: 'Max Channel Routing Fee Rate (ppm)', width: 50, type: DataTypeEnum.NUMBER }],
[{ key: 'channel_max_base', value: lqNode.option_will_fund.channel_fee_max_base_msat / 1000, title: 'Max Channel Routing Base Fee (Sats)', width: 50, type: DataTypeEnum.NUMBER },
{ key: 'channel_max_rate', value: lqNode.option_will_fund.channel_fee_max_proportional_thousandths * 1000, title: 'Max Channel Routing Fee Rate (ppm)', width: 50, type: DataTypeEnum.NUMBER }],
[{ key: 'funding_rate', value: lqNode.option_will_fund.funding_weight, title: 'Funding Weight', width: 100, type: DataTypeEnum.NUMBER }],
[{ key: 'address', value: addArr, title: 'Address', width: 100, type: DataTypeEnum.ARRAY }]
];
this.store.dispatch(openConfirmation({
@ -160,7 +168,7 @@ export class CLNLiquidityAdsListComponent implements OnInit, OnDestroy {
}
}
}));
this.rtlEffects.closeConfirm.pipe(takeUntil(this.unSubs[2])).subscribe((confirmRes) => {
this.rtlEffects.closeConfirm.pipe(takeUntil(this.unSubs[1])).subscribe((confirmRes) => {
if (confirmRes) {
this.onOpenChannel(lqNode);
}
@ -173,11 +181,6 @@ export class CLNLiquidityAdsListComponent implements OnInit, OnDestroy {
}
}
onReset() {
this.channelAmount = 0;
this.channelOpeningFeeRate = 0;
}
onFilterReset() {
this.nodeCapacity = 0;
this.channelCount = 0;

@ -11,17 +11,17 @@
<ng-container *ngTemplateOutlet="nodeDetailsExpansionBlock"></ng-container>
<div fxLayout="column" fxLayoutAlign="space-between stretch" fxLayoutAlign.gt-sm="space-between center" fxLayout.gt-sm="row wrap">
<mat-form-field fxFlex="30" fxLayoutAlign="start end">
<input autoFocus matInput [(ngModel)]="requestedAmount" placeholder="Requested Amount" type="number" [step]="1000" [min]="0" tabindex="1" required name="ramount" #ramount="ngModel">
<input autoFocus matInput [(ngModel)]="requestedAmount" (keyup)="calculateFee()" placeholder="Requested Amount" type="number" [step]="10000" [min]="0" tabindex="1" required name="ramount" #ramount="ngModel">
<span matSuffix> Sats </span>
<mat-error *ngIf="ramount.errors?.required">Requested amount is required.</mat-error>
</mat-form-field>
<mat-form-field fxFlex="30" fxLayoutAlign="start end">
<input matInput [(ngModel)]="feeRate" placeholder="Fee Rate" type="number" [step]="1" [min]="0" tabindex="2" required name="feerate" #feeRt="ngModel">
<input matInput [(ngModel)]="feeRate" placeholder="Fee Rate" (keyup)="calculateFee()" type="number" [step]="10" [min]="0" tabindex="2" required name="feerate" #feeRt="ngModel">
<span matSuffix> Sats/vByte </span>
<mat-error *ngIf="feeRt.errors?.required">Fee rate is required.</mat-error>
</mat-form-field>
<mat-form-field fxFlex="30" fxLayoutAlign="start end">
<input matInput [(ngModel)]="localAmount" placeholder="Local Amount" type="number" [step]="1000" [min]="20000" [max]="totalBalance" tabindex="3" required name="lamount" #lamount="ngModel">
<input matInput [(ngModel)]="localAmount" placeholder="Local Amount" type="number" [step]="10000" [min]="20000" [max]="totalBalance" tabindex="3" required name="lamount" #lamount="ngModel">
<mat-hint>Remaining Bal: {{totalBalance - ((localAmount) ? localAmount : 0) | number}}</mat-hint>
<span matSuffix> Sats </span>
<mat-error *ngIf="lamount.errors?.required">Local amount is required.</mat-error>
@ -30,7 +30,7 @@
</mat-form-field>
</div>
<div fxFlex="100" class="alert alert-info mt-2">
<span>Total cost to lease {{1250 | number}} (Sats)</span>
<span>Total cost to lease {{node.channelOpeningFee | number}} (Sats)</span>
</div>
<div fxFlex="100" class="alert alert-danger mt-2" *ngIf="channelConnectionError !== ''">
<fa-icon [icon]="faExclamationTriangle" class="mr-1 alert-icon"></fa-icon>
@ -46,7 +46,7 @@
</div>
<ng-template #nodeDetailsExpansionBlock>
<mat-expansion-panel class="flat-expansion-panel my-1" *ngIf="node" expanded="false">
<mat-expansion-panel class="flat-expansion-panel mt-1 mb-2" *ngIf="node" expanded="false">
<mat-expansion-panel-header>
<mat-panel-title>
<span>Node: &nbsp;</span><strong class="font-weight-900">{{node?.alias || node?.nodeid}}</strong>
@ -63,7 +63,7 @@
<div fxLayout="row">
<div fxFlex="100">
<h4 fxLayoutAlign="start" class="font-bold-500">Last Timestamp</h4>
<span class="overflow-wrap foreground-secondary-text">{{node.last_timestamp}}</span>
<span class="overflow-wrap foreground-secondary-text">{{(node.last_timestamp * 1000) | date:'dd/MMM/y HH:mm'}}</span>
</div>
</div>
<mat-divider class="w-100 my-1"></mat-divider>

@ -31,7 +31,36 @@ describe('CLNOpenLiquidityChannelComponent', () => {
CommonService,
{ provide: DataService, useClass: mockDataService },
{ provide: MatDialogRef, useClass: mockMatDialogRef },
{ provide: MAT_DIALOG_DATA, useValue: { message: {} } }
{
provide: MAT_DIALOG_DATA, useValue: {
message: {
node: {
nodeid: '0263983b2261d6ad9e2e134c1aa60d0c82d47c1c16b876a096a38d4f283fc236dc',
alias: 'blyte c-lightning',
color: '026398',
last_timestamp: 1640062643,
features: '800088282a6aa2',
addresses: [
{
type: 'ipv4',
address: '172.105.98.46',
port: 9747
}
],
option_will_fund: {
lease_fee_base_msat: '20000000',
lease_fee_basis: 50,
funding_weight: 666,
channel_fee_max_base_msat: '0',
channel_fee_max_proportional_thousandths: 1,
compact_lease: '029a0032000100004e20'
},
channelOpeningFee: 22165
},
balance: 100000, requestedAmount: 20000, feeRate: 10, localAmount: 20000
}
}
}
]
}).
compileComponents();

@ -63,14 +63,19 @@ export class CLNOpenLiquidityChannelComponent implements OnInit, OnDestroy {
this.form.controls.ramount.setValue(this.data.message.requestedAmount);
this.form.controls.feerate.setValue(this.data.message.feeRate);
this.form.controls.lamount.setValue(this.data.message.localAmount);
this.calculateFee();
this.channelConnectionError = '';
}
calculateFee() {
this.node.channelOpeningFee = (+(this.node.option_will_fund.lease_fee_base_msat) / 1000) + (this.requestedAmount * (+this.node.option_will_fund.lease_fee_basis) / 10000) + ((+this.node.option_will_fund.funding_weight / 4) * this.feeRate);
}
onOpenChannel(): boolean | void {
if (!this.node || !this.requestedAmount || !this.feeRate || !this.localAmount) {
if (!this.node || !this.node.option_will_fund || !this.requestedAmount || !this.feeRate || !this.localAmount) {
return true;
}
const newChannel = { peerId: this.node.nodeid, satoshis: this.requestedAmount.toString(), announce: false, feeRate: this.feeRate + 'perkb' };
const newChannel = { peerId: this.node.nodeid, satoshis: this.localAmount.toString(), feeRate: this.feeRate + 'perkb', requestAmount: this.requestedAmount.toString(), compactLease: this.node.option_will_fund.compact_lease };
this.store.dispatch(saveNewChannel({ payload: newChannel }));
}

@ -34,7 +34,7 @@
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="selFeeRate === 'customperkb' && !flgMinConf" fxFlex="48" fxLayoutAlign="end center">
<input matInput [(ngModel)]="customFeeRate" placeholder="Fee Rate (Sats/vB)" type="number" name="custFeeRate" [step]="0.1" [min]="0" tabindex="4" #custFeeRate="ngModel" [required]="selFeeRate === 'customperkb' && !flgMinConf">
<input matInput [(ngModel)]="customFeeRate" placeholder="Fee Rate (Sats/vByte)" type="number" name="custFeeRate" [step]="0.1" [min]="0" tabindex="4" #custFeeRate="ngModel" [required]="selFeeRate === 'customperkb' && !flgMinConf">
<mat-error *ngIf="selFeeRate === 'customperkb' && !flgMinConf && !customFeeRate">Fee Rate is required.</mat-error>
</mat-form-field>
</div>
@ -121,7 +121,7 @@
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="sendFundFormGroup.controls.selFeeRate.value === 'customperkb' && !sendFundFormGroup.controls.flgMinConf.value" fxFlex="48" fxLayoutAlign="end center">
<input matInput formControlName="customFeeRate" placeholder="Fee Rate (Sats/vB)" type="number" name="custFeeRate" [step]="0.1" [min]="0" tabindex="4">
<input matInput formControlName="customFeeRate" placeholder="Fee Rate (Sats/vByte)" type="number" name="custFeeRate" [step]="0.1" [min]="0" tabindex="4">
<mat-error *ngIf="sendFundFormGroup.controls.selFeeRate.value === 'customperkb' && !sendFundFormGroup.controls.flgMinConf.value && !sendFundFormGroup.controls.customFeeRate.value">Fee Rate is required.</mat-error>
</mat-form-field>
</div>

@ -40,7 +40,7 @@
</mat-expansion-panel-header>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<div fxLayout="column" fxLayoutAlign="space-between stretch" fxLayoutAlign.gt-sm="space-between center" fxLayout.gt-sm="row wrap">
<div fxFlex="48" fxLayoutAlign="space-between end">
<div fxFlex="54" fxLayoutAlign="space-between end">
<mat-form-field [fxFlex]="selFeeRate === 'customperkb' && !flgMinConf ? '48' : '100'" fxLayoutAlign="start center">
<mat-select tabindex="4" placeholder="Fee Rate" [(value)]="selFeeRate" (selectionChange)="customFeeRate=null" [disabled]="flgMinConf">
<mat-option *ngFor="let feeRateType of feeRateTypes" [value]="feeRateType.feeRateId">
@ -49,11 +49,11 @@
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="selFeeRate === 'customperkb' && !flgMinConf" fxFlex="48" fxLayoutAlign="end center">
<input matInput [(ngModel)]="customFeeRate" placeholder="Fee Rate (Sats/vB)" type="number" name="custFeeRate" [step]="0.1" [min]="0" tabindex="4" #custFeeRate="ngModel" [required]="selFeeRate === 'customperkb' && !flgMinConf">
<input matInput [(ngModel)]="customFeeRate" placeholder="Fee Rate (Sats/vByte)" type="number" name="custFeeRate" [step]="0.1" [min]="0" tabindex="4" #custFeeRate="ngModel" [required]="selFeeRate === 'customperkb' && !flgMinConf">
<mat-error *ngIf="selFeeRate === 'customperkb' && !flgMinConf && !customFeeRate">Fee Rate is required.</mat-error>
</mat-form-field>
</div>
<div fxFlex="48" fxLayout="row" fxLayoutAlign="start center">
<div fxFlex="42" fxLayout="row" fxLayoutAlign="start center">
<mat-checkbox fxFlex="2" tabindex="5" color="primary" [(ngModel)]="flgMinConf" (change)="flgMinConf ? selFeeRate=null : minConfValue=null" name="flgMinConf" fxLayoutAlign="stretch start" [ngClass]="{'mr-6': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM, 'mr-2': screenSize === screenSizeEnum.MD || screenSize === screenSizeEnum.LG || screenSize === screenSizeEnum.XL}"></mat-checkbox>
<mat-form-field fxFlex="98">
<input matInput [(ngModel)]="minConfValue" placeholder="Min Confirmation Blocks" type="number" name="blocks" [step]="1" [min]="0" tabindex="8" #blocks="ngModel" [required]="flgMinConf" [disabled]="!flgMinConf">
@ -62,13 +62,13 @@
</div>
</div>
<div fxLayout="column" fxLayoutAlign="space-between stretch" fxLayoutAlign.gt-sm="space-between center" fxLayout.gt-sm="row wrap" *ngIf="isCompatibleVersion">
<mat-form-field fxFlex="48" fxLayoutAlign="start end">
<mat-form-field fxFlex="54" fxLayoutAlign="start end">
<mat-select tabindex="6" placeholder="Coin Selection" (selectionChange)="onUTXOSelectionChange($event)" [(value)]="selUTXOs" multiple>
<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-select>
</mat-form-field>
<div fxFlex="48" fxLayout="row" fxLayoutAlign="start center">
<div fxFlex="42" fxLayout="row" fxLayoutAlign="start center">
<mat-slide-toggle tabindex="7" color="primary" [(ngModel)]="flgUseAllBalance" (change)="onUTXOAllBalanceChange()" name="flgUseAllBalance" [disabled]="selUTXOs.length < 1">
Use selected UTXOs balance
</mat-slide-toggle>

@ -138,7 +138,7 @@ export class CLNOpenChannelComponent implements OnInit, OnDestroy {
this.advancedTitle = this.advancedTitle + ' | Min Confirmation Blocks: ' + this.minConfValue;
}
if (this.selFeeRate) {
this.advancedTitle = this.advancedTitle + ' | Fee Rate: ' + (this.customFeeRate ? (this.customFeeRate + ' (Sats/vB)') : (this.feeRateTypes.find((feeRateType) => feeRateType.feeRateId === this.selFeeRate).feeRateType));
this.advancedTitle = this.advancedTitle + ' | Fee Rate: ' + (this.customFeeRate ? (this.customFeeRate + ' (Sats/vByte)') : (this.feeRateTypes.find((feeRateType) => feeRateType.feeRateId === this.selFeeRate).feeRateType));
}
if (this.selUTXOs.length && this.selUTXOs.length > 0) {
this.advancedTitle = this.advancedTitle + ' | Total Selected: ' + this.selUTXOs.length + ' | Selected UTXOs: ' + this.decimalPipe.transform(this.totalSelectedUTXOAmount) + ' Sats';

@ -43,7 +43,7 @@
</div>
</div>
<div fxLayout="column" fxLayoutAlign="space-between stretch" fxLayout.gt-sm="row wrap" fxFlex="100" fxLayoutAlign.gt-sm="space-between center">
<div fxFlex="48" fxLayoutAlign="space-between end">
<div fxFlex="60" fxLayoutAlign="space-between end">
<mat-form-field [fxFlex]="channelFormGroup.controls.selFeeRate.value === 'customperkb' && !channelFormGroup.controls.flgMinConf.value ? '48' : '100'" fxLayoutAlign="start center">
<mat-select tabindex="4" placeholder="Fee Rate" formControlName="selFeeRate">
<mat-option *ngFor="let feeRateType of feeRateTypes" [value]="feeRateType.feeRateId">
@ -52,11 +52,11 @@
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="channelFormGroup.controls.selFeeRate.value === 'customperkb' && !channelFormGroup.controls.flgMinConf.value" fxFlex="48" fxLayoutAlign="end center">
<input matInput formControlName="customFeeRate" placeholder="Fee Rate (Sats/vB)" type="number" name="custFeeRate" [step]="0.1" [min]="0" tabindex="4">
<input matInput formControlName="customFeeRate" placeholder="Fee Rate (Sats/vByte)" type="number" name="custFeeRate" [step]="0.1" [min]="0" tabindex="4">
<mat-error *ngIf="channelFormGroup.controls.selFeeRate.value === 'customperkb' && !channelFormGroup.controls.flgMinConf.value && !channelFormGroup.controls.customFeeRate.value">Fee Rate is required.</mat-error>
</mat-form-field>
</div>
<div fxFlex="48" fxLayout="row" fxLayoutAlign="start center">
<div fxFlex="35" fxLayout="row" fxLayoutAlign="start center">
<mat-checkbox fxFlex="2" tabindex="5" color="primary" formControlName="flgMinConf" fxLayoutAlign="stretch start" [ngClass]="{'mr-6': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM, 'mr-2': screenSize === screenSizeEnum.MD || screenSize === screenSizeEnum.LG || screenSize === screenSizeEnum.XL}"></mat-checkbox>
<mat-form-field fxFlex="98">
<input matInput formControlName="minConfValue" placeholder="Min Confirmation Blocks" type="number" name="blocks" [step]="1" [min]="0" tabindex="8" [required]="channelFormGroup.controls.flgMinConf.value">

@ -355,10 +355,11 @@ export class CLNEffects implements OnDestroy {
mergeMap((action: { type: string, payload: SaveChannel }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.OPEN_CHANNEL }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'SaveNewChannel', status: APICallStatusEnum.INITIATED } }));
const newPayload = { id: action.payload.peerId, satoshis: action.payload.satoshis, feeRate: action.payload.feeRate, announce: action.payload.announce, minconf: (action.payload.minconf) ? action.payload.minconf : null };
if (action.payload.utxos) {
newPayload['utxos'] = action.payload.utxos;
}
const newPayload = { id: action.payload.peerId, satoshis: action.payload.satoshis, feeRate: action.payload.feeRate, announce: action.payload.announce };
if (action.payload.minconf) { newPayload['minconf'] = action.payload.minconf; }
if (action.payload.utxos) { newPayload['utxos'] = action.payload.utxos; }
if (action.payload.requestAmount) { newPayload['request_amt'] = action.payload.requestAmount; }
if (action.payload.compactLease) { newPayload['compact_lease'] = action.payload.compactLease; }
return this.httpClient.post(this.CHILD_API_URL + environment.CHANNELS_API, newPayload).
pipe(
map((postRes: any) => {

@ -22,7 +22,7 @@
<div fxLayout="row wrap" fxLayoutAlign="start center" fxLayoutAlign.gt-md="space-between start">
<div fxLayout="column" fxFlex="100" fxFlex.gt-md="{{obj.width}}" *ngFor="let obj of objs; index as j;">
<h4 fxLayoutAlign="start" class="font-bold-500">{{obj.title}}</h4>
<span *ngIf="obj && obj.value; else emptyField">
<span *ngIf="obj && (!!obj.value || obj.value === 0); else emptyField">
<span [ngSwitch]="obj.type" class="foreground-secondary-text">
<ng-container *ngSwitchCase="dataTypeEnum.ARRAY">
<span *ngFor="let arrayObj of obj.value" class="display-block w-100" [innerHTML]="arrayObj"></span>

@ -60,21 +60,21 @@
</div>
<div fxLayout="column" fxLayout.gt-sm="row" fxFlex="100" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch">
<mat-form-field fxFlex="49">
<input matInput [(ngModel)]="leaseFeeBaseSat" placeholder="Lease Base Fee (Sats)" type="number" step="1000" min="0" tabindex="3" required name="leaseFeeBaseSat">
<input matInput [(ngModel)]="leaseFeeBaseSat" placeholder="Lease Base Fee (Sats)" type="number" step="100" min="0" tabindex="3" required name="leaseFeeBaseSat">
<mat-error *ngIf="!leaseFeeBaseSat">Lease base fee is required.</mat-error>
</mat-form-field>
<mat-form-field fxFlex="49">
<input matInput [(ngModel)]="leaseFeeBasis" placeholder="Lease Base Basis (bps)" type="number" step="10" min="0" tabindex="4" required name="leaseFeeBasis">
<input matInput [(ngModel)]="leaseFeeBasis" placeholder="Lease Base Basis (bps)" type="number" step="1" min="0" tabindex="4" required name="leaseFeeBasis">
<mat-error *ngIf="!leaseFeeBasis">Lease base basis is required.</mat-error>
</mat-form-field>
</div>
<div fxLayout="column" fxLayout.gt-sm="row" fxFlex="100" fxLayoutAlign.gt-sm="space-between center" fxLayoutAlign="start stretch">
<mat-form-field fxFlex="49">
<input matInput [(ngModel)]="channelFeeMaxBaseSat" placeholder="Max Channel Routing Base Fee (Sats)" type="number" step="1" min="0" tabindex="5" required name="channelFeeMaxBaseSat">
<input matInput [(ngModel)]="channelFeeMaxBaseSat" placeholder="Max Channel Routing Base Fee (Sats)" type="number" step="100" min="0" tabindex="5" required name="channelFeeMaxBaseSat">
<mat-error *ngIf="!channelFeeMaxBaseSat">Max channel routing base fee is required.</mat-error>
</mat-form-field>
<mat-form-field fxFlex="49">
<input matInput [(ngModel)]="channelFeeMaxProportional" placeholder="Max Channel Routing Fee Rate (ppm)" type="number" step="10" min="0" tabindex="6" required name="channelFeeMaxProportional">
<input matInput [(ngModel)]="channelFeeMaxProportional" placeholder="Max Channel Routing Fee Rate (ppm)" type="number" step="1000" min="0" tabindex="6" required name="channelFeeMaxProportional">
<mat-error *ngIf="!channelFeeMaxProportional">Max channel routing fee rate is required.</mat-error>
</mat-form-field>
</div>

@ -81,7 +81,7 @@ export class ExperimentalSettingsComponent implements OnInit, OnDestroy {
this.leaseFeeBaseSat = this.fundingPolicy.lease_fee_base_msat ? this.fundingPolicy.lease_fee_base_msat / 1000 : this.fundingPolicy.lease_fee_base_msat === 0 ? 0 : null;
this.leaseFeeBasis = this.fundingPolicy.lease_fee_basis || this.fundingPolicy.lease_fee_basis === 0 ? this.fundingPolicy.lease_fee_basis : null;
this.channelFeeMaxBaseSat = this.fundingPolicy.channel_fee_max_base_msat ? this.fundingPolicy.channel_fee_max_base_msat / 1000 : this.fundingPolicy.channel_fee_max_base_msat === 0 ? 0 : null;
this.channelFeeMaxProportional = this.fundingPolicy.channel_fee_max_proportional_thousandths || this.fundingPolicy.channel_fee_max_proportional_thousandths === 0 ? this.fundingPolicy.channel_fee_max_proportional_thousandths : null;
this.channelFeeMaxProportional = this.fundingPolicy.channel_fee_max_proportional_thousandths || this.fundingPolicy.channel_fee_max_proportional_thousandths === 0 ? (this.fundingPolicy.channel_fee_max_proportional_thousandths * 1000) : null;
});
}
}
@ -114,7 +114,7 @@ export class ExperimentalSettingsComponent implements OnInit, OnDestroy {
onUpdateFundingPolicy() {
this.flgUpdateCalled = false;
this.updateMsg = '';
this.dataService.getOrUpdateFunderPolicy(this.selPolicyType.id, this.policyMod, this.leaseFeeBaseSat, this.leaseFeeBasis, this.channelFeeMaxBaseSat * 1000, this.channelFeeMaxProportional).
this.dataService.getOrUpdateFunderPolicy(this.selPolicyType.id, this.policyMod, this.leaseFeeBaseSat, this.leaseFeeBasis, this.channelFeeMaxBaseSat * 1000, this.channelFeeMaxProportional / 1000).
pipe(takeUntil(this.unSubs[4])).
subscribe({
next: (updatePolicyRes: any) => {
@ -141,7 +141,7 @@ export class ExperimentalSettingsComponent implements OnInit, OnDestroy {
this.leaseFeeBaseSat = this.fundingPolicy.lease_fee_base_msat ? this.fundingPolicy.lease_fee_base_msat / 1000 : this.fundingPolicy.lease_fee_base_msat === 0 ? 0 : null;
this.leaseFeeBasis = this.fundingPolicy.lease_fee_basis || this.fundingPolicy.lease_fee_basis === 0 ? this.fundingPolicy.lease_fee_basis : null;
this.channelFeeMaxBaseSat = this.fundingPolicy.channel_fee_max_base_msat ? this.fundingPolicy.channel_fee_max_base_msat / 1000 : this.fundingPolicy.channel_fee_max_base_msat === 0 ? 0 : null;
this.channelFeeMaxProportional = this.fundingPolicy.channel_fee_max_proportional_thousandths || this.fundingPolicy.channel_fee_max_proportional_thousandths === 0 ? this.fundingPolicy.channel_fee_max_proportional_thousandths : null;
this.channelFeeMaxProportional = this.fundingPolicy.channel_fee_max_proportional_thousandths || this.fundingPolicy.channel_fee_max_proportional_thousandths === 0 ? (this.fundingPolicy.channel_fee_max_proportional_thousandths * 1000) : null;
}
ngOnDestroy() {

@ -341,6 +341,7 @@ export interface LookupNode {
features?: string;
channelCount?: number;
nodeCapacity?: number;
channelOpeningFee?: number;
addresses?: Address[];
option_will_fund?: {
lease_fee_base_msat?: number;
@ -402,6 +403,8 @@ export interface SaveChannel {
feeRate?: string;
minconf?: number;
utxos?: string[];
requestAmount?: string;
compactLease?: string;
}
export interface GetNewAddress {

@ -45,7 +45,7 @@ export const FEE_RATE_TYPES = [
{ feeRateId: 'urgent', feeRateType: 'Urgent' },
{ feeRateId: 'normal', feeRateType: 'Normal' },
{ feeRateId: 'slow', feeRateType: 'Slow' },
{ feeRateId: 'customperkb', feeRateType: 'Custom (Sats/vB)' }
{ feeRateId: 'customperkb', feeRateType: 'Custom (Sats/vByte)' }
];
export const NODE_SETTINGS = {

@ -108,6 +108,10 @@ export class mockDataService {
return of(mockResponseData.getForwardingHistory);
};
listNetworkNodes(qp: string) {
return of(mockResponseData.getListLiqNode);
};
};
export class mockSessionService {

@ -675,6 +675,54 @@ export const mockResponseData = {
],
last_offset_index: 2
},
getListLiqNode: [
{
nodeid: '0263983b2261d6ad9e2e134c1aa60d0c82d47c1c16b876a096a38d4f283fc236dc',
alias: 'blyte c-lightning',
color: '026398',
last_timestamp: 1640062643,
features: '800088282a6aa2',
addresses: [
{
type: 'ipv4',
address: '172.105.98.46',
port: 9747
}
],
option_will_fund: {
lease_fee_base_msat: '20000000',
lease_fee_basis: 50,
funding_weight: 666,
channel_fee_max_base_msat: '0',
channel_fee_max_proportional_thousandths: 1,
compact_lease: '029a0032000100004e20'
},
channelOpeningFee: 22165
},
{
nodeid: '023b485342839753dea66ff280df74e73570abc8160ad9a3456267dc5249e7a749',
alias: 'clight-test2',
color: '023b48',
last_timestamp: 1636307430,
features: '800088282a6aa2',
addresses: [
{
type: 'torv3',
address: 'cll5xqmdxfk6xn73x6ic423qleii3fcfb63vvbkhxwrmnhiyh2cb5xqd.onion',
port: 9735
}
],
option_will_fund: {
lease_fee_base_msat: '10000000',
lease_fee_basis: 50,
funding_weight: 666,
channel_fee_max_base_msat: '1000',
channel_fee_max_proportional_thousandths: 1,
compact_lease: '029a003200010000271003e8'
},
channelOpeningFee: 12165
}
],
setSelectedNodeSuccess: {
status: 200,
body: {

Loading…
Cancel
Save