CLT Bump Fee (#764)

CLT Bump Fee (#718 )
pull/769/head
violet360 3 years ago committed by GitHub
parent 24b006519f
commit 0b383e95a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

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.dbd56bd3357dc3617fe5.woff2) format("woff2"),url(Roboto-Thin.e7f7c82374bd0ebef14b.woff) format("woff");font-weight:100;font-style:normal;}@font-face{font-family:Roboto;src:url(Roboto-ThinItalic.a8cef84f735ef887abdc.woff2) format("woff2"),url(Roboto-ThinItalic.5dd9349c940073834e9a.woff) format("woff");font-weight:100;font-style:italic;}@font-face{font-family:Roboto;src:url(Roboto-Light.c27d89ac77468ae18f28.woff2) format("woff2"),url(Roboto-Light.d923dfafc0c5183b59aa.woff) format("woff");font-weight:300;font-style:normal;}@font-face{font-family:Roboto;src:url(Roboto-LightItalic.506274c7228cf81cae4d.woff2) format("woff2"),url(Roboto-LightItalic.d4b8c137518d9d92bb28.woff) format("woff");font-weight:300;font-style:italic;}@font-face{font-family:Roboto;src:url(Roboto-Regular.64cfb66c866ea50cad47.woff2) format("woff2"),url(Roboto-Regular.e02e9d6ff5547f7e9962.woff) format("woff");font-weight:400;font-style:normal;}@font-face{font-family:Roboto;src:url(Roboto-RegularItalic.4dd2af1e8df532f41db8.woff2) format("woff2"),url(Roboto-RegularItalic.5ea38fff9eebef99c5df.woff) format("woff");font-weight:400;font-style:italic;}@font-face{font-family:Roboto;src:url(Roboto-Medium.1d3bced88509b0838984.woff2) format("woff2"),url(Roboto-Medium.092c6130df8fd2199888.woff) format("woff");font-weight:500;font-style:normal;}@font-face{font-family:Roboto;src:url(Roboto-MediumItalic.d620b8f53f75966fe42e.woff2) format("woff2"),url(Roboto-MediumItalic.18ff1628c628080166c1.woff) format("woff");font-weight:500;font-style:italic;}@font-face{font-family:Roboto;src:url(Roboto-Bold.92fbd4e93cf0a5dbebaa.woff2) format("woff2"),url(Roboto-Bold.73288d91c325e82a5b92.woff) format("woff");font-weight:700;font-style:normal;}@font-face{font-family:Roboto;src:url(Roboto-BoldItalic.5f600d98a73d800ae575.woff2) format("woff2"),url(Roboto-BoldItalic.6d89acbd21d7e3fbecb2.woff) format("woff");font-weight:700;font-style:italic;}@font-face{font-family:Roboto;src:url(Roboto-Black.41ed1105a6ebb8ffe34e.woff2) format("woff2"),url(Roboto-Black.937491dfcbe64ca9a9f1.woff) format("woff");font-weight:900;font-style:normal;}@font-face{font-family:Roboto;src:url(Roboto-BlackItalic.50ca4c51ebc27e7e7d2f.woff2) format("woff2"),url(Roboto-BlackItalic.2e1ee657996854c6f427.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;margin:0;}body{height:100%;overflow:hidden;}*{margin:0;padding:0;}</style><link rel="stylesheet" href="styles.50804d64c130486c55c1.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles.50804d64c130486c55c1.css"></noscript></head>
<body>
<rtl-app></rtl-app>
<script src="runtime.66074bbdb000b1878581.js" defer></script><script src="polyfills.a979cbbe16939013cdcf.js" defer></script><script src="main.0635c89ff4b48a013963.js" defer></script>
<script src="runtime.5cb8a29a4caa173b621b.js" defer></script><script src="polyfills.a979cbbe16939013cdcf.js" defer></script><script src="main.01f216b035f2e4e22e3f.js" defer></script>
</body></html>

File diff suppressed because one or more lines are too long

@ -1 +1 @@
(()=>{"use strict";var e,r,t,a={},o={};function n(e){var r=o[e];if(void 0!==r)return r.exports;var t=o[e]={id:e,loaded:!1,exports:{}};return a[e].call(t.exports,t,t.exports,n),t.loaded=!0,t.exports}n.m=a,e=[],n.O=(r,t,a,o)=>{if(!t){var l=1/0;for(s=0;s<e.length;s++){for(var[t,a,o]=e[s],d=!0,i=0;i<t.length;i++)(!1&o||l>=o)&&Object.keys(n.O).every(e=>n.O[e](t[i]))?t.splice(i--,1):(d=!1,o<l&&(l=o));d&&(e.splice(s--,1),r=a())}return r}o=o||0;for(var s=e.length;s>0&&e[s-1][2]>o;s--)e[s]=e[s-1];e[s]=[t,a,o]},n.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return n.d(r,{a:r}),r},n.d=(e,r)=>{for(var t in r)n.o(r,t)&&!n.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce((r,t)=>(n.f[t](e,r),r),[])),n.u=e=>e+"."+{432:"a6d92c45cf6d18d2ceaa",891:"f50ed5ee955e9ad8b4cf",918:"f9485c36a5f074dfe7ba",958:"a55d8156c48e68ddc825"}[e]+".js",n.miniCssF=e=>"styles.50804d64c130486c55c1.css",n.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},t="rtl:",n.l=(e,a,o,l)=>{if(r[e])r[e].push(a);else{var d,i;if(void 0!==o)for(var s=document.getElementsByTagName("script"),u=0;u<s.length;u++){var c=s[u];if(c.getAttribute("src")==e||c.getAttribute("data-webpack")==t+o){d=c;break}}d||(i=!0,(d=document.createElement("script")).charset="utf-8",d.timeout=120,n.nc&&d.setAttribute("nonce",n.nc),d.setAttribute("data-webpack",t+o),d.src=e),r[e]=[a];var f=(t,a)=>{d.onerror=d.onload=null,clearTimeout(p);var o=r[e];if(delete r[e],d.parentNode&&d.parentNode.removeChild(d),o&&o.forEach(e=>e(a)),t)return t(a)},p=setTimeout(f.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=f.bind(null,d.onerror),d.onload=f.bind(null,d.onload),i&&document.head.appendChild(d)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),n.p="",(()=>{var e={666:0};n.f.j=(r,t)=>{var a=n.o(e,r)?e[r]:void 0;if(0!==a)if(a)t.push(a[2]);else if(666!=r){var o=new Promise((t,o)=>a=e[r]=[t,o]);t.push(a[2]=o);var l=n.p+n.u(r),d=new Error;n.l(l,t=>{if(n.o(e,r)&&(0!==(a=e[r])&&(e[r]=void 0),a)){var o=t&&("load"===t.type?"missing":t.type),l=t&&t.target&&t.target.src;d.message="Loading chunk "+r+" failed.\n("+o+": "+l+")",d.name="ChunkLoadError",d.type=o,d.request=l,a[1](d)}},"chunk-"+r,r)}else e[r]=0},n.O.j=r=>0===e[r];var r=(r,t)=>{var a,o,[l,d,i]=t,s=0;for(a in d)n.o(d,a)&&(n.m[a]=d[a]);if(i)var u=i(n);for(r&&r(t);s<l.length;s++)n.o(e,o=l[s])&&e[o]&&e[o][0](),e[l[s]]=0;return n.O(u)},t=self.webpackChunkrtl=self.webpackChunkrtl||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})()})();
(()=>{"use strict";var e,r,t,a={},o={};function n(e){var r=o[e];if(void 0!==r)return r.exports;var t=o[e]={id:e,loaded:!1,exports:{}};return a[e].call(t.exports,t,t.exports,n),t.loaded=!0,t.exports}n.m=a,e=[],n.O=(r,t,a,o)=>{if(!t){var l=1/0;for(s=0;s<e.length;s++){for(var[t,a,o]=e[s],i=!0,d=0;d<t.length;d++)(!1&o||l>=o)&&Object.keys(n.O).every(e=>n.O[e](t[d]))?t.splice(d--,1):(i=!1,o<l&&(l=o));i&&(e.splice(s--,1),r=a())}return r}o=o||0;for(var s=e.length;s>0&&e[s-1][2]>o;s--)e[s]=e[s-1];e[s]=[t,a,o]},n.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return n.d(r,{a:r}),r},n.d=(e,r)=>{for(var t in r)n.o(r,t)&&!n.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce((r,t)=>(n.f[t](e,r),r),[])),n.u=e=>e+"."+{145:"ece30118af5d019172a0",432:"cc664c98c4074918e24a",891:"0b4a7fadb75c2e9cf113",958:"88b5fa8d3b93e7a0e7b3"}[e]+".js",n.miniCssF=e=>"styles.50804d64c130486c55c1.css",n.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},t="rtl:",n.l=(e,a,o,l)=>{if(r[e])r[e].push(a);else{var i,d;if(void 0!==o)for(var s=document.getElementsByTagName("script"),u=0;u<s.length;u++){var c=s[u];if(c.getAttribute("src")==e||c.getAttribute("data-webpack")==t+o){i=c;break}}i||(d=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,n.nc&&i.setAttribute("nonce",n.nc),i.setAttribute("data-webpack",t+o),i.src=e),r[e]=[a];var f=(t,a)=>{i.onerror=i.onload=null,clearTimeout(p);var o=r[e];if(delete r[e],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach(e=>e(a)),t)return t(a)},p=setTimeout(f.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=f.bind(null,i.onerror),i.onload=f.bind(null,i.onload),d&&document.head.appendChild(i)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),n.p="",(()=>{var e={666:0};n.f.j=(r,t)=>{var a=n.o(e,r)?e[r]:void 0;if(0!==a)if(a)t.push(a[2]);else if(666!=r){var o=new Promise((t,o)=>a=e[r]=[t,o]);t.push(a[2]=o);var l=n.p+n.u(r),i=new Error;n.l(l,t=>{if(n.o(e,r)&&(0!==(a=e[r])&&(e[r]=void 0),a)){var o=t&&("load"===t.type?"missing":t.type),l=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+o+": "+l+")",i.name="ChunkLoadError",i.type=o,i.request=l,a[1](i)}},"chunk-"+r,r)}else e[r]=0},n.O.j=r=>0===e[r];var r=(r,t)=>{var a,o,[l,i,d]=t,s=0;for(a in i)n.o(i,a)&&(n.m[a]=i[a]);if(d)var u=d(n);for(r&&r(t);s<l.length;s++)n.o(e,o=l[s])&&e[o]&&e[o][0](),e[l[s]]=0;return n.O(u)},t=self.webpackChunkrtl=self.webpackChunkrtl||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})()})();

@ -26,6 +26,7 @@ import { CLNodeLookupComponent } from './lookups/node-lookup/node-lookup.compone
import { CLQueryRoutesComponent } from './transactions/query-routes/query-routes.component';
import { CLChannelOpenTableComponent } from './peers-channels/channels/channels-tables/channel-open-table/channel-open-table.component';
import { CLChannelPendingTableComponent } from './peers-channels/channels/channels-tables/channel-pending-table/channel-pending-table.component';
import { CLBumpFeeComponent } from './peers-channels/channels/bump-fee-modal/bump-fee.component';
import { CLNodeInfoComponent } from './home/node-info/node-info.component';
import { CLBalancesInfoComponent } from './home/balances-info/balances-info.component';
import { CLFeeInfoComponent } from './home/fee-info/fee-info.component';
@ -81,6 +82,7 @@ import { CLUnlockedGuard } from '../shared/services/auth.guard';
CLChannelsTablesComponent,
CLChannelOpenTableComponent,
CLChannelPendingTableComponent,
CLBumpFeeComponent,
CLNodeInfoComponent,
CLBalancesInfoComponent,
CLFeeInfoComponent,

@ -0,0 +1,53 @@
<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">Bump Fee</span>
</div>
<button tabindex="8" fxFlex="5" fxLayoutAlign="center" class="btn-close-x p-0" (click)="onClose()" mat-button>X</button>
</mat-card-header>
<mat-card-content class="padding-gap-x-large">
<form fxLayout="column">
<div fxLayout="column" class="bordered-box mb-1 p-2">
<p fxLayoutAlign="start center" class="pb-1 word-break">Bump fee for channel point: {{bumpFeeChannel?.funding_txid}}
<fa-icon class="ml-1" [icon]="faCopy" matSuffix rtlClipboard [payload]="bumpFeeChannel?.funding_txid" (copied)="onCopyID($event)" matTooltip="Copy transaction ID"></fa-icon>
</p>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch">
<div fxFlex="100" class="alert alert-info">
<fa-icon [icon]="faInfoCircle" class="mr-1 alert-icon"></fa-icon>
<span fxLayout="column" fxFlex="100">Bumping fee on pending open channels is an advanced feature, attempt it only if you are familiar with the functionality of Bitcoin transactions.
<div>Before attempting fee bump ensure the following:</div>
<div class="pl-1">1: Use a Bitcoin block explorer to ensure that channel opening transaction is not confirmed.</div>
<div class="pl-1">2: The channel opening transaction must have a sizable change output, which can be spent further. The fee cannot be bumped without the change output.</div>
<div class="pl-1">3: Find the index value of the change output via a block explorer.</div>
<div class="pl-1">4: Enter the index value of the change output in the form below and the desired fee rate.</div>
<div class="pl-1">5: Upon successful fee bump, use your block explorer to track the child transaction in the mempool, which should be linked with the change output transaction.</div>
</span>
</div>
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between center">
<mat-form-field fxFlex="49">
<input autoFocus matInput [(ngModel)]="outputIndex" placeholder="Output Index" type="number" [step]="1" [min]="0" tabindex="1" required name="outputIdx" #outputIdx="ngModel">
<mat-error *ngIf="outputIdx.errors?.required">Output Index required.</mat-error>
<mat-error *ngIf="outputIdx.errors?.pendingChannelOutputIndex">Invalid index value.</mat-error>
</mat-form-field>
<mat-form-field fxFlex="49">
<input matInput [(ngModel)]="fees" placeholder="Fees (Sats/vByte)"
type="number" name="fees" [step]="1" [min]="0" required tabindex="4" #fee="ngModel">
<mat-error *ngIf="!fees">Fees is required.</mat-error>
</mat-form-field>
</div>
<div fxFlex="100" class="alert alert-danger mt-1" *ngIf="bumpFeeError !== ''">
<fa-icon [icon]="faExclamationTriangle" class="mr-1 alert-icon"></fa-icon>
<span>{{bumpFeeError}}</span>
</div>
</div>
</div>
<div fxLayout="row" fxLayoutAlign="end center">
<button mat-stroked-button color="primary" type="reset" class="mr-1" (click)="resetData()" tabindex="5" default>Clear</button>
<button mat-flat-button color="primary" type="submit" tabindex="6" (click)="onBumpFee()">{{bumpFeeError !== '' ? 'Retry Bump Fee' : 'Bump Fee'}}</button>
</div>
</form>
</mat-card-content>
</div>
</div>

@ -0,0 +1,51 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { EffectsModule } from '@ngrx/effects';
import { StoreModule } from '@ngrx/store';
import { DataService } from '../../../../shared/services/data.service';
import { LoggerService } from '../../../../shared/services/logger.service';
import { SharedModule } from '../../../../shared/shared.module';
import { mockCLEffects, mockDataService, mockECLEffects, mockLNDEffects, mockLoggerService, mockMatDialogRef, mockRTLEffects } from '../../../../shared/test-helpers/mock-services';
import { RTLReducer } from '../../../../store/rtl.reducers';
import { CLBumpFeeComponent } from './bump-fee.component';
describe('CLBumpFeeComponent', () => {
let component: CLBumpFeeComponent;
let fixture: ComponentFixture<CLBumpFeeComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [CLBumpFeeComponent],
imports: [
BrowserAnimationsModule,
SharedModule,
StoreModule.forRoot(RTLReducer, {
runtimeChecks: {
strictStateImmutability: false,
strictActionImmutability: false
}
}),
EffectsModule.forRoot([mockRTLEffects, mockLNDEffects, mockCLEffects, mockECLEffects])
],
providers: [
{ provide: LoggerService, useClass: mockLoggerService },
{ provide: MatDialogRef, useClass: mockMatDialogRef },
{ provide: MAT_DIALOG_DATA, useValue: { channel: {} } },
{ provide: DataService, useClass: mockDataService }
]
}).
compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(CLBumpFeeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

@ -0,0 +1,101 @@
import { Component, OnInit, OnDestroy, ViewChild, Inject } from '@angular/core';
import { NgModel } from '@angular/forms';
import { Subject } from 'rxjs';
import { filter, take } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { faCopy, faInfoCircle, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Channel } from '../../../../shared/models/clModels';
import { CLChannelInformation } from '../../../../shared/models/alertData';
import { ADDRESS_TYPES, APICallStatusEnum } from '../../../../shared/services/consts-enums-functions';
import { LoggerService } from '../../../../shared/services/logger.service';
import * as CLActions from '../../../store/cl.actions';
import * as RTLActions from '../../../../store/rtl.actions';
import * as fromRTLReducer from '../../../../store/rtl.reducers';
@Component({
selector: 'rtl-cl-bump-fee',
templateUrl: './bump-fee.component.html',
styleUrls: ['./bump-fee.component.scss']
})
export class CLBumpFeeComponent implements OnInit, OnDestroy {
private outputIdx: NgModel;
@ViewChild('outputIdx') set payReq(outIdx: NgModel) {
if (outIdx) {
this.outputIdx = outIdx;
}
}
public newAddress = '';
public bumpFeeChannel: Channel;
public fees = null;
public outputIndex = null;
public faCopy = faCopy;
public faInfoCircle = faInfoCircle;
public faExclamationTriangle = faExclamationTriangle;
public bumpFeeError = '';
private unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
constructor(private actions: Actions, public dialogRef: MatDialogRef<CLBumpFeeComponent>, @Inject(MAT_DIALOG_DATA) public data: CLChannelInformation, private store: Store<fromRTLReducer.RTLState>, private logger: LoggerService, private snackBar: MatSnackBar) { }
ngOnInit() {
this.bumpFeeChannel = this.data.channel;
}
onBumpFee(): boolean | void {
if ((!this.outputIndex && this.outputIndex !== 0) || !this.fees) {
return true;
}
this.bumpFeeError = '';
this.store.dispatch(new CLActions.GetNewAddress(ADDRESS_TYPES[0]));
this.actions.pipe(
filter((action) => action.type === CLActions.SET_NEW_ADDRESS_CL || action.type === CLActions.SET_CHANNEL_TRANSACTION_RES_CL || action.type === CLActions.UPDATE_API_CALL_STATUS_CL),
take(3)).
subscribe((action: (CLActions.SetNewAddress | CLActions.SetChannelTransactionRes | CLActions.UpdateAPICallStatus)) => {
if (action.type === CLActions.SET_NEW_ADDRESS_CL) {
this.store.dispatch(new CLActions.SetChannelTransaction({
address: action.payload,
satoshis: 'all',
feeRate: this.fees,
utxos: [this.bumpFeeChannel.funding_txid + ':' + this.outputIndex.toString()]
}));
}
if (action.type === CLActions.SET_CHANNEL_TRANSACTION_RES_CL) {
this.store.dispatch(new RTLActions.OpenSnackBar('Successfully bumped the fee. Use the block explorer to verify transaction.'));
this.dialogRef.close();
}
if (action.type === CLActions.UPDATE_API_CALL_STATUS_CL && action.payload.status === APICallStatusEnum.ERROR && (action.payload.action === 'SetChannelTransaction' || action.payload.action === 'GenerateNewAddress')) {
this.logger.error(action.payload.message);
this.bumpFeeError = action.payload.message;
}
});
}
onCopyID(payload: string) {
this.snackBar.open('Transaction ID copied.');
}
resetData() {
this.bumpFeeError = '';
this.fees = null;
this.outputIndex = null;
this.outputIdx.control.setErrors(null);
}
onClose() {
this.dialogRef.close(false);
}
ngOnDestroy() {
this.unSubs.forEach((completeSub) => {
completeSub.next(null);
completeSub.complete();
});
}
}

@ -26,7 +26,7 @@
</ng-container>
<ng-container matColumnDef="state">
<th mat-header-cell *matHeaderCellDef mat-sort-header> State </th>
<td mat-cell *matCellDef="let channel"> {{channel?.state}}</td>
<td mat-cell *matCellDef="let channel" [ngStyle]="{'max-width': (screenSize === screenSizeEnum.XS) ? '10rem' : ''}"> {{CLChannelPendingState[channel?.state]}} </td>
</ng-container>
<ng-container matColumnDef="msatoshi_to_us">
<th mat-header-cell *matHeaderCellDef mat-sort-header arrowPosition="before"> mSatoshi To Us </th>
@ -58,6 +58,7 @@
<mat-select-trigger></mat-select-trigger>
<mat-option (click)="onChannelClick(channel, $event)">View Info</mat-option>
<mat-option (click)="onChannelClose(channel)" *ngIf="isCompatibleVersion && !channel.connected && channel.state === 'CHANNELD_NORMAL'">Close Channel</mat-option>
<mat-option (click)="onBumpFee(channel)" *ngIf="channel.state === 'CHANNELD_AWAITING_LOCKIN'">Bump Fee</mat-option>
</mat-select>
</div>
</td>

@ -1,3 +1,12 @@
@import "../../../../../shared/theme/styles/mixins.scss";
.mat-column-actions {
min-height: 4.8rem;
}
.mat-column-state {
flex: 1 1 15%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

@ -7,7 +7,7 @@ import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { GetInfo, Channel } from '../../../../../shared/models/clModels';
import { PAGE_SIZE, PAGE_SIZE_OPTIONS, getPaginatorLabel, ScreenSizeEnum, FEE_RATE_TYPES, AlertTypeEnum, APICallStatusEnum } from '../../../../../shared/services/consts-enums-functions';
import { PAGE_SIZE, PAGE_SIZE_OPTIONS, getPaginatorLabel, ScreenSizeEnum, FEE_RATE_TYPES, AlertTypeEnum, APICallStatusEnum, CLChannelPendingState } from '../../../../../shared/services/consts-enums-functions';
import { ApiCallsListCL } from '../../../../../shared/models/apiCallsPayload';
import { LoggerService } from '../../../../../shared/services/logger.service';
import { CommonService } from '../../../../../shared/services/common.service';
@ -17,6 +17,7 @@ import { RTLEffects } from '../../../../../store/rtl.effects';
import * as RTLActions from '../../../../../store/rtl.actions';
import * as CLActions from '../../../../store/cl.actions';
import * as fromRTLReducer from '../../../../../store/rtl.reducers';
import { CLBumpFeeComponent } from '../../bump-fee-modal/bump-fee.component';
@Component({
selector: 'rtl-cl-channel-pending-table',
@ -41,6 +42,7 @@ export class CLChannelPendingTableComponent implements OnInit, AfterViewInit, On
public feeRateTypes = FEE_RATE_TYPES;
public selFilter = '';
public flgSticky = false;
public CLChannelPendingState = CLChannelPendingState;
public pageSize = PAGE_SIZE;
public pageSizeOptions = PAGE_SIZE_OPTIONS;
public screenSize = '';
@ -82,7 +84,8 @@ export class CLChannelPendingTableComponent implements OnInit, AfterViewInit, On
}
this.numPeers = (rtlStore.peers && rtlStore.peers.length) ? rtlStore.peers.length : 0;
this.totalBalance = rtlStore.balance.totalBalance;
this.channelsData = this.commonService.sortByKey(rtlStore.allChannels.filter((channel) => !(channel.state === 'CHANNELD_NORMAL' && channel.connected)), 'state', 'string');
this.channelsData = rtlStore.allChannels.filter((channel) => !(channel.state === 'CHANNELD_NORMAL' && channel.connected));
this.channelsData = this.channelsData.sort((a, b) => ((this.CLChannelPendingState[a.state] >= this.CLChannelPendingState[b.state]) ? 1 : -1));
if (this.channelsData && this.channelsData.length > 0) {
this.loadChannelsTable(this.channelsData);
}
@ -100,6 +103,13 @@ export class CLChannelPendingTableComponent implements OnInit, AfterViewInit, On
this.channels.filter = this.selFilter.trim().toLowerCase();
}
onBumpFee(selChannel: Channel) {
this.store.dispatch(new RTLActions.OpenAlert({ data: {
channel: selChannel,
component: CLBumpFeeComponent
} }));
}
onChannelClick(selChannel: Channel, event: any) {
this.store.dispatch(new RTLActions.OpenAlert({ data: {
channel: selChannel,
@ -131,14 +141,22 @@ export class CLChannelPendingTableComponent implements OnInit, AfterViewInit, On
this.channels.filterPredicate = (channel: Channel, fltr: string) => {
const newChannel = ((channel.connected) ? 'connected' : 'disconnected') + (channel.channel_id ? channel.channel_id.toLowerCase() : '') +
(channel.short_channel_id ? channel.short_channel_id.toLowerCase() : '') + (channel.id ? channel.id.toLowerCase() : '') + (channel.alias ? channel.alias.toLowerCase() : '') +
(channel.private ? 'private' : 'public') + (channel.state ? channel.state.toLowerCase() : '') +
(channel.private ? 'private' : 'public') + ((channel.state && this.CLChannelPendingState[channel.state]) ? this.CLChannelPendingState[channel.state].toLowerCase() : '') +
(channel.funding_txid ? channel.funding_txid.toLowerCase() : '') + (channel.msatoshi_to_us ? channel.msatoshi_to_us : '') +
(channel.msatoshi_total ? channel.msatoshi_total : '') + (channel.their_channel_reserve_satoshis ? channel.their_channel_reserve_satoshis : '') +
(channel.our_channel_reserve_satoshis ? channel.our_channel_reserve_satoshis : '') + (channel.spendable_msatoshi ? channel.spendable_msatoshi : '');
return newChannel.includes(fltr);
};
this.channels.sort = this.sort;
this.channels.sortingDataAccessor = (data: any, sortHeaderId: string) => ((data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null);
this.channels.sortingDataAccessor = (data: any, sortHeaderId: string) => {
switch (sortHeaderId) {
case 'state':
return this.CLChannelPendingState[data.state];
default:
return (data[sortHeaderId] && isNaN(data[sortHeaderId])) ? data[sortHeaderId].toLocaleLowerCase() : data[sortHeaderId] ? +data[sortHeaderId] : null;
}
};
this.channels.paginator = this.paginator;
this.logger.info(this.channels);
}

@ -729,13 +729,13 @@ export class CLEffects implements OnDestroy {
pipe(
map((postRes: any) => {
this.logger.info(postRes);
this.store.dispatch(new CLActions.UpdateAPICallStatus({ action: 'SetChannelTransaction', status: APICallStatusEnum.COMPLETED }));
this.store.dispatch(new CLActions.SetChannelTransactionRes(postRes));
this.store.dispatch(new RTLActions.CloseSpinner(UI_MESSAGES.SEND_FUNDS));
this.store.dispatch(new CLActions.FetchBalance());
this.store.dispatch(new CLActions.FetchUTXOs());
return {
type: CLActions.SET_CHANNEL_TRANSACTION_RES_CL,
payload: postRes
type: CLActions.UPDATE_API_CALL_STATUS_CL,
payload: { action: 'SetChannelTransaction', status: APICallStatusEnum.COMPLETED }
};
}),
catchError((err: any) => {

@ -180,6 +180,7 @@ export class LightningInvoicesComponent implements OnInit, AfterViewInit, OnDest
onPageChange(event: PageEvent) {
let reverse = true;
let index_offset = this.lastOffset;
let page_size = event.pageSize;
if (event.pageIndex === 0) {
reverse = true;
index_offset = 0;
@ -191,7 +192,8 @@ export class LightningInvoicesComponent implements OnInit, AfterViewInit, OnDest
index_offset = this.firstOffset;
} else if (event.length <= ((event.pageIndex + 1) * event.pageSize)) {
reverse = false;
index_offset = event.length - (event.pageIndex * event.pageSize) + 1;
index_offset = 0;
page_size = event.length - (event.pageIndex * event.pageSize);
}
this.store.dispatch(new LNDActions.FetchInvoices({ num_max_invoices: event.pageSize, index_offset: index_offset, reversed: reverse }));
}

@ -126,6 +126,20 @@ export const WALLET_ADDRESS_TYPE = {
UNUSED_NESTED_PUBKEY_HASH: { name: 'Unused Nested Pubkey Hash', tooltip: '' }
};
export enum CLChannelPendingState {
CHANNELD_NORMAL = 'Active',
OPENINGD = 'Opening',
CHANNELD_AWAITING_LOCKIN = 'Pending Open',
CHANNELD_SHUTTING_DOWN = 'Shutting Down',
CLOSINGD_SIGEXCHANGE = 'Closing: Sig Exchange',
CLOSINGD_COMPLETE = 'Closed',
AWAITING_UNILATERAL = 'Awaiting Unilateral Close',
FUNDING_SPEND_SEEN = 'Funding Spend Seen',
ONCHAIN = 'Onchain',
DUALOPEND_OPEN_INIT = 'Dual Open Initialized',
DUALOPEND_AWAITING_LOCKIN = 'Dual Pending Open'
}
export enum LoopStateEnum {
INITIATED = 'Initiated',
PREIMAGE_REVEALED = 'Preimage Revealed',

Loading…
Cancel
Save