Swap Out, Swap In and Cancelled Swap Tables

Swap Out, Swap In and Cancelled Swap Tables
pull/1089/head
ShahanaFarooqui 2 years ago
parent b37f6b8efe
commit b23115e133

@ -95,17 +95,17 @@ export const listSwapPeers = (req, res, next) => {
}); });
}; };
export const allowSwapRequests = (req, res, next) => { export const allowSwapRequests = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peerswap', msg: 'Allowing/Denying Swap Requests..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peerswap', msg: 'Allowing/Not Allowing Swap Requests..' });
options = common.getOptions(req); options = common.getOptions(req);
if (options.error) { if (options.error) {
return res.status(options.statusCode).json({ message: options.message, error: options.error }); return res.status(options.statusCode).json({ message: options.message, error: options.error });
} }
options.url = req.session.selectedNode.ln_server_url + '/v1/peerswap/allowSwapRequests' + req.params.isAllowed; options.url = req.session.selectedNode.ln_server_url + '/v1/peerswap/allowSwapRequests' + req.params.isAllowed;
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peerswap', msg: 'Swap Request Allowed/Denied', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peerswap', msg: 'Swap Request Allowed/Not Allowed', data: body });
res.status(200).json(body); res.status(200).json(body);
}).catch((errRes) => { }).catch((errRes) => {
const err = common.handleError(errRes, 'Peerswap', 'Allow/Deny Swap Request Error', req.session.selectedNode); const err = common.handleError(errRes, 'Peerswap', 'Allow/Not Allow Swap Request Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
}); });
}; };

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.43515fc39338348b.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.43515fc39338348b.css"></noscript></head> <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.43515fc39338348b.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.43515fc39338348b.css"></noscript></head>
<body> <body>
<rtl-app></rtl-app> <rtl-app></rtl-app>
<script src="runtime.6449ae8affb0dea2.js" type="module"></script><script src="polyfills.eddc63f1737a019a.js" type="module"></script><script src="main.b852398d8716a19c.js" type="module"></script> <script src="runtime.4b216667d6a60356.js" type="module"></script><script src="polyfills.eddc63f1737a019a.js" type="module"></script><script src="main.31d6322513f9b4d7.js" type="module"></script>
</body></html> </body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -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],s=!0,d=0;d<t.length;d++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[d]))?t.splice(d--,1):(s=!1,o<a&&(a=o));if(s){e.splice(i--,1);var l=f();void 0!==l&&(n=l)}}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+"."+{253:"256a01ccdc95a5d7",508:"06f7dec065381b97",515:"da134be35cc26574",924:"e98936d5bf0dd5da"}[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 d=document.getElementsByTagName("script"),l=0;l<d.length;l++){var u=d[l];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==n+o){a=u;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((u,c)=>i=e[f]=[u,c]);o.push(i[2]=a);var s=r.p+r.u(f),d=new Error;r.l(s,u=>{if(r.o(e,f)&&(0!==(i=e[f])&&(e[f]=void 0),i)){var c=u&&("load"===u.type?"missing":u.type),p=u&&u.target&&u.target.src;d.message="Loading chunk "+f+" failed.\n("+c+": "+p+")",d.name="ChunkLoadError",d.type=c,d.request=p,i[1](d)}},"chunk-"+f,f)}else e[f]=0},r.O.j=f=>0===e[f];var n=(f,o)=>{var d,l,[i,a,s]=o,u=0;if(i.some(p=>0!==e[p])){for(d in a)r.o(a,d)&&(r.m[d]=a[d]);if(s)var c=s(r)}for(f&&f(o);u<i.length;u++)r.o(e,l=i[u])&&e[l]&&e[l][0](),e[l]=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))})()})(); (()=>{"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+"."+{258:"525782ba4bbc257e",508:"06f7dec065381b97",515:"73bff63b24de0558",706:"911e43a7ac305c95"}[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))})()})();

@ -90,15 +90,15 @@ export const listSwapPeers = (req, res, next) => {
}; };
export const allowSwapRequests = (req, res, next) => { export const allowSwapRequests = (req, res, next) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peerswap', msg: 'Allowing/Denying Swap Requests..' }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peerswap', msg: 'Allowing/Not Allowing Swap Requests..' });
options = common.getOptions(req); options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); } if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.ln_server_url + '/v1/peerswap/allowSwapRequests' + req.params.isAllowed; options.url = req.session.selectedNode.ln_server_url + '/v1/peerswap/allowSwapRequests' + req.params.isAllowed;
request(options).then((body) => { request(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peerswap', msg: 'Swap Request Allowed/Denied', data: body }); logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Peerswap', msg: 'Swap Request Allowed/Not Allowed', data: body });
res.status(200).json(body); res.status(200).json(body);
}).catch((errRes) => { }).catch((errRes) => {
const err = common.handleError(errRes, 'Peerswap', 'Allow/Deny Swap Request Error', req.session.selectedNode); const err = common.handleError(errRes, 'Peerswap', 'Allow/Not Allow Swap Request Error', req.session.selectedNode);
return res.status(err.statusCode).json({ message: err.message, error: err.error }); return res.status(err.statusCode).json({ message: err.message, error: err.error });
}); });
}; };

@ -61,9 +61,7 @@ import { CLNOpenLiquidityChannelComponent } from './liquidity-ads/open-liquidity
import { LNServicesComponent } from './ln-services/ln-services.component'; import { LNServicesComponent } from './ln-services/ln-services.component';
import { PeerswapComponent } from './ln-services/peerswap/peerswap.component'; import { PeerswapComponent } from './ln-services/peerswap/peerswap.component';
import { SwapPeersComponent } from './ln-services/peerswap/swap-peers/swap-peers.component'; import { SwapPeersComponent } from './ln-services/peerswap/swap-peers/swap-peers.component';
import { PeerswapsCancelledComponent } from './ln-services/peerswap/swaps-cancelled/swaps-cancelled.component'; import { PeerswapsListComponent } from './ln-services/peerswap/swaps-list/swaps-list.component';
import { PeerswapsInComponent } from './ln-services/peerswap/swaps-in/swaps-in.component';
import { PeerswapsOutComponent } from './ln-services/peerswap/swaps-out/swaps-out.component';
import { CLNSwapOutModalComponent } from './ln-services/peerswap/swap-out-modal/swap-out-modal.component'; import { CLNSwapOutModalComponent } from './ln-services/peerswap/swap-out-modal/swap-out-modal.component';
import { CLNSwapInModalComponent } from './ln-services/peerswap/swap-in-modal/swap-in-modal.component'; import { CLNSwapInModalComponent } from './ln-services/peerswap/swap-in-modal/swap-in-modal.component';
@ -133,9 +131,7 @@ import { CLNUnlockedGuard } from '../shared/services/auth.guard';
LNServicesComponent, LNServicesComponent,
PeerswapComponent, PeerswapComponent,
SwapPeersComponent, SwapPeersComponent,
PeerswapsCancelledComponent, PeerswapsListComponent,
PeerswapsInComponent,
PeerswapsOutComponent,
CLNSwapOutModalComponent, CLNSwapOutModalComponent,
CLNSwapInModalComponent CLNSwapInModalComponent
], ],

@ -38,9 +38,7 @@ import { CLNLiquidityAdsListComponent } from './liquidity-ads/liquidity-ads-list
import { LNServicesComponent } from './ln-services/ln-services.component'; import { LNServicesComponent } from './ln-services/ln-services.component';
import { PeerswapComponent } from './ln-services/peerswap/peerswap.component'; import { PeerswapComponent } from './ln-services/peerswap/peerswap.component';
import { SwapPeersComponent } from './ln-services/peerswap/swap-peers/swap-peers.component'; import { SwapPeersComponent } from './ln-services/peerswap/swap-peers/swap-peers.component';
import { PeerswapsCancelledComponent } from './ln-services/peerswap/swaps-cancelled/swaps-cancelled.component'; import { PeerswapsListComponent } from './ln-services/peerswap/swaps-list/swaps-list.component';
import { PeerswapsInComponent } from './ln-services/peerswap/swaps-in/swaps-in.component';
import { PeerswapsOutComponent } from './ln-services/peerswap/swaps-out/swaps-out.component';
export const ClnRoutes: Routes = [ export const ClnRoutes: Routes = [
{ {
@ -113,11 +111,11 @@ export const ClnRoutes: Routes = [
path: 'services', component: LNServicesComponent, canActivate: [CLNUnlockedGuard], children: [ path: 'services', component: LNServicesComponent, canActivate: [CLNUnlockedGuard], children: [
{ {
path: 'peerswap', component: PeerswapComponent, canActivate: [CLNUnlockedGuard], children: [ path: 'peerswap', component: PeerswapComponent, canActivate: [CLNUnlockedGuard], children: [
{ path: '', pathMatch: 'full', redirectTo: 'peers' }, { path: '', pathMatch: 'full', redirectTo: 'prs' },
{ path: 'peers', component: SwapPeersComponent, canActivate: [CLNUnlockedGuard] }, { path: 'prs', component: SwapPeersComponent, canActivate: [CLNUnlockedGuard] },
{ path: 'psout', component: PeerswapsOutComponent, canActivate: [CLNUnlockedGuard] }, { path: 'psout', component: PeerswapsListComponent, canActivate: [CLNUnlockedGuard] },
{ path: 'psin', component: PeerswapsInComponent, canActivate: [CLNUnlockedGuard] }, { path: 'psin', component: PeerswapsListComponent, canActivate: [CLNUnlockedGuard] },
{ path: 'pscancelled', component: PeerswapsCancelledComponent, canActivate: [CLNUnlockedGuard] } { path: 'pscanceled', component: PeerswapsListComponent, canActivate: [CLNUnlockedGuard] }
] ]
} }
] ]

@ -4,7 +4,6 @@ import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators'; import { takeUntil, filter } from 'rxjs/operators';
import { faHandshake } from '@fortawesome/free-solid-svg-icons'; import { faHandshake } from '@fortawesome/free-solid-svg-icons';
@Component({ @Component({
selector: 'rtl-peerswap', selector: 'rtl-peerswap',
templateUrl: './peerswap.component.html', templateUrl: './peerswap.component.html',
@ -13,7 +12,7 @@ import { faHandshake } from '@fortawesome/free-solid-svg-icons';
export class PeerswapComponent implements OnInit, OnDestroy { export class PeerswapComponent implements OnInit, OnDestroy {
public faHandshake = faHandshake; public faHandshake = faHandshake;
public links = [{ link: 'peers', name: 'Peers' }, { link: 'psout', name: 'Swap Out' }, { link: 'psin', name: 'Swap In' }, { link: 'pscancelled', name: 'Swap Cancelled' }]; public links = [{ link: 'prs', name: 'Peers' }, { link: 'psout', name: 'Swap Out' }, { link: 'psin', name: 'Swap In' }, { link: 'pscanceled', name: 'Swap Canceled' }];
public activeTab = this.links[0]; public activeTab = this.links[0];
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()]; private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];

@ -1,36 +1,37 @@
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="100"> <div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header"> <mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start"> <div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">Initiate a Swapin</span> <span class="page-title">Initiate a Swapin</span>
</div> </div>
<button tabindex="5" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default <button tabindex="5" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default
mat-button>X</button> mat-button>X</button>
</mat-card-header> </mat-card-header>
<mat-card-content class="padding-gap-x-large"> <mat-card-content class="padding-gap-x-large">
<form fxLayout="row wrap" fxLayoutAlign="start space-between" fxFlex="100" #swapInForm="ngForm"> <form fxLayout="row wrap" fxLayoutAlign="start space-between" fxFlex="100" #swapInForm="ngForm">
<p fxLayoutAlign="start center" class="pb-2 word-break">Swapin with {{sPeer?.alias}}</p> <p fxLayoutAlign="start center" class="pb-2 word-break">Swapin with {{sPeer?.alias}}</p>
<mat-form-field fxFlex="100" fxLayoutAlign="start end"> <mat-form-field fxFlex="100" fxLayoutAlign="start end">
<input matInput [value]="sPeer.short_channel_id" placeholder="Short Channel ID" tabindex="1" name="shortChanId" disabled> <input matInput [value]="sPeer.short_channel_id" placeholder="Short Channel ID" tabindex="1" name="shortChanId" disabled>
</mat-form-field> </mat-form-field>
<mat-form-field fxFlex="100"> <mat-form-field fxFlex="100">
<input matInput autoFocus [(ngModel)]="swapAmount" (keyup)="onAmountChange()" placeholder="Amount" <input matInput autoFocus [(ngModel)]="swapAmount" (keyup)="onAmountChange()" placeholder="Amount"
type="number" [step]="100" [min]="1" [max]="sPeer.remote_balance" tabindex="2" name="swapAmt" #swapAmt="ngModel" required> type="number" [step]="1000" [min]="100000" [max]="sPeer.remote_balance" tabindex="2" name="swapAmt" #swapAmt="ngModel" required>
<span matSuffix class="ml-1"> Sats </span> <span matSuffix class="ml-1"> Sats </span>
<mat-error *ngIf="swapAmt.errors?.required">Amount is required.</mat-error> <mat-error *ngIf="swapAmt.errors?.required">Amount is required.</mat-error>
<mat-error *ngIf="swapAmt.errors?.max">Amount must be less than or equal to {{sPeer.remote_balance}}.</mat-error> <mat-error *ngIf="swapAmt.errors?.min">Amount must be greater than or equal to 100,000.</mat-error>
<mat-hint>Remaining Local: {{sPeer.remote_balance - ((swapAmount) ? swapAmount : 0) | number}}<br>{{swapAmountHint}}</mat-hint> <mat-error *ngIf="swapAmt.errors?.max">Amount must be less than or equal to {{sPeer.remote_balance | number}}.</mat-error>
</mat-form-field> <mat-hint>Amount should be between 100,000 and {{sPeer.remote_balance | number}}<br>{{swapAmountHint}}</mat-hint>
<div fxFlex="100" class="alert alert-danger mt-2" *ngIf="swapInError !== ''"> </mat-form-field>
<fa-icon [icon]="faExclamationTriangle" class="mr-1 alert-icon"></fa-icon> <div fxFlex="100" class="alert alert-danger mt-2" *ngIf="swapInError !== ''">
<span *ngIf="swapInError !== ''">{{swapInError}}</span> <fa-icon [icon]="faExclamationTriangle" class="mr-1 alert-icon"></fa-icon>
</div> <span *ngIf="swapInError !== ''">{{swapInError}}</span>
<div fxLayout="row" fxFlex="100" class="mt-1" fxLayoutAlign="end center"> </div>
<button class="mr-1" mat-button color="primary" tabindex="3" type="button" (click)="resetData()">Clear <div fxLayout="row" fxFlex="100" class="mt-1" fxLayoutAlign="end center">
Field</button> <button class="mr-1" mat-button color="primary" tabindex="3" type="button" (click)="resetData()">Clear
<button mat-button color="primary" (click)="onExecuteSwapin()" tabindex="4">Execute</button> Field</button>
</div> <button mat-button color="primary" (click)="onExecuteSwapin()" tabindex="4">Execute</button>
</form> </div>
</mat-card-content> </form>
</div> </mat-card-content>
</div>
</div> </div>

@ -57,7 +57,7 @@ export class CLNSwapInModalComponent implements OnInit, OnDestroy {
onExecuteSwapin(): boolean | void { onExecuteSwapin(): boolean | void {
this.swapInError = ''; this.swapInError = '';
if (!this.swapAmount || !this.sPeer || !this.sPeer.short_channel_id) { return true; } if (!this.swapAmount || !this.sPeer || !this.sPeer.short_channel_id) { return true; }
this.store.dispatch(swapIn({ payload: { amountSats: this.swapAmount, shortChannelId: this.sPeer?.short_channel_id, asset: 'btc' } })); this.store.dispatch(swapIn({ payload: { alias: this.sPeer.alias || '', amountSats: this.swapAmount, shortChannelId: this.sPeer?.short_channel_id, asset: 'btc' } }));
} }
resetData() { resetData() {

@ -1,36 +1,37 @@
<div fxLayout="row"> <div fxLayout="row">
<div fxFlex="100"> <div fxFlex="100">
<mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header"> <mat-card-header fxLayout="row" fxLayoutAlign="space-between center" class="modal-info-header">
<div fxFlex="95" fxLayoutAlign="start start"> <div fxFlex="95" fxLayoutAlign="start start">
<span class="page-title">Initiate a Swapout</span> <span class="page-title">Initiate a Swapout</span>
</div> </div>
<button tabindex="5" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default <button tabindex="5" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" [mat-dialog-close]="false" default
mat-button>X</button> mat-button>X</button>
</mat-card-header> </mat-card-header>
<mat-card-content class="padding-gap-x-large"> <mat-card-content class="padding-gap-x-large">
<form fxLayout="row wrap" fxLayoutAlign="start space-between" fxFlex="100" #swapOutForm="ngForm"> <form fxLayout="row wrap" fxLayoutAlign="start space-between" fxFlex="100" #swapOutForm="ngForm">
<p fxLayoutAlign="start center" class="pb-2 word-break">Swapout with {{sPeer?.alias}}</p> <p fxLayoutAlign="start center" class="pb-2 word-break">Swapout with {{sPeer?.alias}}</p>
<mat-form-field fxFlex="100" fxLayoutAlign="start end"> <mat-form-field fxFlex="100" fxLayoutAlign="start end">
<input matInput [value]="sPeer.short_channel_id" placeholder="Short Channel ID" tabindex="1" name="shortChanId" disabled> <input matInput [value]="sPeer.short_channel_id" placeholder="Short Channel ID" tabindex="1" name="shortChanId" disabled>
</mat-form-field> </mat-form-field>
<mat-form-field fxFlex="100"> <mat-form-field fxFlex="100">
<input matInput autoFocus [(ngModel)]="swapAmount" (keyup)="onAmountChange()" placeholder="Amount" <input matInput autoFocus [(ngModel)]="swapAmount" (keyup)="onAmountChange()" placeholder="Amount"
type="number" [step]="100" [min]="1" [max]="sPeer.local_balance" tabindex="2" name="swapAmt" #swapAmt="ngModel" required> type="number" [step]="1000" [min]="100000" [max]="sPeer.local_balance" tabindex="2" name="swapAmt" #swapAmt="ngModel" required>
<span matSuffix class="ml-1"> Sats </span> <span matSuffix class="ml-1"> Sats </span>
<mat-error *ngIf="swapAmt.errors?.required">Amount is required.</mat-error> <mat-error *ngIf="swapAmt.errors?.required">Amount is required.</mat-error>
<mat-error *ngIf="swapAmt.errors?.max">Amount must be less than or equal to {{sPeer.local_balance}}.</mat-error> <mat-error *ngIf="swapAmt.errors?.min">Amount must be greater than or equal to 100,000.</mat-error>
<mat-hint>Remaining Local: {{sPeer.local_balance - ((swapAmount) ? swapAmount : 0) | number}}<br>{{swapAmountHint}}</mat-hint> <mat-error *ngIf="swapAmt.errors?.max">Amount must be less than or equal to {{sPeer.local_balance | number}}.</mat-error>
</mat-form-field> <mat-hint>Amount should be between 100,000 and {{sPeer.local_balance | number}}<br>{{swapAmountHint}}</mat-hint>
<div fxFlex="100" class="alert alert-danger mt-2" *ngIf="swapOutError !== ''"> </mat-form-field>
<fa-icon [icon]="faExclamationTriangle" class="mr-1 alert-icon"></fa-icon> <div fxFlex="100" class="alert alert-danger mt-2" *ngIf="swapOutError !== ''">
<span *ngIf="swapOutError !== ''">{{swapOutError}}</span> <fa-icon [icon]="faExclamationTriangle" class="mr-1 alert-icon"></fa-icon>
</div> <span *ngIf="swapOutError !== ''">{{swapOutError}}</span>
<div fxLayout="row" fxFlex="100" class="mt-1" fxLayoutAlign="end center"> </div>
<button class="mr-1" mat-button color="primary" tabindex="3" type="button" (click)="resetData()">Clear <div fxLayout="row" fxFlex="100" class="mt-1" fxLayoutAlign="end center">
Field</button> <button class="mr-1" mat-button color="primary" tabindex="3" type="button" (click)="resetData()">Clear
<button mat-button color="primary" (click)="onExecuteSwapout()" tabindex="4">Execute</button> Field</button>
</div> <button mat-button color="primary" (click)="onExecuteSwapout()" tabindex="4">Execute</button>
</form> </div>
</mat-card-content> </form>
</div> </mat-card-content>
</div>
</div> </div>

@ -57,7 +57,7 @@ export class CLNSwapOutModalComponent implements OnInit, OnDestroy {
onExecuteSwapout(): boolean | void { onExecuteSwapout(): boolean | void {
this.swapOutError = ''; this.swapOutError = '';
if (!this.swapAmount || !this.sPeer || !this.sPeer.short_channel_id) { return true; } if (!this.swapAmount || !this.sPeer || !this.sPeer.short_channel_id) { return true; }
this.store.dispatch(swapOut({ payload: { amountSats: this.swapAmount, shortChannelId: this.sPeer?.short_channel_id, asset: 'btc' } })); this.store.dispatch(swapOut({ payload: { alias: this.sPeer.alias || '', amountSats: this.swapAmount, shortChannelId: this.sPeer?.short_channel_id, asset: 'btc' } }));
} }
resetData() { resetData() {

@ -22,17 +22,9 @@
<th mat-header-cell *matHeaderCellDef mat-sort-header>Node Alias</th> <th mat-header-cell *matHeaderCellDef mat-sort-header>Node Alias</th>
<td mat-cell *matCellDef="let sPeer">{{sPeer?.alias}}</td> <td mat-cell *matCellDef="let sPeer">{{sPeer?.alias}}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="nodeid">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Node ID</th>
<td mat-cell *matCellDef="let sPeer">
<span fxLayout="row" class="ellipsis-parent" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '25rem'}">
<span class="ellipsis-child">{{sPeer?.nodeid}}</span>
</span>
</td>
</ng-container>
<ng-container matColumnDef="swaps_allowed"> <ng-container matColumnDef="swaps_allowed">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Swaps Allowed</th> <th mat-header-cell *matHeaderCellDef mat-sort-header>Swaps Allowed</th>
<td mat-cell *matCellDef="let sPeer">{{sPeer?.swaps_allowed ? 'Allowed' : 'Denied'}}</td> <td mat-cell *matCellDef="let sPeer">{{sPeer?.swaps_allowed ? 'Yes' : 'No'}}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="local_balance"> <ng-container matColumnDef="local_balance">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Local Balance (Sats)</th> <th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Local Balance (Sats)</th>

@ -1,11 +1,3 @@
.mat-column-nodeid {
flex: 0 0 20%;
width: 20%;
& .ellipsis-parent {
display: flex;
}
}
.mat-column-actions { .mat-column-actions {
min-height: 4.8rem; min-height: 4.8rem;
} }

@ -1,6 +1,5 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { DatePipe } from '@angular/common';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
@ -50,7 +49,7 @@ export class SwapPeersComponent implements OnInit, OnDestroy {
public apiCallStatusEnum = APICallStatusEnum; public apiCallStatusEnum = APICallStatusEnum;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()]; private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private commonService: CommonService, private store: Store<RTLState>, private datePipe: DatePipe, private router: Router) { constructor(private logger: LoggerService, private commonService: CommonService, private store: Store<RTLState>) {
this.screenSize = this.commonService.getScreenSize(); this.screenSize = this.commonService.getScreenSize();
if (this.screenSize === ScreenSizeEnum.XS) { if (this.screenSize === ScreenSizeEnum.XS) {
this.flgSticky = false; this.flgSticky = false;
@ -63,13 +62,11 @@ export class SwapPeersComponent implements OnInit, OnDestroy {
this.displayedColumns = ['short_channel_id', 'alias', 'swaps_allowed', 'local_balance', 'remote_balance', 'actions']; this.displayedColumns = ['short_channel_id', 'alias', 'swaps_allowed', 'local_balance', 'remote_balance', 'actions'];
} else { } else {
this.flgSticky = true; this.flgSticky = true;
this.displayedColumns = ['short_channel_id', 'alias', 'nodeid', 'swaps_allowed', 'local_balance', 'remote_balance', 'actions']; this.displayedColumns = ['short_channel_id', 'alias', 'swaps_allowed', 'local_balance', 'remote_balance', 'actions'];
} }
} }
ngOnInit() { ngOnInit() {
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.onSameUrlNavigation = 'reload';
this.store.dispatch(fetchSwapPeers()); this.store.dispatch(fetchSwapPeers());
this.store.select(swapPeers).pipe(takeUntil(this.unSubs[0])). this.store.select(swapPeers).pipe(takeUntil(this.unSubs[0])).
subscribe((spSeletor: { totalSwapPeers: number, swapPeers: SwapPeerChannelsFlattened[], apiCallStatus: ApiCallStatusPayload }) => { subscribe((spSeletor: { totalSwapPeers: number, swapPeers: SwapPeerChannelsFlattened[], apiCallStatus: ApiCallStatusPayload }) => {
@ -88,7 +85,6 @@ export class SwapPeersComponent implements OnInit, OnDestroy {
} }
onSwapPeerClick(selSPeer: SwapPeerChannelsFlattened) { onSwapPeerClick(selSPeer: SwapPeerChannelsFlattened) {
this.logger.warn(selSPeer);
const reorderedSPeer = [ const reorderedSPeer = [
[{ key: 'nodeid', value: selSPeer.nodeid, title: 'Node Id', width: 100, type: DataTypeEnum.STRING }], [{ key: 'nodeid', value: selSPeer.nodeid, title: 'Node Id', width: 100, type: DataTypeEnum.STRING }],
[{ key: 'alias', value: selSPeer.alias, title: 'Alias', width: 50, type: DataTypeEnum.STRING }, [{ key: 'alias', value: selSPeer.alias, title: 'Alias', width: 50, type: DataTypeEnum.STRING },
@ -96,15 +92,15 @@ export class SwapPeersComponent implements OnInit, OnDestroy {
[{ key: 'local_balance', value: selSPeer.local_balance, title: 'Local Balance (Sats)', width: 50, type: DataTypeEnum.NUMBER }, [{ key: 'local_balance', value: selSPeer.local_balance, title: 'Local Balance (Sats)', width: 50, type: DataTypeEnum.NUMBER },
{ key: 'remote_balance', value: selSPeer.remote_balance, title: 'Remote Balance (Sats)', width: 50, type: DataTypeEnum.NUMBER }], { key: 'remote_balance', value: selSPeer.remote_balance, title: 'Remote Balance (Sats)', width: 50, type: DataTypeEnum.NUMBER }],
[{ key: 'total_fee_paid', value: selSPeer.total_fee_paid, title: 'Total Fee Paid (Sats)', width: 40, type: DataTypeEnum.NUMBER }, [{ key: 'total_fee_paid', value: selSPeer.total_fee_paid, title: 'Total Fee Paid (Sats)', width: 40, type: DataTypeEnum.NUMBER },
{ key: 'swaps_allowed', value: selSPeer.swaps_allowed ? 'Allowed' : 'Denied', title: 'Swaps Allowed', width: 30, type: DataTypeEnum.STRING }, { key: 'swaps_allowed', value: selSPeer.swaps_allowed ? 'Yes' : 'No', title: 'Swaps Allowed', width: 30, type: DataTypeEnum.STRING },
{ key: 'total_channels', value: selSPeer.channels?.length, title: 'Channels Opened', width: 30, type: DataTypeEnum.NUMBER }], { key: 'total_channels', value: selSPeer.channels?.length, title: 'Channels With Peer', width: 30, type: DataTypeEnum.NUMBER }],
[{ key: 'sent_total_swaps_out', value: selSPeer.sent?.total_swaps_out, title: 'Swap Out Sent', width: 25, type: DataTypeEnum.NUMBER }, [{ key: 'sent_total_swaps_out', value: selSPeer.sent?.total_swaps_out, title: 'Swap Out Sent', width: 25, type: DataTypeEnum.NUMBER },
{ key: 'sent_total_swaps_in', value: selSPeer.sent?.total_swaps_in, title: 'Swap In Sent', width: 25, type: DataTypeEnum.NUMBER }, { key: 'sent_total_swaps_in', value: selSPeer.sent?.total_swaps_in, title: 'Swap In Sent', width: 25, type: DataTypeEnum.NUMBER },
{ key: 'sent_total_sats_swapped_out', value: selSPeer.sent?.total_sats_swapped_out, title: 'Swapped Out Sent (Sats)', width: 25, type: DataTypeEnum.NUMBER }, { key: 'sent_total_sats_swapped_out', value: selSPeer.sent?.total_sats_swapped_out, title: 'Swapped Out Sent (Sats)', width: 25, type: DataTypeEnum.NUMBER },
{ key: 'sent_total_sats_swapped_in', value: selSPeer.sent?.total_sats_swapped_in, title: 'Swapped In Sent (Sats)', width: 25, type: DataTypeEnum.NUMBER }], { key: 'sent_total_sats_swapped_in', value: selSPeer.sent?.total_sats_swapped_in, title: 'Swapped In Sent (Sats)', width: 25, type: DataTypeEnum.NUMBER }],
[{ key: 'received_total_swaps_out', value: selSPeer.received?.total_swaps_out, title: 'Swap Out Received', width: 25, type: DataTypeEnum.NUMBER }, [{ key: 'received_total_swaps_out', value: selSPeer.received?.total_swaps_out, title: 'Swap Out Received', width: 25, type: DataTypeEnum.NUMBER },
{ key: 'received_total_swaps_in', value: selSPeer.received?.total_swaps_in, title: 'Swap In Received', width: 25, type: DataTypeEnum.NUMBER }, { key: 'received_total_swaps_in', value: selSPeer.received?.total_swaps_in, title: 'Swap In Received', width: 25, type: DataTypeEnum.NUMBER },
{ key: 'received_total_sats_swapped_out', value: selSPeer.received?.total_sats_swapped_out, title: 'Swapped Out Received(Sats)', width: 25, type: DataTypeEnum.NUMBER }, { key: 'received_total_sats_swapped_out', value: selSPeer.received?.total_sats_swapped_out, title: 'Swapped Out Received (Sats)', width: 25, type: DataTypeEnum.NUMBER },
{ key: 'received_total_sats_swapped_in', value: selSPeer.received?.total_sats_swapped_in, title: 'Swapped In Received (Sats)', width: 25, type: DataTypeEnum.NUMBER }] { key: 'received_total_sats_swapped_in', value: selSPeer.received?.total_sats_swapped_in, title: 'Swapped In Received (Sats)', width: 25, type: DataTypeEnum.NUMBER }]
]; ];
this.store.dispatch(openAlert({ this.store.dispatch(openAlert({
@ -148,7 +144,7 @@ export class SwapPeersComponent implements OnInit, OnDestroy {
const newSPeer = const newSPeer =
(sPeer.nodeid ? sPeer.nodeid : '') + (sPeer.nodeid ? sPeer.nodeid : '') +
(sPeer.alias ? sPeer.alias.toLowerCase() : '') + (sPeer.alias ? sPeer.alias.toLowerCase() : '') +
(sPeer.swaps_allowed ? 'allowed' : 'denied') + (sPeer.swaps_allowed ? 'yes' : 'no') +
(sPeer.short_channel_id ? sPeer.short_channel_id : '') + (sPeer.short_channel_id ? sPeer.short_channel_id : '') +
(sPeer.local_balance ? sPeer.local_balance : '') + (sPeer.local_balance ? sPeer.local_balance : '') +
(sPeer.remote_balance ? sPeer.remote_balance : ''); (sPeer.remote_balance ? sPeer.remote_balance : '');

@ -1,39 +0,0 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { SharedModule } from '../../../../shared/shared.module';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { PeerswapsCancelledComponent } from './swaps-cancelled.component';
import { mockLoggerService } from '../../../../shared/test-helpers/mock-services';
import { LoggerService } from '../../../../shared/services/logger.service';
describe('PeerswapsCancelledComponent', () => {
let component: PeerswapsCancelledComponent;
let fixture: ComponentFixture<PeerswapsCancelledComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [PeerswapsCancelledComponent],
imports: [
BrowserAnimationsModule,
SharedModule
],
providers: [
{ provide: LoggerService, useClass: mockLoggerService }
]
}).
compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(PeerswapsCancelledComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
afterEach(() => {
TestBed.resetTestingModule();
});
});

@ -1,27 +0,0 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { LoggerService } from '../../../../shared/services/logger.service';
@Component({
selector: 'rtl-peerswap-cancelled',
templateUrl: './swaps-cancelled.component.html',
styleUrls: ['./swaps-cancelled.component.scss']
})
export class PeerswapsCancelledComponent implements OnInit, OnDestroy {
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService) {}
ngOnInit() {
this.logger.info('Peerswap Out');
}
ngOnDestroy() {
this.unSubs.forEach((completeSub) => {
completeSub.next(<any>null);
completeSub.complete();
});
}
}

@ -1,39 +0,0 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { SharedModule } from '../../../../shared/shared.module';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { PeerswapsInComponent } from './swaps-in.component';
import { mockLoggerService } from '../../../../shared/test-helpers/mock-services';
import { LoggerService } from '../../../../shared/services/logger.service';
describe('PeerswapsInComponent', () => {
let component: PeerswapsInComponent;
let fixture: ComponentFixture<PeerswapsInComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [PeerswapsInComponent],
imports: [
BrowserAnimationsModule,
SharedModule
],
providers: [
{ provide: LoggerService, useClass: mockLoggerService }
]
}).
compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(PeerswapsInComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
afterEach(() => {
TestBed.resetTestingModule();
});
});

@ -1,27 +0,0 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { LoggerService } from '../../../../shared/services/logger.service';
@Component({
selector: 'rtl-peer-swaps-in',
templateUrl: './swaps-in.component.html',
styleUrls: ['./swaps-in.component.scss']
})
export class PeerswapsInComponent implements OnInit, OnDestroy {
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService) {}
ngOnInit() {
this.logger.info('Peerswap Out');
}
ngOnDestroy() {
this.unSubs.forEach((completeSub) => {
completeSub.next(<any>null);
completeSub.complete();
});
}
}

@ -0,0 +1,100 @@
<div fxLayout="column" fxLayoutAlign="start stretch" class="padding-gap-x">
<div fxLayout="column" fxLayout.gt-xs="row wrap" fxLayoutAlign.gt-xs="start center" fxLayoutAlign="start stretch"
class="page-sub-title-container">
<div fxFlex="70" class="padding-gap-x">
<fa-icon [icon]="selSwapList === swapLists[0] ? faPersonArrowUpFromLine : selSwapList === swapLists[1] ? faPersonArrowDownToLine : faPersonCircleXmark" class="mr-1"></fa-icon>
{{selSwapList === swapLists[0] ? 'Swapouts' : selSwapList === swapLists[1] ? 'Swapins' : 'Canceled Swaps'}}
</div>
<mat-form-field fxFlex="30">
<input matInput (keyup)="applyFilter()" [(ngModel)]="selFilter" placeholder="Filter">
</mat-form-field>
</div>
<div [perfectScrollbar] fxLayout="column" fxLayoutAlign="start center" fxFlex="100" class="table-container">
<mat-progress-bar *ngIf="apiCallStatus?.status === apiCallStatusEnum.INITIATED" mode="indeterminate">
</mat-progress-bar>
<table mat-table #table [dataSource]="swaps" fxFlex="100" matSort
[ngClass]="{'error-border': errorMessage !== ''}" class="overflow-auto">
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Swap Id</th>
<td mat-cell *matCellDef="let swap">
<span fxLayout="row" class="ellipsis-parent"
[ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : '25rem'}">
<span class="ellipsis-child">
<fa-icon [icon]="faArrowRightFromBracket" *ngIf="swap.role === peerswapRoles.SENDER" matTooltip="Sender" matTooltipPosition="right" class="mr-1" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></fa-icon>
<fa-icon [icon]="faArrowRightToBracket" *ngIf="swap.role === peerswapRoles.RECEIVER" matTooltip="Receiver" matTooltipPosition="right" class="mr-1" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></fa-icon>
{{swap?.id}}
</span>
</span>
</td>
</ng-container>
<ng-container matColumnDef="alias">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Node Alias</th>
<td mat-cell *matCellDef="let swap">{{swap?.alias}}</td>
</ng-container>
<ng-container matColumnDef="short_channel_id">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="pl-1">Short Channel ID</th>
<td mat-cell *matCellDef="let swap" class="pl-1">{{swap?.short_channel_id}}</td>
</ng-container>
<ng-container matColumnDef="created_at">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Created At</th>
<td mat-cell *matCellDef="let swap">
{{swap?.created_at | date:'dd/MMM/y HH:mm'}}
</td>
</ng-container>
<ng-container matColumnDef="state">
<th mat-header-cell *matHeaderCellDef mat-sort-header>State</th>
<td mat-cell *matCellDef="let swap">{{swap?.state | swapState}}</td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before">Amount (Sats)</th>
<td mat-cell *matCellDef="let swap"><span fxLayoutAlign="end center">{{swap?.amount | number }}</span>
</td>
</ng-container>
<ng-container matColumnDef="cancel_message">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="pl-2">Cancel Message</th>
<td mat-cell *matCellDef="let swap" class="pl-2">{{swap?.cancel_message}}</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="px-3">
<div class="bordered-box table-actions-select">
<mat-select placeholder="Actions" tabindex="1" class="mr-0">
<mat-select-trigger></mat-select-trigger>
<mat-option (click)="onDownloadCSV()">Download CSV</mat-option>
</mat-select>
</div>
</th>
<td mat-cell *matCellDef="let swap" [ngClass]="{'px-3': screenSize !== screenSizeEnum.XS}"
fxLayoutAlign="end center">
<button *ngIf="(selSwapList === swapLists[2]) || (selSwapList !== swapLists[2] && (swap.state === 'State_ClaimedPreimage' || swap.state === 'State_ClaimedCoop'))" mat-stroked-button color="primary" type="button" tabindex="4" (click)="onSwapClick(swap)">View Info</button>
<div *ngIf="selSwapList !== swapLists[2] && swap.state !== 'State_ClaimedPreimage' && swap.state !== 'State_ClaimedCoop'" class="bordered-box table-actions-select" fxLayoutAlign="center center">
<mat-select placeholder="Actions" tabindex="2" class="mr-0">
<mat-select-trigger></mat-select-trigger>
<mat-option (click)="onSwapClick(swap)">View Info</mat-option>
<mat-option (click)="onSwapRefresh(swap)">Refresh</mat-option>
</mat-select>
</div>
</td>
</ng-container>
<ng-container matColumnDef="no_swap">
<td mat-footer-cell *matFooterCellDef colspan="4">
<p
*ngIf="(!swaps?.data || (swaps?.data && swaps?.data.length && swaps?.data?.length<1)) && apiCallStatus?.status === apiCallStatusEnum.COMPLETED">
No swap available.</p>
<p
*ngIf="(!swaps?.data || (swaps?.data && swaps?.data.length && swaps?.data?.length<1)) && apiCallStatus?.status === apiCallStatusEnum.INITIATED">
Getting swaps...</p>
<p
*ngIf="(!swaps?.data || (swaps?.data && swaps?.data.length && swaps?.data?.length<1)) && apiCallStatus?.status === apiCallStatusEnum.ERROR">
{{errorMessage}}</p>
</td>
</ng-container>
<tr mat-footer-row *matFooterRowDef="['no_swap']"
[ngClass]="{'display-none': swaps?.data && swaps?.data?.length>0}">
</tr>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: flgSticky;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
<mat-paginator *ngIf="errorMessage === ''" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions"
[showFirstLastButtons]="screenSize === screenSizeEnum.XS ? false : true" class="mb-1"></mat-paginator>
</div>

@ -0,0 +1,12 @@
.mat-column-id {
flex: 0 0 20%;
width: 20%;
& .ellipsis-parent {
display: flex;
}
}
.mat-column-actions {
min-height: 4.8rem;
}

@ -0,0 +1,55 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterTestingModule } from '@angular/router/testing';
import { EffectsModule } from '@ngrx/effects';
import { StoreModule } from '@ngrx/store';
import { CommonService } from '../../../../shared/services/common.service';
import { mockCLEffects, mockLoggerService, mockECLEffects, mockLNDEffects, mockRTLEffects, mockDataService } from '../../../../shared/test-helpers/mock-services';
import { SharedModule } from '../../../../shared/shared.module';
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 { PeerswapsListComponent } from './swaps-list.component';
import { LoggerService } from '../../../../shared/services/logger.service';
import { Router } from '@angular/router';
describe('PeerswapsListComponent', () => {
let component: PeerswapsListComponent;
let fixture: ComponentFixture<PeerswapsListComponent>;
// private commonService: CommonService, private store: Store<RTLState>, private router: Router
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [PeerswapsListComponent],
imports: [
BrowserAnimationsModule,
SharedModule,
RouterTestingModule,
StoreModule.forRoot({ root: RootReducer, lnd: LNDReducer, cln: CLNReducer, ecl: ECLReducer }),
EffectsModule.forRoot([mockRTLEffects, mockLNDEffects, mockCLEffects, mockECLEffects])
],
providers: [
CommonService,
{ provide: LoggerService, useClass: mockLoggerService },
{ provide: DataService, useClass: mockDataService }
]
}).
compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(PeerswapsListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
afterEach(() => {
TestBed.resetTestingModule();
});
});

@ -0,0 +1,225 @@
import { Component, OnInit, OnDestroy, ViewChild, AfterViewInit } from '@angular/core';
import { DatePipe, TitleCasePipe } from '@angular/common';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { MatPaginator, MatPaginatorIntl } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { faArrowRightFromBracket, faArrowRightToBracket, faPersonArrowDownToLine, faPersonArrowUpFromLine, faPersonCircleXmark } from '@fortawesome/free-solid-svg-icons';
import { Swap } from '../../../../shared/models/clnModels';
import { PAGE_SIZE, PAGE_SIZE_OPTIONS, getPaginatorLabel, ScreenSizeEnum, APICallStatusEnum, DataTypeEnum, AlertTypeEnum, PeerswapRoles, SwapTypeEnum } from '../../../../shared/services/consts-enums-functions';
import { ApiCallStatusPayload } from '../../../../shared/models/apiCallsPayload';
import { LoggerService } from '../../../../shared/services/logger.service';
import { CommonService } from '../../../../shared/services/common.service';
import { RTLState } from '../../../../store/rtl.state';
import { openAlert } from '../../../../store/rtl.actions';
import { fetchSwaps, getSwap } from '../../../store/cln.actions';
import { swaps } from '../../../store/cln.selector';
import { SwapStatePipe } from '../../../../shared/pipes/app.pipe';
@Component({
selector: 'rtl-peer-swaps-list',
templateUrl: './swaps-list.component.html',
styleUrls: ['./swaps-list.component.scss'],
providers: [
{ provide: MatPaginatorIntl, useValue: getPaginatorLabel('Swaps') }
]
})
export class PeerswapsListComponent implements OnInit, AfterViewInit, OnDestroy {
@ViewChild(MatSort, { static: false }) sort: MatSort | undefined;
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator | undefined;
public faPersonArrowDownToLine = faPersonArrowDownToLine;
public faPersonArrowUpFromLine = faPersonArrowUpFromLine;
public faPersonCircleXmark = faPersonCircleXmark;
public faArrowRightFromBracket = faArrowRightFromBracket;
public faArrowRightToBracket = faArrowRightToBracket;
public displayedColumns: any[] = [];
public allSwapsData: any = null;
public swapsData: Swap[] = [];
public swaps: any;
public flgSticky = false;
public pageSize = PAGE_SIZE;
public pageSizeOptions = PAGE_SIZE_OPTIONS;
public screenSize = '';
public screenSizeEnum = ScreenSizeEnum;
public errorMessage = '';
public selFilter = '';
public swapLists = ['psout', 'psin', 'pscanceled'];
public selSwapList = this.swapLists[0];
public peerswapRoles = PeerswapRoles;
public apiCallStatus: ApiCallStatusPayload | null = null;
public apiCallStatusEnum = APICallStatusEnum;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService, private commonService: CommonService, private store: Store<RTLState>, private datePipe: DatePipe, private router: Router, private swapStatePipe: SwapStatePipe, private titleCasePipe: TitleCasePipe) {
this.screenSize = this.commonService.getScreenSize();
}
ngOnInit() {
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.onSameUrlNavigation = 'reload';
this.selSwapList = this.router.url.substring(this.router.url.lastIndexOf('/') + 1);
this.store.select(swaps).pipe(takeUntil(this.unSubs[0])).
subscribe((swapsSeletor: { swapOuts: Swap[], swapIns: Swap[], swapsCanceled: Swap[], apiCallStatus: ApiCallStatusPayload }) => {
this.errorMessage = '';
this.apiCallStatus = swapsSeletor.apiCallStatus;
if (this.apiCallStatus?.status === APICallStatusEnum.UN_INITIATED) {
this.store.dispatch(fetchSwaps());
}
if (this.apiCallStatus.status === APICallStatusEnum.ERROR) {
this.errorMessage = !this.apiCallStatus.message ? '' : (typeof (this.apiCallStatus.message) === 'object') ? JSON.stringify(this.apiCallStatus.message) : this.apiCallStatus.message;
}
if (this.apiCallStatus?.status === APICallStatusEnum.COMPLETED) {
this.allSwapsData = { swapOuts: swapsSeletor.swapOuts, swapIns: swapsSeletor.swapIns, swapsCanceled: swapsSeletor.swapsCanceled };
if (this.sort && this.paginator) {
this.loadTableWithSelection();
}
}
this.logger.info(swapsSeletor);
});
}
ngAfterViewInit(): void {
if (this.allSwapsData) {
this.loadTableWithSelection();
}
}
loadTableWithSelection() {
switch (this.selSwapList) {
case this.swapLists[0]:
if (this.screenSize === ScreenSizeEnum.XS) {
this.flgSticky = false;
this.displayedColumns = ['id', 'state', 'amount', 'actions'];
} else if (this.screenSize === ScreenSizeEnum.SM) {
this.flgSticky = false;
this.displayedColumns = ['id', 'alias', 'short_channel_id', 'state', 'amount', 'actions'];
} else if (this.screenSize === ScreenSizeEnum.MD) {
this.flgSticky = false;
this.displayedColumns = ['id', 'alias', 'short_channel_id', 'created_at', 'state', 'amount', 'actions'];
} else {
this.flgSticky = true;
this.displayedColumns = ['id', 'alias', 'short_channel_id', 'created_at', 'state', 'amount', 'actions'];
}
this.swapsData = this.allSwapsData?.swapOuts || [];
break;
case this.swapLists[1]:
if (this.screenSize === ScreenSizeEnum.XS) {
this.flgSticky = false;
this.displayedColumns = ['id', 'state', 'amount', 'actions'];
} else if (this.screenSize === ScreenSizeEnum.SM) {
this.flgSticky = false;
this.displayedColumns = ['id', 'alias', 'short_channel_id', 'state', 'amount', 'actions'];
} else if (this.screenSize === ScreenSizeEnum.MD) {
this.flgSticky = false;
this.displayedColumns = ['id', 'alias', 'short_channel_id', 'created_at', 'state', 'amount', 'actions'];
} else {
this.flgSticky = true;
this.displayedColumns = ['id', 'alias', 'short_channel_id', 'created_at', 'state', 'amount', 'actions'];
}
this.swapsData = this.allSwapsData?.swapIns || [];
break;
case this.swapLists[2]:
if (this.screenSize === ScreenSizeEnum.XS) {
this.flgSticky = false;
this.displayedColumns = ['id', 'amount', 'cancel_message', 'actions'];
} else if (this.screenSize === ScreenSizeEnum.SM) {
this.flgSticky = false;
this.displayedColumns = ['id', 'alias', 'short_channel_id', 'amount', 'cancel_message', 'actions'];
} else if (this.screenSize === ScreenSizeEnum.MD) {
this.flgSticky = false;
this.displayedColumns = ['id', 'alias', 'short_channel_id', 'created_at', 'amount', 'cancel_message', 'actions'];
} else {
this.flgSticky = true;
this.displayedColumns = ['id', 'alias', 'short_channel_id', 'created_at', 'amount', 'cancel_message', 'actions'];
}
this.swapsData = this.allSwapsData?.swapsCanceled || [];
break;
default:
break;
}
if (this.swapsData && this.swapsData.length > 0 && this.sort && this.paginator) {
this.loadswapsTable(this.swapsData);
}
}
onSwapClick(selSwap: Swap) {
const reorderedSwap = [
[{ key: 'id', value: selSwap.id, title: 'Swap Id', width: 100, type: DataTypeEnum.STRING }],
[{ key: 'state', value: this.swapStatePipe.transform(selSwap.state || ''), title: 'State', width: 50, type: DataTypeEnum.STRING },
{ key: 'role', value: this.titleCasePipe.transform(selSwap.role), title: 'Role', width: 50, type: DataTypeEnum.STRING }],
[{ key: 'alias', value: selSwap.alias, title: 'Alias', width: 50, type: DataTypeEnum.STRING },
{ key: 'short_channel_id', value: selSwap.short_channel_id, title: 'Short Channel ID', width: 50, type: DataTypeEnum.STRING }],
[{ key: 'amount', value: selSwap.amount, title: 'Amount (Sats)', width: 50, type: DataTypeEnum.NUMBER },
{ key: 'created_at', value: this.datePipe.transform(new Date(selSwap.created_at || ''), 'dd/MMM/YYYY HH:mm'), title: 'Created At', width: 50, type: DataTypeEnum.STRING }],
[{ key: 'peer_node_id', value: selSwap.peer_node_id, title: 'Peer Node Id', width: 100, type: DataTypeEnum.STRING }],
[{ key: 'initiator_node_id', value: selSwap.initiator_node_id, title: 'Initiator Node Id', width: 100, type: DataTypeEnum.STRING }]
];
if (selSwap.opening_tx_id) {
reorderedSwap.push([{ key: 'opening_tx_id', value: selSwap.opening_tx_id, title: 'Opening Transaction Id', width: 100, type: DataTypeEnum.STRING }]);
}
if (selSwap.claim_tx_id) {
reorderedSwap.push([{ key: 'claim_tx_id', value: selSwap.claim_tx_id, title: 'Claim Transaction Id', width: 100, type: DataTypeEnum.STRING }]);
}
if (selSwap.cancel_message) {
reorderedSwap.push([{ key: 'cancel_message', value: selSwap.cancel_message, title: 'Cancel Message', width: 100, type: DataTypeEnum.STRING }]);
}
this.store.dispatch(openAlert({
payload: {
data: {
type: AlertTypeEnum.INFORMATION,
alertTitle: this.selSwapList === this.swapLists[0] ? 'Swapout Information' : this.selSwapList === this.swapLists[1] ? 'Swapin Information' : 'Swap Canceled Information',
message: reorderedSwap
}
}
}));
}
loadswapsTable(swaps: Swap[]) {
this.swaps = new MatTableDataSource<Swap>([...swaps]);
this.swaps.sort = this.sort;
this.swaps.sortingDataAccessor = (data: any, sortHeaderId: string) => ((data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null);
this.swaps.filterPredicate = (swap: Swap, fltr: string) => {
const newSwap =
(swap.id ? swap.id : '') +
(swap.alias ? swap.alias.toLowerCase() : '') +
(swap.role ? swap.role : '') +
(swap.short_channel_id ? swap.short_channel_id : '') +
(swap.amount ? swap.amount : '') +
(swap.state ? swap.state : '') +
((swap.created_at) ? this.datePipe.transform(new Date(swap.created_at), 'dd/MMM/YYYY HH:mm')?.toLowerCase() : '') +
(swap.cancel_message ? swap.cancel_message.toLowerCase : '');
return newSwap?.includes(fltr) || false;
};
this.swaps.paginator = this.paginator;
this.applyFilter();
this.logger.info(this.swaps);
}
onSwapRefresh(selSwap: Swap) {
this.store.dispatch(getSwap({ payload: selSwap.id || '' }));
}
onDownloadCSV() {
if (this.swaps && this.swaps.data && this.swaps.data.length > 0) {
this.commonService.downloadFile(this.swaps.data, 'Peerswap-' + this.selSwapList);
}
}
applyFilter() {
this.swaps.filter = this.selFilter.trim().toLowerCase();
}
ngOnDestroy() {
this.unSubs.forEach((completeSub) => {
completeSub.next(<any>null);
completeSub.complete();
});
}
}

@ -1,39 +0,0 @@
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
import { SharedModule } from '../../../../shared/shared.module';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { PeerswapsOutComponent } from './swaps-out.component';
import { mockLoggerService } from '../../../../shared/test-helpers/mock-services';
import { LoggerService } from '../../../../shared/services/logger.service';
describe('PeerswapsOutComponent', () => {
let component: PeerswapsOutComponent;
let fixture: ComponentFixture<PeerswapsOutComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [PeerswapsOutComponent],
imports: [
BrowserAnimationsModule,
SharedModule
],
providers: [
{ provide: LoggerService, useClass: mockLoggerService }
]
}).
compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(PeerswapsOutComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
afterEach(() => {
TestBed.resetTestingModule();
});
});

@ -1,27 +0,0 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { LoggerService } from '../../../../shared/services/logger.service';
@Component({
selector: 'rtl-peer-swaps-out',
templateUrl: './swaps-out.component.html',
styleUrls: ['./swaps-out.component.scss']
})
export class PeerswapsOutComponent implements OnInit, OnDestroy {
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private logger: LoggerService) {}
ngOnInit() {
this.logger.info('Peerswap Out');
}
ngOnDestroy() {
this.unSubs.forEach((completeSub) => {
completeSub.next(<any>null);
completeSub.complete();
});
}
}

@ -6,7 +6,7 @@ import { StoreModule } from '@ngrx/store';
import { CommonService } from '../../../../../shared/services/common.service'; import { CommonService } from '../../../../../shared/services/common.service';
import { DataService } from '../../../../../shared/services/data.service'; import { DataService } from '../../../../../shared/services/data.service';
import { LoggerService } from '../../../../../shared/services/logger.service'; import { LoggerService } from '../../../../../shared/services/logger.service';
import { mockCLEffects, mockDataService, mockLoggerService, mockECLEffects, mockLNDEffects, mockRTLEffects, mockRouter } from '../../../../../shared/test-helpers/mock-services'; import { mockCLEffects, mockDataService, mockLoggerService, mockECLEffects, mockLNDEffects, mockRTLEffects } from '../../../../../shared/test-helpers/mock-services';
import { SharedModule } from '../../../../../shared/shared.module'; import { SharedModule } from '../../../../../shared/shared.module';
import { RTLEffects } from '../../../../../store/rtl.effects'; import { RTLEffects } from '../../../../../store/rtl.effects';
@ -16,7 +16,7 @@ import { CLNReducer } from '../../../../../cln/store/cln.reducers';
import { ECLReducer } from '../../../../../eclair/store/ecl.reducers'; import { ECLReducer } from '../../../../../eclair/store/ecl.reducers';
import { CLNEffects } from '../../../../store/cln.effects'; import { CLNEffects } from '../../../../store/cln.effects';
import { CLNChannelOpenTableComponent } from './channel-open-table.component'; import { CLNChannelOpenTableComponent } from './channel-open-table.component';
import { ExtraOptions, Route, Router } from '@angular/router'; import { Router } from '@angular/router';
describe('CLNChannelOpenTableComponent', () => { describe('CLNChannelOpenTableComponent', () => {
let component: CLNChannelOpenTableComponent; let component: CLNChannelOpenTableComponent;
@ -34,7 +34,6 @@ describe('CLNChannelOpenTableComponent', () => {
], ],
providers: [ providers: [
CommonService, CommonService,
{ provide: Router, useClass: mockRouter },
{ provide: LoggerService, useClass: mockLoggerService }, { provide: LoggerService, useClass: mockLoggerService },
{ provide: DataService, useClass: mockDataService }, { provide: DataService, useClass: mockDataService },
{ provide: RTLEffects, useClass: mockRTLEffects }, { provide: RTLEffects, useClass: mockRTLEffects },

@ -1,6 +1,6 @@
import { createAction, props } from '@ngrx/store'; import { createAction, props } from '@ngrx/store';
import { CLNActions } from '../../shared/services/consts-enums-functions'; import { CLNActions, SwapTypeEnum } from '../../shared/services/consts-enums-functions';
import { ApiCallStatusPayload } from '../../shared/models/apiCallsPayload'; import { ApiCallStatusPayload } from '../../shared/models/apiCallsPayload';
import { SelNodeChild } from '../../shared/models/RTLconfig'; import { SelNodeChild } from '../../shared/models/RTLconfig';
import { GetInfo, Fees, Peer, Payment, QueryRoutes, Channel, FeeRates, Invoice, ListInvoices, OnChain, UTXO, SaveChannel, GetNewAddress, DetachPeer, UpdateChannel, CloseChannel, SendPayment, GetQueryRoutes, ChannelLookup, OfferInvoice, Offer, OfferBookmark, ListForwards, FetchListForwards, LocalFailedEvent, ForwardingEvent, Swap, SwapPeer, SwapRequest } from '../../shared/models/clnModels'; import { GetInfo, Fees, Peer, Payment, QueryRoutes, Channel, FeeRates, Invoice, ListInvoices, OnChain, UTXO, SaveChannel, GetNewAddress, DetachPeer, UpdateChannel, CloseChannel, SendPayment, GetQueryRoutes, ChannelLookup, OfferInvoice, Offer, OfferBookmark, ListForwards, FetchListForwards, LocalFailedEvent, ForwardingEvent, Swap, SwapPeer, SwapRequest } from '../../shared/models/clnModels';
@ -143,10 +143,14 @@ export const fetchSwapRequests = createAction(CLNActions.FETCH_SWAP_REQUESTS_CLN
export const setSwapRequests = createAction(CLNActions.SET_SWAP_REQUESTS_CLN, props<{ payload: SwapRequest[] }>()); export const setSwapRequests = createAction(CLNActions.SET_SWAP_REQUESTS_CLN, props<{ payload: SwapRequest[] }>());
export const swapOut = createAction(CLNActions.SWAPOUT_CLN, props<{ payload: { amountSats: number, shortChannelId: string, asset: string } }>()); export const swapOut = createAction(CLNActions.SWAPOUT_CLN, props<{ payload: { alias: string, amountSats: number, shortChannelId: string, asset: string } }>());
export const addSwapout = createAction(CLNActions.ADD_SWAPOUT_CLN, props<{ payload: Swap }>()); export const addSwapout = createAction(CLNActions.ADD_SWAPOUT_CLN, props<{ payload: Swap }>());
export const swapIn = createAction(CLNActions.SWAPIN_CLN, props<{ payload: { amountSats: number, shortChannelId: string, asset: string } }>()); export const swapIn = createAction(CLNActions.SWAPIN_CLN, props<{ payload: { alias: string, amountSats: number, shortChannelId: string, asset: string } }>());
export const addSwapin = createAction(CLNActions.ADD_SWAPIN_CLN, props<{ payload: Swap }>()); export const addSwapin = createAction(CLNActions.ADD_SWAPIN_CLN, props<{ payload: Swap }>());
export const getSwap = createAction(CLNActions.GET_SWAP_CLN, props<{ payload: string }>());
export const updateSwapState = createAction(CLNActions.UPDATE_SWAP_STATE_CLN, props<{ payload: { swapId: string, state: string, type: SwapTypeEnum } }>());

@ -5,7 +5,7 @@ import { Store } from '@ngrx/store';
import { Actions, createEffect, ofType } from '@ngrx/effects'; import { Actions, createEffect, ofType } from '@ngrx/effects';
import { Subject, of } from 'rxjs'; import { Subject, of } from 'rxjs';
import { map, mergeMap, catchError, takeUntil } from 'rxjs/operators'; import { map, mergeMap, catchError, takeUntil } from 'rxjs/operators';
import { Location } from '@angular/common'; import { DatePipe, DecimalPipe, Location, TitleCasePipe } from '@angular/common';
import { environment, API_URL } from '../../../environments/environment'; import { environment, API_URL } from '../../../environments/environment';
import { LoggerService } from '../../shared/services/logger.service'; import { LoggerService } from '../../shared/services/logger.service';
@ -14,15 +14,16 @@ import { SessionService } from '../../shared/services/session.service';
import { WebSocketClientService } from '../../shared/services/web-socket.service'; import { WebSocketClientService } from '../../shared/services/web-socket.service';
import { ErrorMessageComponent } from '../../shared/components/data-modal/error-message/error-message.component'; import { ErrorMessageComponent } from '../../shared/components/data-modal/error-message/error-message.component';
import { CLNInvoiceInformationComponent } from '../transactions/invoices/invoice-information-modal/invoice-information.component'; import { CLNInvoiceInformationComponent } from '../transactions/invoices/invoice-information-modal/invoice-information.component';
import { GetInfo, Fees, Balance, LocalRemoteBalance, Payment, FeeRates, ListInvoices, Invoice, Peer, OnChain, QueryRoutes, SaveChannel, GetNewAddress, DetachPeer, UpdateChannel, CloseChannel, SendPayment, GetQueryRoutes, ChannelLookup, FetchInvoices, Channel, OfferInvoice, Offer, ListForwards, FetchListForwards, ForwardingEvent, LocalFailedEvent, Swap } from '../../shared/models/clnModels'; import { GetInfo, Fees, Balance, LocalRemoteBalance, Payment, FeeRates, ListInvoices, Invoice, Peer, OnChain, QueryRoutes, SaveChannel, GetNewAddress, DetachPeer, UpdateChannel, CloseChannel, SendPayment, GetQueryRoutes, ChannelLookup, FetchInvoices, Channel, OfferInvoice, Offer, ListForwards, FetchListForwards, ForwardingEvent, LocalFailedEvent, Swap, ActiveSwap } from '../../shared/models/clnModels';
import { AlertTypeEnum, APICallStatusEnum, UI_MESSAGES, CLNWSEventTypeEnum, CLNActions, RTLActions, CLNForwardingEventsStatusEnum, DataTypeEnum } from '../../shared/services/consts-enums-functions'; import { AlertTypeEnum, APICallStatusEnum, UI_MESSAGES, CLNWSEventTypeEnum, CLNActions, RTLActions, CLNForwardingEventsStatusEnum, DataTypeEnum, SwapTypeEnum } from '../../shared/services/consts-enums-functions';
import { closeAllDialogs, closeSpinner, logout, openAlert, openSnackBar, openSpinner, setApiUrl, setNodeData } from '../../store/rtl.actions'; import { closeAllDialogs, closeSpinner, logout, openAlert, openSnackBar, openSpinner, setApiUrl, setNodeData } from '../../store/rtl.actions';
import { RTLState } from '../../store/rtl.state'; import { RTLState } from '../../store/rtl.state';
import { addUpdateOfferBookmark, fetchBalance, fetchChannels, fetchFeeRates, fetchFees, fetchInvoices, fetchLocalRemoteBalance, fetchPayments, fetchPeers, fetchUTXOs, getForwardingHistory, setLookup, setPeers, setQueryRoutes, updateCLAPICallStatus, updateInvoice, setOfferInvoice, sendPaymentStatus, setForwardingHistory } from './cln.actions'; import { addUpdateOfferBookmark, fetchBalance, fetchChannels, fetchFeeRates, fetchFees, fetchInvoices, fetchLocalRemoteBalance, fetchPayments, fetchPeers, fetchUTXOs, getForwardingHistory, setLookup, setPeers, setQueryRoutes, updateCLAPICallStatus, updateInvoice, setOfferInvoice, sendPaymentStatus, setForwardingHistory } from './cln.actions';
import { allAPIsCallStatus, clnNodeInformation } from './cln.selector'; import { allAPIsCallStatus } from './cln.selector';
import { ApiCallsListCL } from '../../shared/models/apiCallsPayload'; import { ApiCallsListCL } from '../../shared/models/apiCallsPayload';
import { CLNOfferInformationComponent } from '../transactions/offers/offer-information-modal/offer-information.component'; import { CLNOfferInformationComponent } from '../transactions/offers/offer-information-modal/offer-information.component';
import { SwapStatePipe } from '../../shared/pipes/app.pipe';
@Injectable() @Injectable()
export class CLNEffects implements OnDestroy { export class CLNEffects implements OnDestroy {
@ -40,7 +41,11 @@ export class CLNEffects implements OnDestroy {
private logger: LoggerService, private logger: LoggerService,
private router: Router, private router: Router,
private wsService: WebSocketClientService, private wsService: WebSocketClientService,
private location: Location private location: Location,
private swapStatePipe: SwapStatePipe,
private titleCasePipe: TitleCasePipe,
private decimalPipe: DecimalPipe,
private datePipe: DatePipe
) { ) {
this.store.select(allAPIsCallStatus).pipe(takeUntil(this.unSubs[0])).subscribe((allApisCallStatus: ApiCallsListCL) => { this.store.select(allAPIsCallStatus).pipe(takeUntil(this.unSubs[0])).subscribe((allApisCallStatus: ApiCallsListCL) => {
if ( if (
@ -934,6 +939,25 @@ export class CLNEffects implements OnDestroy {
}) })
)); ));
swapGetCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.GET_SWAP_CLN),
mergeMap((action: { type: string, payload: string }) => {
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'GetSwap', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get(this.CHILD_API_URL + environment.PEERSWAP_API + '/swap/' + action.payload).
pipe(map((swapRes: ActiveSwap) => {
this.logger.info(swapRes);
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'GetSwap', status: APICallStatusEnum.COMPLETED } }));
return {
type: CLNActions.UPDATE_SWAP_STATE_CLN,
payload: { swapId: action.payload, state: swapRes.current, type: swapRes.type === 1 ? SwapTypeEnum.SWAP_IN : SwapTypeEnum.SWAP_OUT }
};
}), catchError((err: any) => {
this.handleErrorWithoutAlert('GetSwap', UI_MESSAGES.NO_SPINNER, 'Getting Swap Failed.', err);
return of({ type: RTLActions.VOID });
}));
})
));
swapsFetchCL = createEffect(() => this.actions.pipe( swapsFetchCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.FETCH_SWAPS_CLN), ofType(CLNActions.FETCH_SWAPS_CLN),
mergeMap((action: { type: string, payload: any }) => { mergeMap((action: { type: string, payload: any }) => {
@ -985,7 +1009,7 @@ export class CLNEffects implements OnDestroy {
payload: res || [] payload: res || []
}; };
}), catchError((err: any) => { }), catchError((err: any) => {
this.handleErrorWithoutAlert('FetchSwaps', UI_MESSAGES.NO_SPINNER, 'Fetching Swap Requests Failed.', err); this.handleErrorWithoutAlert('FetchSwapRequests', UI_MESSAGES.NO_SPINNER, 'Fetching Swap Requests Failed.', err);
return of({ type: RTLActions.VOID }); return of({ type: RTLActions.VOID });
})); }));
}) })
@ -993,13 +1017,14 @@ export class CLNEffects implements OnDestroy {
peerswapOutCL = createEffect(() => this.actions.pipe( peerswapOutCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.SWAPOUT_CLN), ofType(CLNActions.SWAPOUT_CLN),
mergeMap((action: { type: string, payload: { amountSats: number, shortChannelId: string, asset: string } }) => { mergeMap((action: { type: string, payload: { alias: string, amountSats: number, shortChannelId: string, asset: string } }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.PEERSWAP_SWAPOUT })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.PEERSWAP_SWAPOUT }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'PeerswapSwapout', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'PeerswapSwapout', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.post(this.CHILD_API_URL + environment.PEERSWAP_API + '/swapOut', { return this.httpClient.post(this.CHILD_API_URL + environment.PEERSWAP_API + '/swapOut', {
amountSats: action.payload.amountSats, shortChannelId: action.payload.shortChannelId, asset: action.payload.asset amountSats: action.payload.amountSats, shortChannelId: action.payload.shortChannelId, asset: action.payload.asset
}).pipe(map((postRes: Swap) => { }).pipe(map((postRes: Swap) => {
this.logger.info(postRes); this.logger.info(postRes);
postRes.alias = action.payload.alias;
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.PEERSWAP_SWAPOUT })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.PEERSWAP_SWAPOUT }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'PeerswapSwapout', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'PeerswapSwapout', status: APICallStatusEnum.COMPLETED } }));
setTimeout(() => { setTimeout(() => {
@ -1008,7 +1033,7 @@ export class CLNEffects implements OnDestroy {
data: { data: {
type: AlertTypeEnum.INFORMATION, type: AlertTypeEnum.INFORMATION,
alertTitle: 'Swapout Initiated', alertTitle: 'Swapout Initiated',
message: postRes.id message: this.reorderedSwapResponse(postRes)
} }
} }
})); }));
@ -1027,13 +1052,14 @@ export class CLNEffects implements OnDestroy {
peerswapInCL = createEffect(() => this.actions.pipe( peerswapInCL = createEffect(() => this.actions.pipe(
ofType(CLNActions.SWAPIN_CLN), ofType(CLNActions.SWAPIN_CLN),
mergeMap((action: { type: string, payload: { amountSats: number, shortChannelId: string, asset: string } }) => { mergeMap((action: { type: string, payload: { alias: string, amountSats: number, shortChannelId: string, asset: string } }) => {
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.PEERSWAP_SWAPIN })); this.store.dispatch(openSpinner({ payload: UI_MESSAGES.PEERSWAP_SWAPIN }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'PeerswapSwapin', status: APICallStatusEnum.INITIATED } })); this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'PeerswapSwapin', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.post(this.CHILD_API_URL + environment.PEERSWAP_API + '/swapIn', { return this.httpClient.post(this.CHILD_API_URL + environment.PEERSWAP_API + '/swapIn', {
amountSats: action.payload.amountSats, shortChannelId: action.payload.shortChannelId, asset: action.payload.asset amountSats: action.payload.amountSats, shortChannelId: action.payload.shortChannelId, asset: action.payload.asset
}).pipe(map((postRes: Swap) => { }).pipe(map((postRes: Swap) => {
this.logger.info(postRes); this.logger.info(postRes);
postRes.alias = action.payload.alias;
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.PEERSWAP_SWAPIN })); this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.PEERSWAP_SWAPIN }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'PeerswapSwapin', status: APICallStatusEnum.COMPLETED } })); this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'PeerswapSwapin', status: APICallStatusEnum.COMPLETED } }));
setTimeout(() => { setTimeout(() => {
@ -1042,7 +1068,7 @@ export class CLNEffects implements OnDestroy {
data: { data: {
type: AlertTypeEnum.INFORMATION, type: AlertTypeEnum.INFORMATION,
alertTitle: 'Swapin Initiated', alertTitle: 'Swapin Initiated',
message: [{ key: 'id', value: postRes.id, title: 'Swap Id', width: 100, type: DataTypeEnum.STRING }] message: this.reorderedSwapResponse(postRes)
} }
} }
})); }));
@ -1059,6 +1085,30 @@ export class CLNEffects implements OnDestroy {
}) })
)); ));
reorderedSwapResponse(swapRes: Swap) {
const reorderedSwap = [
[{ key: 'id', value: swapRes.id, title: 'Swap Id', width: 100, type: DataTypeEnum.STRING }],
[{ key: 'state', value: this.swapStatePipe.transform(swapRes.state || ''), title: 'State', width: 50, type: DataTypeEnum.STRING },
{ key: 'role', value: this.titleCasePipe.transform(swapRes.role), title: 'Role', width: 50, type: DataTypeEnum.STRING }],
[{ key: 'alias', value: swapRes.alias, title: 'Alias', width: 50, type: DataTypeEnum.STRING },
{ key: 'short_channel_id', value: swapRes.short_channel_id, title: 'Short Channel ID', width: 50, type: DataTypeEnum.STRING }],
[{ key: 'amount', value: this.decimalPipe.transform(swapRes.amount), title: 'Amount (Sats)', width: 50, type: DataTypeEnum.STRING },
{ key: 'created_at', value: this.datePipe.transform(new Date(swapRes.created_at || ''), 'dd/MMM/YYYY HH:mm'), title: 'Created At', width: 50, type: DataTypeEnum.STRING }],
[{ key: 'peer_node_id', value: swapRes.peer_node_id, title: 'Peer Node Id', width: 100, type: DataTypeEnum.STRING }],
[{ key: 'initiator_node_id', value: swapRes.initiator_node_id, title: 'Initiator Node Id', width: 100, type: DataTypeEnum.STRING }]
];
if (swapRes.opening_tx_id) {
reorderedSwap.push([{ key: 'opening_tx_id', value: swapRes.opening_tx_id, title: 'Opening Transaction Id', width: 100, type: DataTypeEnum.STRING }]);
}
if (swapRes.claim_tx_id) {
reorderedSwap.push([{ key: 'claim_tx_id', value: swapRes.claim_tx_id, title: 'Claim Transaction Id', width: 100, type: DataTypeEnum.STRING }]);
}
if (swapRes.cancel_message) {
reorderedSwap.push([{ key: 'cancel_message', value: swapRes.cancel_message, title: 'Cancel Message', width: 100, type: DataTypeEnum.STRING }]);
}
return reorderedSwap;
}
initializeRemainingData(info: any, landingPage: string) { initializeRemainingData(info: any, landingPage: string) {
this.sessionService.setItem('clUnlocked', 'true'); this.sessionService.setItem('clUnlocked', 'true');
const node_data = { const node_data = {

@ -5,10 +5,10 @@ import {
setChildNodeSettingsCL, setFeeRates, setFees, setForwardingHistory, setChildNodeSettingsCL, setFeeRates, setFees, setForwardingHistory,
setInfo, setInvoices, setLocalRemoteBalance, setOffers, addOffer, setPayments, setPeers, setUTXOs, setInfo, setInvoices, setLocalRemoteBalance, setOffers, addOffer, setPayments, setPeers, setUTXOs,
updateCLAPICallStatus, updateInvoice, updateOffer, setOfferBookmarks, addUpdateOfferBookmark, removeOfferBookmark, updateCLAPICallStatus, updateInvoice, updateOffer, setOfferBookmarks, addUpdateOfferBookmark, removeOfferBookmark,
setSwaps, setSwapPeers, setSwapRequests, addSwapout, addSwapin setSwaps, setSwapPeers, setSwapRequests, addSwapout, addSwapin, updateSwapState
} from './cln.actions'; } from './cln.actions';
import { Channel, OfferBookmark, Swap } from '../../shared/models/clnModels'; import { Channel, OfferBookmark, Swap } from '../../shared/models/clnModels';
import { CLNForwardingEventsStatusEnum, PeerswapTypes } from '../../shared/services/consts-enums-functions'; import { CLNForwardingEventsStatusEnum, PeerswapTypes, SwapTypeEnum } from '../../shared/services/consts-enums-functions';
export const CLNReducer = createReducer(initCLNState, export const CLNReducer = createReducer(initCLNState,
on(updateCLAPICallStatus, (state, { payload }) => { on(updateCLAPICallStatus, (state, { payload }) => {
@ -221,19 +221,51 @@ export const CLNReducer = createReducer(initCLNState,
on(setSwaps, (state, { payload }) => { on(setSwaps, (state, { payload }) => {
const swapOutArr: Swap[] = []; const swapOutArr: Swap[] = [];
const swapInArr: Swap[] = []; const swapInArr: Swap[] = [];
payload.forEach((swap) => { const swapCanceledArr: Swap[] = [];
if (swap.type === PeerswapTypes.SWAP_OUT) { for (let i = (payload.length - 1); i >= 0; i--) {
swapOutArr.push(swap); payload[i].alias = state.peers?.find((peer) => peer.id === payload[i].peer_node_id)?.alias || payload[i].peer_node_id;
if (payload[i].state === 'State_SwapCanceled') {
swapCanceledArr.push(payload[i]);
} else { } else {
swapInArr.push(swap); if (payload[i].type === PeerswapTypes.SWAP_OUT) {
swapOutArr.push(payload[i]);
} else {
swapInArr.push(payload[i]);
}
} }
}); }
return { return {
...state, ...state,
swapOuts: swapOutArr, swapOuts: swapOutArr,
swapIns: swapInArr swapIns: swapInArr,
swapsCanceled: swapCanceledArr
}; };
}), }),
on(updateSwapState, (state, { payload }) => {
if (payload.type === SwapTypeEnum.SWAP_IN) {
const updatedSwapIns = [...state.swapIns];
const foundSwapIdx = updatedSwapIns.findIndex((swapIn) => (swapIn.id === payload.swapId));
if (foundSwapIdx > -1) {
updatedSwapIns[foundSwapIdx].state = payload.state;
}
return {
...state,
swapIns: updatedSwapIns
};
}
if (payload.type === SwapTypeEnum.SWAP_OUT) {
const updatedSwapOuts = [...state.swapOuts];
const foundSwapIdx = updatedSwapOuts.findIndex((swapOut) => (swapOut.id === payload.swapId));
if (foundSwapIdx > -1) {
updatedSwapOuts[foundSwapIdx].state = payload.state;
}
return {
...state,
swapOuts: updatedSwapOuts
};
}
return { ...state };
}),
on(setSwapRequests, (state, { payload }) => ({ on(setSwapRequests, (state, { payload }) => ({
...state, ...state,
swapRequests: payload swapRequests: payload

@ -27,7 +27,6 @@ export const nodeInfoAndNodeSettingsAndAPIsStatus = createSelector(clnState, (st
export const offers = createSelector(clnState, (state: CLNState) => ({ offers: state.offers, apiCallStatus: state.apisCallStatus.FetchOffers })); export const offers = createSelector(clnState, (state: CLNState) => ({ offers: state.offers, apiCallStatus: state.apisCallStatus.FetchOffers }));
export const offerBookmarks = createSelector(clnState, (state: CLNState) => ({ offersBookmarks: state.offersBookmarks, apiCallStatus: state.apisCallStatus.FetchOfferBookmarks })); export const offerBookmarks = createSelector(clnState, (state: CLNState) => ({ offersBookmarks: state.offersBookmarks, apiCallStatus: state.apisCallStatus.FetchOfferBookmarks }));
export const getoffer = (bolt12Str) => createSelector(clnState, (state: CLNState) => (state.offers.find((offer: Offer) => offer.bolt12 === bolt12Str))); export const getoffer = (bolt12Str) => createSelector(clnState, (state: CLNState) => (state.offers.find((offer: Offer) => offer.bolt12 === bolt12Str)));
export const swapOuts = createSelector(clnState, (state: CLNState) => ({ swapOuts: state.swapOuts, apiCallStatus: state.apisCallStatus.FetchSwaps })); export const swaps = createSelector(clnState, (state: CLNState) => ({ swapOuts: state.swapOuts, swapIns: state.swapIns, swapsCanceled: state.swapsCanceled, apiCallStatus: state.apisCallStatus.FetchSwaps }));
export const swapIns = createSelector(clnState, (state: CLNState) => ({ swapIns: state.swapIns, apiCallStatus: state.apisCallStatus.FetchSwaps }));
export const swapPeers = createSelector(clnState, (state: CLNState) => ({ totalSwapPeers: state.totalSwapPeers, swapPeers: state.swapPeers, apiCallStatus: state.apisCallStatus.FetchSwapPeers })); export const swapPeers = createSelector(clnState, (state: CLNState) => ({ totalSwapPeers: state.totalSwapPeers, swapPeers: state.swapPeers, apiCallStatus: state.apisCallStatus.FetchSwapPeers }));
export const swapRequests = createSelector(clnState, (state: CLNState) => ({ swapRequests: state.swapRequests, apiCallStatus: state.apisCallStatus.FetchSwapRequests })); export const swapRequests = createSelector(clnState, (state: CLNState) => ({ swapRequests: state.swapRequests, apiCallStatus: state.apisCallStatus.FetchSwapRequests }));

@ -28,6 +28,7 @@ export interface CLNState {
swapPeers: SwapPeerChannelsFlattened[]; swapPeers: SwapPeerChannelsFlattened[];
swapOuts: Swap[]; swapOuts: Swap[];
swapIns: Swap[]; swapIns: Swap[];
swapsCanceled: Swap[];
swapRequests: SwapRequest[]; swapRequests: SwapRequest[];
} }
@ -76,5 +77,6 @@ export const initCLNState: CLNState = {
swapPeers: [], swapPeers: [],
swapOuts: [], swapOuts: [],
swapIns: [], swapIns: [],
swapsCanceled: [],
swapRequests: [] swapRequests: []
}; };

@ -51,7 +51,7 @@ export const EclRoutes: Routes = [
{ path: 'inactive', component: ECLChannelInactiveTableComponent, canActivate: [ECLUnlockedGuard] } { path: 'inactive', component: ECLChannelInactiveTableComponent, canActivate: [ECLUnlockedGuard] }
] ]
}, },
{ path: 'peers', component: ECLPeersComponent, data: { sweepAll: false }, canActivate: [ECLUnlockedGuard] } { path: 'peers', component: ECLPeersComponent, canActivate: [ECLUnlockedGuard] }
] ]
}, },
{ {

@ -11,7 +11,7 @@ import { CommonService } from '../../../../../shared/services/common.service';
import { LoggerService } from '../../../../../shared/services/logger.service'; import { LoggerService } from '../../../../../shared/services/logger.service';
import { ECLChannelOpenTableComponent } from './channel-open-table.component'; import { ECLChannelOpenTableComponent } from './channel-open-table.component';
import { mockDataService, mockLoggerService, mockRouter, mockRTLEffects } from '../../../../../shared/test-helpers/mock-services'; import { mockDataService, mockLoggerService, mockRTLEffects } from '../../../../../shared/test-helpers/mock-services';
import { RTLEffects } from '../../../../../store/rtl.effects'; import { RTLEffects } from '../../../../../store/rtl.effects';
import { SharedModule } from '../../../../../shared/shared.module'; import { SharedModule } from '../../../../../shared/shared.module';
import { DataService } from '../../../../../shared/services/data.service'; import { DataService } from '../../../../../shared/services/data.service';
@ -32,7 +32,6 @@ describe('ECLChannelOpenTableComponent', () => {
], ],
providers: [ providers: [
CommonService, CommonService,
{ provide: Router, useClass: mockRouter },
{ provide: LoggerService, useClass: mockLoggerService }, { provide: LoggerService, useClass: mockLoggerService },
{ provide: DataService, useClass: mockDataService }, { provide: DataService, useClass: mockDataService },
{ provide: RTLEffects, useClass: mockRTLEffects } { provide: RTLEffects, useClass: mockRTLEffects }

@ -69,7 +69,7 @@ export const LndRoutes: Routes = [
{ path: 'activehtlcs', component: ChannelActiveHTLCsTableComponent, canActivate: [LNDUnlockedGuard] } { path: 'activehtlcs', component: ChannelActiveHTLCsTableComponent, canActivate: [LNDUnlockedGuard] }
] ]
}, },
{ path: 'peers', component: PeersComponent, data: { sweepAll: false }, canActivate: [LNDUnlockedGuard] } { path: 'peers', component: PeersComponent, canActivate: [LNDUnlockedGuard] }
] ]
}, },
{ {

@ -12,7 +12,7 @@ import { LoopService } from '../../../../../shared/services/loop.service';
import { ChannelOpenTableComponent } from './channel-open-table.component'; import { ChannelOpenTableComponent } from './channel-open-table.component';
import { SharedModule } from '../../../../../shared/shared.module'; import { SharedModule } from '../../../../../shared/shared.module';
import { mockDataService, mockLoggerService, mockLNDEffects, mockRTLEffects, mockRouter } from '../../../../../shared/test-helpers/mock-services'; import { mockDataService, mockLoggerService, mockLNDEffects, mockRTLEffects } from '../../../../../shared/test-helpers/mock-services';
import { RTLEffects } from '../../../../../store/rtl.effects'; import { RTLEffects } from '../../../../../store/rtl.effects';
import { LNDEffects } from '../../../../store/lnd.effects'; import { LNDEffects } from '../../../../store/lnd.effects';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@ -34,7 +34,6 @@ describe('ChannelOpenTableComponent', () => {
], ],
providers: [ providers: [
CommonService, LoopService, CommonService, LoopService,
{ provide: Router, useClass: mockRouter },
{ provide: LoggerService, useClass: mockLoggerService }, { provide: LoggerService, useClass: mockLoggerService },
{ provide: DataService, useClass: mockDataService }, { provide: DataService, useClass: mockDataService },
{ provide: RTLEffects, useClass: mockRTLEffects }, { provide: RTLEffects, useClass: mockRTLEffects },

@ -117,7 +117,7 @@
<span fxFlex="60" class="foreground-secondary-text"> <span fxFlex="60" class="foreground-secondary-text">
<span *ngIf="htlc.state === 'SETTLED'" class="dot green" matTooltip="Settled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span> <span *ngIf="htlc.state === 'SETTLED'" class="dot green" matTooltip="Settled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="htlc.state === 'ACCEPTED'" class="dot yellow" matTooltip="Accepted" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span> <span *ngIf="htlc.state === 'ACCEPTED'" class="dot yellow" matTooltip="Accepted" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="htlc.state === 'CANCELED'" class="dot red" matTooltip="Cancelled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span> <span *ngIf="htlc.state === 'CANCELED'" class="dot red" matTooltip="Canceled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
{{htlc.chan_id}} {{htlc.chan_id}}
</span> </span>
<span fxFlex="40" class="foreground-secondary-text">{{((+htlc.amt_msat/1000) || 0) | number:getDecimalFormat(htlc)}}</span> <span fxFlex="40" class="foreground-secondary-text">{{((+htlc.amt_msat/1000) || 0) | number:getDecimalFormat(htlc)}}</span>

@ -35,7 +35,7 @@
<span *ngIf="invoice?.state === 'OPEN'" class="dot grey" matTooltip="Open" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span> <span *ngIf="invoice?.state === 'OPEN'" class="dot grey" matTooltip="Open" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="invoice?.state === 'SETTLED'" class="dot green" matTooltip="Settled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span> <span *ngIf="invoice?.state === 'SETTLED'" class="dot green" matTooltip="Settled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="invoice?.state === 'ACCEPTED'" class="dot yellow" matTooltip="Accepted" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span> <span *ngIf="invoice?.state === 'ACCEPTED'" class="dot yellow" matTooltip="Accepted" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="invoice?.state === 'CANCELED'" class="dot red" matTooltip="Cancelled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span> <span *ngIf="invoice?.state === 'CANCELED'" class="dot red" matTooltip="Canceled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
{{(invoice?.creation_date * 1000) | date:'dd/MMM/y HH:mm'}}</td> {{(invoice?.creation_date * 1000) | date:'dd/MMM/y HH:mm'}}</td>
</ng-container> </ng-container>
<ng-container matColumnDef="settle_date"> <ng-container matColumnDef="settle_date">

@ -98,7 +98,7 @@
<span fxFlex="60" class="foreground-secondary-text"> <span fxFlex="60" class="foreground-secondary-text">
<span *ngIf="htlc.state === 'SETTLED'" class="dot green" matTooltip="Settled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span> <span *ngIf="htlc.state === 'SETTLED'" class="dot green" matTooltip="Settled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="htlc.state === 'ACCEPTED'" class="dot yellow" matTooltip="Accepted" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span> <span *ngIf="htlc.state === 'ACCEPTED'" class="dot yellow" matTooltip="Accepted" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
<span *ngIf="htlc.state === 'CANCELED'" class="dot red" matTooltip="Cancelled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span> <span *ngIf="htlc.state === 'CANCELED'" class="dot red" matTooltip="Canceled" matTooltipPosition="right" [ngClass]="{'mr-0': screenSize === screenSizeEnum.XS}"></span>
{{htlc.chan_id}} {{htlc.chan_id}}
</span> </span>
<span fxFlex="40" class="foreground-secondary-text">{{((+htlc.amt_msat/1000) || 0) | number:getDecimalFormat(htlc)}}</span> <span fxFlex="40" class="foreground-secondary-text">{{((+htlc.amt_msat/1000) || 0) | number:getDecimalFormat(htlc)}}</span>

@ -163,9 +163,9 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
clonedMenu = JSON.parse(JSON.stringify(MENU_DATA.LNDChildren)); clonedMenu = JSON.parse(JSON.stringify(MENU_DATA.LNDChildren));
this.navMenus.data = clonedMenu?.filter((navMenuData: any) => { this.navMenus.data = clonedMenu?.filter((navMenuData: any) => {
if (navMenuData.children && navMenuData.children.length) { if (navMenuData.children && navMenuData.children.length) {
navMenuData.children = navMenuData.children?.filter((navMenuChild) => ((navMenuChild.userPersona === UserPersonaEnum.ALL || navMenuChild.userPersona === this.settings?.userPersona) && navMenuChild.link !== '/services/loop' && navMenuChild.link !== '/services/boltz') || navMenuData.children = navMenuData.children?.filter((navMenuChild) => ((navMenuChild.userPersona === UserPersonaEnum.ALL || navMenuChild.userPersona === this.settings?.userPersona) && navMenuChild.link !== '/lnd/services/loop' && navMenuChild.link !== '/lnd/services/boltz') ||
(navMenuChild.link === '/services/loop' && this.settings?.swapServerUrl && this.settings.swapServerUrl.trim() !== '') || (navMenuChild.link === '/lnd/services/loop' && this.settings?.swapServerUrl && this.settings.swapServerUrl.trim() !== '') ||
(navMenuChild.link === '/services/boltz' && this.settings?.boltzServerUrl && this.settings.boltzServerUrl.trim() !== '')); (navMenuChild.link === '/lnd/services/boltz' && this.settings?.boltzServerUrl && this.settings.boltzServerUrl.trim() !== ''));
return navMenuData.children.length > 0; return navMenuData.children.length > 0;
} }
return navMenuData.userPersona === UserPersonaEnum.ALL || navMenuData.userPersona === this.settings?.userPersona; return navMenuData.userPersona === UserPersonaEnum.ALL || navMenuData.userPersona === this.settings?.userPersona;
@ -177,8 +177,8 @@ export class SideNavigationComponent implements OnInit, OnDestroy {
clonedMenu = JSON.parse(JSON.stringify(MENU_DATA.CLNChildren)); clonedMenu = JSON.parse(JSON.stringify(MENU_DATA.CLNChildren));
this.navMenus.data = clonedMenu?.filter((navMenuData: any) => { this.navMenus.data = clonedMenu?.filter((navMenuData: any) => {
if (navMenuData.children && navMenuData.children.length) { if (navMenuData.children && navMenuData.children.length) {
navMenuData.children = navMenuData.children?.filter((navMenuChild) => ((navMenuChild.userPersona === UserPersonaEnum.ALL || navMenuChild.userPersona === this.settings?.userPersona) && navMenuChild.link !== '/services/peerswap') || navMenuData.children = navMenuData.children?.filter((navMenuChild) => ((navMenuChild.userPersona === UserPersonaEnum.ALL || navMenuChild.userPersona === this.settings?.userPersona) && navMenuChild.link !== '/cln/services/peerswap') ||
(navMenuChild.link === '/services/peerswap' && this.settings?.enablePeerswap)); (navMenuChild.link === '/cln/services/peerswap' && this.settings?.enablePeerswap));
return navMenuData.children.length > 0; return navMenuData.children.length > 0;
} }
return navMenuData.userPersona === UserPersonaEnum.ALL || navMenuData.userPersona === this.settings?.userPersona; return navMenuData.userPersona === UserPersonaEnum.ALL || navMenuData.userPersona === this.settings?.userPersona;

@ -1,7 +1,7 @@
<div [perfectScrollbar] fxLayout="column" fxFlex="100"> <div [perfectScrollbar] fxLayout="column" fxFlex="100">
<div fxFlex="100" class="alert alert-info mt-1"> <div fxFlex="100" class="alert alert-info mt-1">
<fa-icon [icon]="faInfoCircle" class="mr-1 alert-icon"></fa-icon> <fa-icon [icon]="faInfoCircle" class="mr-1 alert-icon"></fa-icon>
<span>Please ensure that <strong>peerswapd</strong> is running and accessible to RTL before enabling this service. Click <strong><a href="https://www.peerswap.dev/" target="_blank">here</a></strong> to learn more about peerswap.</span> <span>Please ensure that <strong>peerswap</strong> plugin is running and accessible to RTL before enabling this service. Click <strong><a href="https://www.peerswap.dev/" target="_blank">here</a></strong> to learn more about peerswap.</span>
</div> </div>
<form fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch" class="settings-container page-sub-title-container mt-1" #form="ngForm"> <form fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch" class="settings-container page-sub-title-container mt-1" #form="ngForm">
<div fxLayout="column" fxFlex="50" fxLayoutAlign="start stretch"> <div fxLayout="column" fxFlex="50" fxLayoutAlign="start stretch">

@ -579,6 +579,7 @@ export interface SwapRequest {
export interface Swap { export interface Swap {
id?: string; id?: string;
alias?: string;
asset?: string; asset?: string;
created_at?: string; created_at?: string;
type?: string; type?: string;

@ -21,3 +21,14 @@ export class CamelCasePipe implements PipeTransform {
} }
} }
@Pipe({
name: 'swapState'
})
export class SwapStatePipe implements PipeTransform {
transform(value: string, args?: any): string {
return value?.replace('State_', '').replace('SwapInSender_', '').replace('SwapOutSender_', '').replace('SwapInReceiver_', '').replace('SwapOutReceiver_', '').replace('_', ' ').replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => ' ' + word);
}
}

@ -333,11 +333,6 @@ export enum PaymentTypes {
KEYSEND = 'KEYSEND' KEYSEND = 'KEYSEND'
} }
export enum PeerswapTypes {
SWAP_OUT = 'swap-out',
SWAP_IN = 'swap-in'
}
export enum ReportBy { export enum ReportBy {
FEES = 'FEES', FEES = 'FEES',
EVENTS = 'EVENTS' EVENTS = 'EVENTS'
@ -532,6 +527,8 @@ export enum CLNActions {
SET_SWAP_PEERS_CLN = 'SET_SWAP_PEERS_CLN', SET_SWAP_PEERS_CLN = 'SET_SWAP_PEERS_CLN',
FETCH_SWAP_REQUESTS_CLN = 'FETCH_SWAP_REQUESTS_CLN', FETCH_SWAP_REQUESTS_CLN = 'FETCH_SWAP_REQUESTS_CLN',
SET_SWAP_REQUESTS_CLN = 'SET_SWAP_REQUESTS_CLN', SET_SWAP_REQUESTS_CLN = 'SET_SWAP_REQUESTS_CLN',
GET_SWAP_CLN = 'GET_SWAP_CLN',
UPDATE_SWAP_STATE_CLN = 'UPDATE_SWAP_STATE_CLN',
SWAPOUT_CLN = 'SWAPOUT_CLN', SWAPOUT_CLN = 'SWAPOUT_CLN',
ADD_SWAPOUT_CLN = 'ADD_SWAPOUT_CLN', ADD_SWAPOUT_CLN = 'ADD_SWAPOUT_CLN',
SWAPIN_CLN = 'SWAPIN_CLN', SWAPIN_CLN = 'SWAPIN_CLN',
@ -650,3 +647,17 @@ export enum CLNForwardingEventsStatusEnum {
FAILED = 'failed', FAILED = 'failed',
LOCAL_FAILED = 'local_failed' LOCAL_FAILED = 'local_failed'
} }
export enum PeerswapTypes {
SWAP_OUT = 'swap-out',
SWAP_IN = 'swap-in'
}
export enum PeerswapRoles {
SENDER = 'sender',
RECEIVER = 'receiver'
}
export enum PeerswapStates {
SWAP_CANCELED = 'State_SwapCanceled'
}

@ -85,7 +85,7 @@ import { AutoFocusDirective } from './directive/auto-focus.directive';
import { MonthlyDateDirective, YearlyDateDirective } from './directive/date-formats.directive'; import { MonthlyDateDirective, YearlyDateDirective } from './directive/date-formats.directive';
import { MaxValidator } from './directive/max-amount.directive'; import { MaxValidator } from './directive/max-amount.directive';
import { MinValidator } from './directive/min-amount.directive'; import { MinValidator } from './directive/min-amount.directive';
import { RemoveLeadingZerosPipe, CamelCasePipe } from './pipes/app.pipe'; import { RemoveLeadingZerosPipe, CamelCasePipe, SwapStatePipe } from './pipes/app.pipe';
const DEFAULT_PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = { const DEFAULT_PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
suppressScrollX: false, suppressScrollX: false,
@ -210,6 +210,7 @@ export const DEFAULT_DATE_FORMAT: MatDateFormats = {
YearlyDateDirective, YearlyDateDirective,
RemoveLeadingZerosPipe, RemoveLeadingZerosPipe,
CamelCasePipe, CamelCasePipe,
SwapStatePipe,
MaxValidator, MaxValidator,
MinValidator, MinValidator,
AppSettingsComponent, AppSettingsComponent,
@ -266,6 +267,7 @@ export const DEFAULT_DATE_FORMAT: MatDateFormats = {
MinValidator, MinValidator,
RemoveLeadingZerosPipe, RemoveLeadingZerosPipe,
CamelCasePipe, CamelCasePipe,
SwapStatePipe,
AuthSettingsComponent, AuthSettingsComponent,
TransactionsReportTableComponent, TransactionsReportTableComponent,
OnChainGeneratedAddressComponent, OnChainGeneratedAddressComponent,
@ -286,7 +288,7 @@ export const DEFAULT_DATE_FORMAT: MatDateFormats = {
{ provide: DateAdapter, useClass: DefaultDateAdapter }, { provide: DateAdapter, useClass: DefaultDateAdapter },
{ provide: MAT_DATE_FORMATS, useValue: DEFAULT_DATE_FORMAT }, { provide: MAT_DATE_FORMATS, useValue: DEFAULT_DATE_FORMAT },
{ provide: OverlayContainer, useClass: ThemeOverlay }, { provide: OverlayContainer, useClass: ThemeOverlay },
DecimalPipe, TitleCasePipe, DatePipe DecimalPipe, TitleCasePipe, DatePipe, SwapStatePipe
] ]
}) })
export class SharedModule { } export class SharedModule { }

@ -28,20 +28,6 @@ export class mockHttpClient {
} }
export class mockRouter {
getCurrentNavigation() {
return {
extras: {
state: {
filter: 'DummyChannelID4325565432212367867'
}
}
};
};
}
export class mockDataService { export class mockDataService {
private lnImplementation = 'LND'; private lnImplementation = 'LND';

Loading…
Cancel
Save