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) => {
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);
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;
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);
}).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 });
});
};

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>
<body>
<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>

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) => {
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);
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;
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);
}).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 });
});
};

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

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

@ -4,7 +4,6 @@ import { Subject } from 'rxjs';
import { takeUntil, filter } from 'rxjs/operators';
import { faHandshake } from '@fortawesome/free-solid-svg-icons';
@Component({
selector: 'rtl-peerswap',
templateUrl: './peerswap.component.html',
@ -13,7 +12,7 @@ import { faHandshake } from '@fortawesome/free-solid-svg-icons';
export class PeerswapComponent implements OnInit, OnDestroy {
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];
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];

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

@ -57,7 +57,7 @@ export class CLNSwapInModalComponent implements OnInit, OnDestroy {
onExecuteSwapin(): boolean | void {
this.swapInError = '';
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() {

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

@ -57,7 +57,7 @@ export class CLNSwapOutModalComponent implements OnInit, OnDestroy {
onExecuteSwapout(): boolean | void {
this.swapOutError = '';
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() {

@ -22,17 +22,9 @@
<th mat-header-cell *matHeaderCellDef mat-sort-header>Node Alias</th>
<td mat-cell *matCellDef="let sPeer">{{sPeer?.alias}}</td>
</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">
<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 matColumnDef="local_balance">
<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 {
min-height: 4.8rem;
}

@ -1,6 +1,5 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { DatePipe } from '@angular/common';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
@ -50,7 +49,7 @@ export class SwapPeersComponent implements OnInit, OnDestroy {
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) {
constructor(private logger: LoggerService, private commonService: CommonService, private store: Store<RTLState>) {
this.screenSize = this.commonService.getScreenSize();
if (this.screenSize === ScreenSizeEnum.XS) {
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'];
} else {
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() {
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.onSameUrlNavigation = 'reload';
this.store.dispatch(fetchSwapPeers());
this.store.select(swapPeers).pipe(takeUntil(this.unSubs[0])).
subscribe((spSeletor: { totalSwapPeers: number, swapPeers: SwapPeerChannelsFlattened[], apiCallStatus: ApiCallStatusPayload }) => {
@ -88,7 +85,6 @@ export class SwapPeersComponent implements OnInit, OnDestroy {
}
onSwapPeerClick(selSPeer: SwapPeerChannelsFlattened) {
this.logger.warn(selSPeer);
const reorderedSPeer = [
[{ 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 },
@ -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: '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: 'swaps_allowed', value: selSPeer.swaps_allowed ? 'Allowed' : 'Denied', title: 'Swaps Allowed', width: 30, type: DataTypeEnum.STRING },
{ key: 'total_channels', value: selSPeer.channels?.length, title: 'Channels Opened', width: 30, type: DataTypeEnum.NUMBER }],
{ 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 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_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_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_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 }]
];
this.store.dispatch(openAlert({
@ -148,7 +144,7 @@ export class SwapPeersComponent implements OnInit, OnDestroy {
const newSPeer =
(sPeer.nodeid ? sPeer.nodeid : '') +
(sPeer.alias ? sPeer.alias.toLowerCase() : '') +
(sPeer.swaps_allowed ? 'allowed' : 'denied') +
(sPeer.swaps_allowed ? 'yes' : 'no') +
(sPeer.short_channel_id ? sPeer.short_channel_id : '') +
(sPeer.local_balance ? sPeer.local_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 { DataService } from '../../../../../shared/services/data.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 { RTLEffects } from '../../../../../store/rtl.effects';
@ -16,7 +16,7 @@ import { CLNReducer } from '../../../../../cln/store/cln.reducers';
import { ECLReducer } from '../../../../../eclair/store/ecl.reducers';
import { CLNEffects } from '../../../../store/cln.effects';
import { CLNChannelOpenTableComponent } from './channel-open-table.component';
import { ExtraOptions, Route, Router } from '@angular/router';
import { Router } from '@angular/router';
describe('CLNChannelOpenTableComponent', () => {
let component: CLNChannelOpenTableComponent;
@ -34,7 +34,6 @@ describe('CLNChannelOpenTableComponent', () => {
],
providers: [
CommonService,
{ provide: Router, useClass: mockRouter },
{ provide: LoggerService, useClass: mockLoggerService },
{ provide: DataService, useClass: mockDataService },
{ provide: RTLEffects, useClass: mockRTLEffects },

@ -1,6 +1,6 @@
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 { 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';
@ -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 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 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 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 { Subject, of } from 'rxjs';
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 { 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 { ErrorMessageComponent } from '../../shared/components/data-modal/error-message/error-message.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 { AlertTypeEnum, APICallStatusEnum, UI_MESSAGES, CLNWSEventTypeEnum, CLNActions, RTLActions, CLNForwardingEventsStatusEnum, DataTypeEnum } from '../../shared/services/consts-enums-functions';
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, SwapTypeEnum } from '../../shared/services/consts-enums-functions';
import { closeAllDialogs, closeSpinner, logout, openAlert, openSnackBar, openSpinner, setApiUrl, setNodeData } from '../../store/rtl.actions';
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 { allAPIsCallStatus, clnNodeInformation } from './cln.selector';
import { allAPIsCallStatus } from './cln.selector';
import { ApiCallsListCL } from '../../shared/models/apiCallsPayload';
import { CLNOfferInformationComponent } from '../transactions/offers/offer-information-modal/offer-information.component';
import { SwapStatePipe } from '../../shared/pipes/app.pipe';
@Injectable()
export class CLNEffects implements OnDestroy {
@ -40,7 +41,11 @@ export class CLNEffects implements OnDestroy {
private logger: LoggerService,
private router: Router,
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) => {
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(
ofType(CLNActions.FETCH_SWAPS_CLN),
mergeMap((action: { type: string, payload: any }) => {
@ -985,7 +1009,7 @@ export class CLNEffects implements OnDestroy {
payload: res || []
};
}), 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 });
}));
})
@ -993,13 +1017,14 @@ export class CLNEffects implements OnDestroy {
peerswapOutCL = createEffect(() => this.actions.pipe(
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(updateCLAPICallStatus({ payload: { action: 'PeerswapSwapout', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.post(this.CHILD_API_URL + environment.PEERSWAP_API + '/swapOut', {
amountSats: action.payload.amountSats, shortChannelId: action.payload.shortChannelId, asset: action.payload.asset
}).pipe(map((postRes: Swap) => {
this.logger.info(postRes);
postRes.alias = action.payload.alias;
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.PEERSWAP_SWAPOUT }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'PeerswapSwapout', status: APICallStatusEnum.COMPLETED } }));
setTimeout(() => {
@ -1008,7 +1033,7 @@ export class CLNEffects implements OnDestroy {
data: {
type: AlertTypeEnum.INFORMATION,
alertTitle: 'Swapout Initiated',
message: postRes.id
message: this.reorderedSwapResponse(postRes)
}
}
}));
@ -1027,13 +1052,14 @@ export class CLNEffects implements OnDestroy {
peerswapInCL = createEffect(() => this.actions.pipe(
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(updateCLAPICallStatus({ payload: { action: 'PeerswapSwapin', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.post(this.CHILD_API_URL + environment.PEERSWAP_API + '/swapIn', {
amountSats: action.payload.amountSats, shortChannelId: action.payload.shortChannelId, asset: action.payload.asset
}).pipe(map((postRes: Swap) => {
this.logger.info(postRes);
postRes.alias = action.payload.alias;
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.PEERSWAP_SWAPIN }));
this.store.dispatch(updateCLAPICallStatus({ payload: { action: 'PeerswapSwapin', status: APICallStatusEnum.COMPLETED } }));
setTimeout(() => {
@ -1042,7 +1068,7 @@ export class CLNEffects implements OnDestroy {
data: {
type: AlertTypeEnum.INFORMATION,
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) {
this.sessionService.setItem('clUnlocked', 'true');
const node_data = {

@ -5,10 +5,10 @@ import {
setChildNodeSettingsCL, setFeeRates, setFees, setForwardingHistory,
setInfo, setInvoices, setLocalRemoteBalance, setOffers, addOffer, setPayments, setPeers, setUTXOs,
updateCLAPICallStatus, updateInvoice, updateOffer, setOfferBookmarks, addUpdateOfferBookmark, removeOfferBookmark,
setSwaps, setSwapPeers, setSwapRequests, addSwapout, addSwapin
setSwaps, setSwapPeers, setSwapRequests, addSwapout, addSwapin, updateSwapState
} from './cln.actions';
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,
on(updateCLAPICallStatus, (state, { payload }) => {
@ -221,19 +221,51 @@ export const CLNReducer = createReducer(initCLNState,
on(setSwaps, (state, { payload }) => {
const swapOutArr: Swap[] = [];
const swapInArr: Swap[] = [];
payload.forEach((swap) => {
if (swap.type === PeerswapTypes.SWAP_OUT) {
swapOutArr.push(swap);
const swapCanceledArr: Swap[] = [];
for (let i = (payload.length - 1); i >= 0; i--) {
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 {
swapInArr.push(swap);
if (payload[i].type === PeerswapTypes.SWAP_OUT) {
swapOutArr.push(payload[i]);
} else {
swapInArr.push(payload[i]);
}
}
});
}
return {
...state,
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 }) => ({
...state,
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 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 swapOuts = createSelector(clnState, (state: CLNState) => ({ swapOuts: state.swapOuts, apiCallStatus: state.apisCallStatus.FetchSwaps }));
export const swapIns = createSelector(clnState, (state: CLNState) => ({ swapIns: state.swapIns, 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 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 }));

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

@ -51,7 +51,7 @@ export const EclRoutes: Routes = [
{ 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 { 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 { SharedModule } from '../../../../../shared/shared.module';
import { DataService } from '../../../../../shared/services/data.service';
@ -32,7 +32,6 @@ describe('ECLChannelOpenTableComponent', () => {
],
providers: [
CommonService,
{ provide: Router, useClass: mockRouter },
{ provide: LoggerService, useClass: mockLoggerService },
{ provide: DataService, useClass: mockDataService },
{ provide: RTLEffects, useClass: mockRTLEffects }

@ -69,7 +69,7 @@ export const LndRoutes: Routes = [
{ 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 { 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 { LNDEffects } from '../../../../store/lnd.effects';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@ -34,7 +34,6 @@ describe('ChannelOpenTableComponent', () => {
],
providers: [
CommonService, LoopService,
{ provide: Router, useClass: mockRouter },
{ provide: LoggerService, useClass: mockLoggerService },
{ provide: DataService, useClass: mockDataService },
{ provide: RTLEffects, useClass: mockRTLEffects },

@ -117,7 +117,7 @@
<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 === '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}}
</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 === '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 === '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>
</ng-container>
<ng-container matColumnDef="settle_date">

@ -98,7 +98,7 @@
<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 === '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}}
</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));
this.navMenus.data = clonedMenu?.filter((navMenuData: any) => {
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') ||
(navMenuChild.link === '/services/loop' && this.settings?.swapServerUrl && this.settings.swapServerUrl.trim() !== '') ||
(navMenuChild.link === '/services/boltz' && this.settings?.boltzServerUrl && this.settings.boltzServerUrl.trim() !== ''));
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 === '/lnd/services/loop' && this.settings?.swapServerUrl && this.settings.swapServerUrl.trim() !== '') ||
(navMenuChild.link === '/lnd/services/boltz' && this.settings?.boltzServerUrl && this.settings.boltzServerUrl.trim() !== ''));
return navMenuData.children.length > 0;
}
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));
this.navMenus.data = clonedMenu?.filter((navMenuData: any) => {
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') ||
(navMenuChild.link === '/services/peerswap' && this.settings?.enablePeerswap));
navMenuData.children = navMenuData.children?.filter((navMenuChild) => ((navMenuChild.userPersona === UserPersonaEnum.ALL || navMenuChild.userPersona === this.settings?.userPersona) && navMenuChild.link !== '/cln/services/peerswap') ||
(navMenuChild.link === '/cln/services/peerswap' && this.settings?.enablePeerswap));
return navMenuData.children.length > 0;
}
return navMenuData.userPersona === UserPersonaEnum.ALL || navMenuData.userPersona === this.settings?.userPersona;

@ -1,7 +1,7 @@
<div [perfectScrollbar] fxLayout="column" fxFlex="100">
<div fxFlex="100" class="alert alert-info mt-1">
<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>
<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">

@ -579,6 +579,7 @@ export interface SwapRequest {
export interface Swap {
id?: string;
alias?: string;
asset?: string;
created_at?: 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'
}
export enum PeerswapTypes {
SWAP_OUT = 'swap-out',
SWAP_IN = 'swap-in'
}
export enum ReportBy {
FEES = 'FEES',
EVENTS = 'EVENTS'
@ -532,6 +527,8 @@ export enum CLNActions {
SET_SWAP_PEERS_CLN = 'SET_SWAP_PEERS_CLN',
FETCH_SWAP_REQUESTS_CLN = 'FETCH_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',
ADD_SWAPOUT_CLN = 'ADD_SWAPOUT_CLN',
SWAPIN_CLN = 'SWAPIN_CLN',
@ -650,3 +647,17 @@ export enum CLNForwardingEventsStatusEnum {
FAILED = '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 { MaxValidator } from './directive/max-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 = {
suppressScrollX: false,
@ -210,6 +210,7 @@ export const DEFAULT_DATE_FORMAT: MatDateFormats = {
YearlyDateDirective,
RemoveLeadingZerosPipe,
CamelCasePipe,
SwapStatePipe,
MaxValidator,
MinValidator,
AppSettingsComponent,
@ -266,6 +267,7 @@ export const DEFAULT_DATE_FORMAT: MatDateFormats = {
MinValidator,
RemoveLeadingZerosPipe,
CamelCasePipe,
SwapStatePipe,
AuthSettingsComponent,
TransactionsReportTableComponent,
OnChainGeneratedAddressComponent,
@ -286,7 +288,7 @@ export const DEFAULT_DATE_FORMAT: MatDateFormats = {
{ provide: DateAdapter, useClass: DefaultDateAdapter },
{ provide: MAT_DATE_FORMATS, useValue: DEFAULT_DATE_FORMAT },
{ provide: OverlayContainer, useClass: ThemeOverlay },
DecimalPipe, TitleCasePipe, DatePipe
DecimalPipe, TitleCasePipe, DatePipe, SwapStatePipe
]
})
export class SharedModule { }

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

Loading…
Cancel
Save