lnd: Onchain CPFP

- UTXO label bug fix
- Warning on utxo label for "sweep" in text.
pull/1394/head
ShahanaFarooqui 2 weeks ago
parent 4bdecdf472
commit 481174034f

@ -154,7 +154,7 @@ export const labelTransaction = (req, res, next) => {
return res.status(options.statusCode).json({ message: options.message, error: options.error });
}
options.url = req.session.selectedNode.settings.lnServerUrl + '/v2/wallet/tx/label';
options.form = JSON.parse(JSON.stringify(options.form));
options.form = JSON.stringify(req.body);
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Wallet', msg: 'Label Transaction Options', data: options.form });
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Wallet', msg: 'Transaction Labelled', data: body });

@ -358,7 +358,7 @@ export class ConfigService {
this.updateConfig = (confFileFullPath, config) => {
// Update Config file to change Settings to settings and Authentication to authentication
// Added in v0.15.1, remove in a year?
if (!config.nodes || config.nodes[0].settings) {
if (!config.nodes) {
return;
}
config.nodes.map((node) => {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
(()=>{"use strict";var e,v={},m={};function r(e){var o=m[e];if(void 0!==o)return o.exports;var t=m[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,r),t.loaded=!0,t.exports}r.m=v,e=[],r.O=(o,t,i,f)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,i,f]=e[n],c=!0,d=0;d<t.length;d++)(!1&f||a>=f)&&Object.keys(r.O).every(b=>r.O[b](t[d]))?t.splice(d--,1):(c=!1,f<a&&(a=f));if(c){e.splice(n--,1);var u=i();void 0!==u&&(o=u)}}return o}f=f||0;for(var n=e.length;n>0&&e[n-1][2]>f;n--)e[n]=e[n-1];e[n]=[t,i,f]},r.d=(e,o)=>{for(var t in o)r.o(o,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:o[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((o,t)=>(r.f[t](e,o),o),[])),r.u=e=>e+"."+{125:"df4ebfbf2688940a",456:"52fd629b36893386",570:"58fb22012be84615",758:"b6dcd2f2b36dacf0"}[e]+".js",r.miniCssF=e=>{},r.o=(e,o)=>Object.prototype.hasOwnProperty.call(e,o),(()=>{var e={},o="RTLApp:";r.l=(t,i,f,n)=>{if(e[t])e[t].push(i);else{var a,c;if(void 0!==f)for(var d=document.getElementsByTagName("script"),u=0;u<d.length;u++){var l=d[u];if(l.getAttribute("src")==t||l.getAttribute("data-webpack")==o+f){a=l;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",o+f),a.src=r.tu(t)),e[t]=[i];var s=(g,b)=>{a.onerror=a.onload=null,clearTimeout(p);var h=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),h&&h.forEach(y=>y(b)),g)return g(b)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:o=>o},typeof trustedTypes<"u"&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="",(()=>{var e={666:0};r.f.j=(i,f)=>{var n=r.o(e,i)?e[i]:void 0;if(0!==n)if(n)f.push(n[2]);else if(666!=i){var a=new Promise((l,s)=>n=e[i]=[l,s]);f.push(n[2]=a);var c=r.p+r.u(i),d=new Error;r.l(c,l=>{if(r.o(e,i)&&(0!==(n=e[i])&&(e[i]=void 0),n)){var s=l&&("load"===l.type?"missing":l.type),p=l&&l.target&&l.target.src;d.message="Loading chunk "+i+" failed.\n("+s+": "+p+")",d.name="ChunkLoadError",d.type=s,d.request=p,n[1](d)}},"chunk-"+i,i)}else e[i]=0},r.O.j=i=>0===e[i];var o=(i,f)=>{var d,u,[n,a,c]=f,l=0;if(n.some(p=>0!==e[p])){for(d in a)r.o(a,d)&&(r.m[d]=a[d]);if(c)var s=c(r)}for(i&&i(f);l<n.length;l++)r.o(e,u=n[l])&&e[u]&&e[u][0](),e[u]=0;return r.O(s)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(o.bind(null,0)),t.push=o.bind(null,t.push.bind(t))})()})();

@ -0,0 +1 @@
(()=>{"use strict";var e,v={},m={};function r(e){var f=m[e];if(void 0!==f)return f.exports;var t=m[e]={id:e,loaded:!1,exports:{}};return v[e].call(t.exports,t,t.exports,r),t.loaded=!0,t.exports}r.m=v,e=[],r.O=(f,t,i,o)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,i,o]=e[n],c=!0,l=0;l<t.length;l++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[l]))?t.splice(l--,1):(c=!1,o<a&&(a=o));if(c){e.splice(n--,1);var d=i();void 0!==d&&(f=d)}}return f}o=o||0;for(var n=e.length;n>0&&e[n-1][2]>o;n--)e[n]=e[n-1];e[n]=[t,i,o]},r.d=(e,f)=>{for(var t in f)r.o(f,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:f[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((f,t)=>(r.f[t](e,f),f),[])),r.u=e=>e+"."+{125:"652a194bbd78e174",456:"52fd629b36893386",570:"37090718556d71ce",758:"b6dcd2f2b36dacf0"}[e]+".js",r.miniCssF=e=>{},r.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),(()=>{var e={},f="RTLApp:";r.l=(t,i,o,n)=>{if(e[t])e[t].push(i);else{var a,c;if(void 0!==o)for(var l=document.getElementsByTagName("script"),d=0;d<l.length;d++){var u=l[d];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==f+o){a=u;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",f+o),a.src=r.tu(t)),e[t]=[i];var s=(g,b)=>{a.onerror=a.onload=null,clearTimeout(p);var h=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),h&&h.forEach(y=>y(b)),g)return g(b)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{typeof Symbol<"u"&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:f=>f},typeof trustedTypes<"u"&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="",(()=>{var e={666:0};r.f.j=(i,o)=>{var n=r.o(e,i)?e[i]:void 0;if(0!==n)if(n)o.push(n[2]);else if(666!=i){var a=new Promise((u,s)=>n=e[i]=[u,s]);o.push(n[2]=a);var c=r.p+r.u(i),l=new Error;r.l(c,u=>{if(r.o(e,i)&&(0!==(n=e[i])&&(e[i]=void 0),n)){var s=u&&("load"===u.type?"missing":u.type),p=u&&u.target&&u.target.src;l.message="Loading chunk "+i+" failed.\n("+s+": "+p+")",l.name="ChunkLoadError",l.type=s,l.request=p,n[1](l)}},"chunk-"+i,i)}else e[i]=0},r.O.j=i=>0===e[i];var f=(i,o)=>{var l,d,[n,a,c]=o,u=0;if(n.some(p=>0!==e[p])){for(l in a)r.o(a,l)&&(r.m[l]=a[l]);if(c)var s=c(r)}for(i&&i(o);u<n.length;u++)r.o(e,d=n[u])&&e[d]&&e[d][0](),e[d]=0;return r.O(s)},t=self.webpackChunkRTLApp=self.webpackChunkRTLApp||[];t.forEach(f.bind(null,0)),t.push=f.bind(null,t.push.bind(t))})()})();

@ -140,7 +140,7 @@ export const labelTransaction = (req, res, next) => {
options = common.getOptions(req);
if (options.error) { return res.status(options.statusCode).json({ message: options.message, error: options.error }); }
options.url = req.session.selectedNode.settings.lnServerUrl + '/v2/wallet/tx/label';
options.form = JSON.parse(JSON.stringify(options.form));
options.form = JSON.stringify(req.body);
logger.log({ selectedNode: req.session.selectedNode, level: 'DEBUG', fileName: 'Wallet', msg: 'Label Transaction Options', data: options.form });
request.post(options).then((body) => {
logger.log({ selectedNode: req.session.selectedNode, level: 'INFO', fileName: 'Wallet', msg: 'Transaction Labelled', data: body });

@ -337,7 +337,7 @@ export class ConfigService {
private updateConfig = (confFileFullPath, config) => {
// Update Config file to change Settings to settings and Authentication to authentication
// Added in v0.15.1, remove in a year?
if (!config.nodes || config.nodes[0].settings) { return; }
if (!config.nodes) { return; }
config.nodes.map((node) => {
if (node.Authentication) {
node.authentication = JSON.parse(JSON.stringify(node.Authentication));

@ -10,7 +10,7 @@
<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 transaction id: {{bumpFeeChannel?.funding_txid}}
<fa-icon class="ml-1" matSuffix rtlClipboard matTooltip="Copy transaction ID" [icon]="faCopy" [payload]="bumpFeeChannel?.funding_txid" (copied)="onCopyID($event)" />
<fa-icon matTooltip="Show transaction ID" class="ml-1" [icon]="faUpRightFromSquare" (click)="onExplorerClicked(bumpFeeChannel?.funding_txid)"/>
</p>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch">
<div fxFlex="100" class="alert alert-info">
@ -29,9 +29,9 @@
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between center">
<mat-form-field fxLayout="column" fxFlex="49">
<mat-label>Output Index</mat-label>
<input #outputIdx="ngModel" autoFocus matInput type="number" tabindex="1" required name="outputIdx" [step]="1" [min]="0" [(ngModel)]="outputIndex">
<mat-error *ngIf="outputIdx.errors?.required">Output Index required.</mat-error>
<mat-error *ngIf="outputIdx.errors?.pendingChannelOutputIndex">Invalid index value.</mat-error>
<input #outputIndx="ngModel" autoFocus matInput type="number" tabindex="1" required name="outputIndx" [step]="1" [min]="0" [(ngModel)]="outputIndex">
<mat-error *ngIf="outputIndx.errors?.required">Output Index required.</mat-error>
<mat-error *ngIf="outputIndx.errors?.pendingChannelOutputIndex">Invalid index value.</mat-error>
</mat-form-field>
<mat-form-field fxLayout="column" fxFlex="49">
<mat-label>Fees (Sats/vByte)</mat-label>

@ -4,9 +4,8 @@ import { Subject } from 'rxjs';
import { filter, take, takeUntil } from 'rxjs/operators';
import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { faCopy, faInfoCircle, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import { faCopy, faInfoCircle, faExclamationTriangle, faUpRightFromSquare } from '@fortawesome/free-solid-svg-icons';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { RecommendedFeeRates, BlockExplorerTransaction } from '../../../../shared/models/rtlModels';
import { Channel } from '../../../../shared/models/clnModels';
@ -15,6 +14,8 @@ import { ADDRESS_TYPES, APICallStatusEnum, CLNActions } from '../../../../shared
import { LoggerService } from '../../../../shared/services/logger.service';
import { DataService } from '../../../../shared/services/data.service';
import { Node } from '../../../../shared/models/RTLconfig';
import { rootSelectedNode } from '../../../../store/rtl.selector';
import { RTLState } from '../../../../store/rtl.state';
import { openSnackBar } from '../../../../store/rtl.actions';
import { getNewAddress, setChannelTransaction } from '../../../store/cln.actions';
@ -27,12 +28,12 @@ import { getNewAddress, setChannelTransaction } from '../../../store/cln.actions
export class CLNBumpFeeComponent implements OnInit, OnDestroy {
private outputIdx: NgModel;
@ViewChild('outputIdx') set payReq(outIdx: NgModel) {
@ViewChild('outputIdx') set outputIndx(outIdx: NgModel) {
if (outIdx) {
this.outputIdx = outIdx;
}
}
public faUpRightFromSquare = faUpRightFromSquare;
public newAddress = '';
public bumpFeeChannel: Channel;
public fees = null;
@ -44,14 +45,20 @@ export class CLNBumpFeeComponent implements OnInit, OnDestroy {
public flgShowDustWarning = false;
public dustOutputValue = 0;
public recommendedFee: RecommendedFeeRates = { fastestFee: 0, halfHourFee: 0, hourFee: 0 };
public selNode: Node;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(private actions: Actions, public dialogRef: MatDialogRef<CLNBumpFeeComponent>, @Inject(MAT_DIALOG_DATA) public data: CLNChannelInformation, private store: Store<RTLState>, private logger: LoggerService, private dataService: DataService, private snackBar: MatSnackBar) { }
constructor(private actions: Actions, public dialogRef: MatDialogRef<CLNBumpFeeComponent>, @Inject(MAT_DIALOG_DATA) public data: CLNChannelInformation, private store: Store<RTLState>, private logger: LoggerService, private dataService: DataService) { }
ngOnInit() {
this.bumpFeeChannel = this.data.channel;
this.logger.info(this.bumpFeeChannel);
this.dataService.getRecommendedFeeRates().pipe(takeUntil(this.unSubs[0])).subscribe({
this.store.select(rootSelectedNode).pipe(takeUntil(this.unSubs[0])).
subscribe((selNode) => {
this.selNode = selNode;
this.logger.info(this.selNode);
});
this.dataService.getRecommendedFeeRates().pipe(takeUntil(this.unSubs[1])).subscribe({
next: (rfRes: RecommendedFeeRates) => {
this.recommendedFee = rfRes;
}, error: (err) => {
@ -59,7 +66,7 @@ export class CLNBumpFeeComponent implements OnInit, OnDestroy {
}
});
this.dataService.getBlockExplorerTransaction(this.bumpFeeChannel.funding_txid).
pipe(takeUntil(this.unSubs[1])).subscribe({
pipe(takeUntil(this.unSubs[2])).subscribe({
next: (txRes: BlockExplorerTransaction) => {
this.outputIndex = txRes.vout.findIndex((vout) => vout.value === this.bumpFeeChannel.to_us_msat) === 0 ? 1 : 0;
this.dustOutputValue = txRes.vout[this.outputIndex].value;
@ -92,7 +99,7 @@ export class CLNBumpFeeComponent implements OnInit, OnDestroy {
this.store.dispatch(openSnackBar({ payload: 'Successfully bumped the fee. Use the block explorer to verify transaction.' }));
this.dialogRef.close();
});
this.actions.pipe(filter((action) => action.type === CLNActions.UPDATE_API_CALL_STATUS_CLN), takeUntil(this.unSubs[2])).
this.actions.pipe(filter((action) => action.type === CLNActions.UPDATE_API_CALL_STATUS_CLN), takeUntil(this.unSubs[3])).
subscribe((action: any) => {
if (action.payload.status === APICallStatusEnum.ERROR && (action.payload.action === 'SetChannelTransaction' || action.payload.action === 'GenerateNewAddress')) {
this.logger.error(action.payload.message);
@ -101,8 +108,8 @@ export class CLNBumpFeeComponent implements OnInit, OnDestroy {
});
}
onCopyID(payload: string) {
this.snackBar.open('Transaction ID copied.');
onExplorerClicked(txid: string) {
window.open(this.selNode.settings.blockExplorerUrl + '/tx/' + txid, '_blank');
}
resetData() {

@ -8,6 +8,10 @@
</mat-card-header>
<mat-card-content class="padding-gap-x-large">
<form #form="ngForm" fxLayout="row wrap" fxLayoutAlign="space-between start" fxFlex="100" class="overflow-x-hidden" (submit)="onLabelUTXO()" (reset)="resetData()">
<div *ngIf="label.toLowerCase().includes('sweep') && utxo.confirmations === '0'" fxFlex="100" class="alert alert-warn">
<fa-icon class="mr-1 alert-icon" [icon]="faExclamationTriangle" />
<span>Bump fee option will be disabled for unconfirmed UTXOs where label text includes "sweep" in its value.</span>
</div>
<mat-form-field fxLayout="column" fxFlex.gt-sm="100">
<mat-label>UTXO Label</mat-label>
<input autoFocus matInput name="label" tabindex="1" required [(ngModel)]="label">

@ -89,6 +89,7 @@
<mat-option (click)="onUTXOClick(utxo)">View Info</mat-option>
<mat-option (click)="onLabelUTXO(utxo)">Label</mat-option>
<mat-option (click)="onLeaseUTXO(utxo)">Lease</mat-option>
<mat-option *ngIf="!utxo.label.toLowerCase().includes('sweep') && utxo.confirmations === '0'" (click)="onBumpFee(utxo)">Bump Fee</mat-option>
</mat-select>
</div>
</td>

@ -26,6 +26,7 @@ import { lndPageSettings, utxos } from '../../../store/lnd.selector';
import { ColumnDefinition, PageSettings, TableSetting } from '../../../../shared/models/pageSettings';
import { CamelCaseWithReplacePipe } from '../../../../shared/pipes/app.pipe';
import { MessageDataField } from '../../../../shared/models/alertData';
import { BumpFeeComponent } from '../../../peers-channels/channels/bump-fee-modal/bump-fee.component';
@Component({
selector: 'rtl-on-chain-utxos',
@ -249,6 +250,17 @@ export class OnChainUTXOsComponent implements OnInit, OnChanges, OnDestroy {
});
}
onBumpFee(selUTXO: UTXO) {
this.store.dispatch(openAlert({
payload: {
data: {
selUTXO: selUTXO,
component: BumpFeeComponent
}
}
}));
}
onDownloadCSV() {
if (this.listUTXOs.data && this.listUTXOs.data.length > 0) {
this.commonService.downloadFile(this.listUTXOs.data, 'UTXOs');

@ -9,8 +9,9 @@
<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?.channel?.channel_point}}
<fa-icon class="ml-1" matSuffix rtlClipboard matTooltip="Copy transaction ID" [icon]="faCopy" [payload]="bumpFeeChannel?.channel?.txid_str" (copied)="onCopyID($event)" />
<p fxLayoutAlign="start center" class="pb-1 word-break">
{{txid ? 'Bump fee for transaction ID: ' + txid : 'Bump fee: '}}
<fa-icon matTooltip="Show transaction ID" class="ml-1" [icon]="faUpRightFromSquare" (click)="onExplorerClicked()"/>
</p>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="space-between stretch">
<div fxFlex="100" class="alert alert-info">
@ -29,9 +30,9 @@
<div fxLayout="row" fxFlex="100" fxLayoutAlign="space-between start">
<mat-form-field fxLayout="column" fxFlex.gt-sm="32" fxLayoutAlign="start end">
<mat-label>Index for Change Output</mat-label>
<input #outputIdx="ngModel" autoFocus matInput type="number" tabindex="1" required name="outputIdx" [step]="1" [min]="0" [(ngModel)]="outputIndex">
<mat-error *ngIf="outputIdx.errors?.required">Index for change output is required.</mat-error>
<mat-error *ngIf="outputIdx.errors?.pendingChannelOutputIndex">Invalid index value.</mat-error>
<input #outputIndx="ngModel" autoFocus matInput type="number" tabindex="1" required name="outputIndx" [step]="1" [min]="0" [(ngModel)]="outputIndex">
<mat-error *ngIf="outputIndx.errors?.required">Index for change output is required.</mat-error>
<mat-error *ngIf="outputIndx.errors?.OutputIndexError">Invalid index value.</mat-error>
</mat-form-field>
<mat-form-field fxLayout="column" fxFlex.gt-sm="32">
<mat-select tabindex="2" [(value)]="selTransType" (selectionChange)="blocks = null;fees = null;">

@ -1,14 +1,16 @@
import { Component, OnInit, OnDestroy, ViewChild, Inject } from '@angular/core';
import { Component, OnInit, OnDestroy, Inject, ViewChild } from '@angular/core';
import { NgModel } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Subject, forkJoin } from 'rxjs';
import { Store } from '@ngrx/store';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { faCopy, faInfoCircle, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
import { faCopy, faInfoCircle, faExclamationTriangle, faUpRightFromSquare } from '@fortawesome/free-solid-svg-icons';
import { RTLState } from '../../../../store/rtl.state';
import { rootSelectedNode } from '../../../../store/rtl.selector';
import { Node } from '../../../../shared/models/RTLconfig';
import { RecommendedFeeRates, BlockExplorerTransaction } from '../../../../shared/models/rtlModels';
import { PendingOpenChannel } from '../../../../shared/models/lndModels';
import { PendingOpenChannelInformation } from '../../../../shared/models/alertData';
import { BumpFeeInformation } from '../../../../shared/models/alertData';
import { TRANS_TYPES } from '../../../../shared/services/consts-enums-functions';
import { DataService } from '../../../../shared/services/data.service';
import { LoggerService } from '../../../../shared/services/logger.service';
@ -21,17 +23,18 @@ import { LoggerService } from '../../../../shared/services/logger.service';
export class BumpFeeComponent implements OnInit, OnDestroy {
private outputIdx: NgModel;
@ViewChild('outputIdx') set payReq(outIdx: NgModel) {
@ViewChild('outputIdx') set outputIndx(outIdx: NgModel) {
if (outIdx) {
this.outputIdx = outIdx;
}
}
public bumpFeeChannel: PendingOpenChannel;
public faUpRightFromSquare = faUpRightFromSquare;
public txid: string = '';
public outputIndex: number | null = null;
public transTypes = [...TRANS_TYPES];
public selTransType = '2';
public blocks: number | null = null;
public fees: number | null = null;
public outputIndex: number | null = null;
public faCopy = faCopy;
public faInfoCircle = faInfoCircle;
public faExclamationTriangle = faExclamationTriangle;
@ -39,28 +42,36 @@ export class BumpFeeComponent implements OnInit, OnDestroy {
public flgShowDustWarning = false;
public dustOutputValue = 0;
public recommendedFee: RecommendedFeeRates = { fastestFee: 0, halfHourFee: 0, hourFee: 0 };
private unSubs: Array<Subject<void>> = [new Subject(), new Subject()];
public selNode: Node;
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];
constructor(public dialogRef: MatDialogRef<BumpFeeComponent>, @Inject(MAT_DIALOG_DATA) public data: PendingOpenChannelInformation, private logger: LoggerService, private dataService: DataService, private snackBar: MatSnackBar) { }
constructor(public dialogRef: MatDialogRef<BumpFeeComponent>, @Inject(MAT_DIALOG_DATA) public data: BumpFeeInformation, private logger: LoggerService, private dataService: DataService, private store: Store<RTLState>) { }
ngOnInit() {
this.transTypes = this.transTypes.splice(1);
this.bumpFeeChannel = this.data.pendingChannel;
const channelPointArr = this.bumpFeeChannel.channel?.channel_point?.split(':') || [];
if (this.bumpFeeChannel && this.bumpFeeChannel.channel) {
this.bumpFeeChannel.channel.txid_str = channelPointArr[0] || (this.bumpFeeChannel.channel && this.bumpFeeChannel.channel.channel_point ? this.bumpFeeChannel.channel.channel_point : '');
this.bumpFeeChannel.channel.output_index = channelPointArr[1] && channelPointArr[1] !== '' ? +channelPointArr[1] : null;
this.outputIndex = this.bumpFeeChannel.channel && this.bumpFeeChannel.channel.output_index !== null && this.bumpFeeChannel.channel.output_index === 0 ? 1 : 0;
if (this.data.pendingChannel && this.data.pendingChannel.channel) {
const channelPointArr = this.data.pendingChannel.channel?.channel_point?.split(':') || [];
this.txid = channelPointArr[0] || (this.data.pendingChannel.channel && this.data.pendingChannel.channel.channel_point ? this.data.pendingChannel.channel.channel_point : '');
this.outputIndex = channelPointArr[1] && channelPointArr[1] !== '' && +channelPointArr[1] === 0 ? 1 : 0;
} else if (this.data.selUTXO && this.data.selUTXO.outpoint) {
this.txid = this.data.selUTXO.outpoint.txid_str || '';
this.outputIndex = this.data.selUTXO.outpoint.output_index || 0;
}
this.dataService.getRecommendedFeeRates().pipe(takeUntil(this.unSubs[0])).subscribe({
this.logger.info(this.txid, this.outputIndex);
this.store.select(rootSelectedNode).pipe(takeUntil(this.unSubs[0])).
subscribe((selNode) => {
this.selNode = selNode;
this.logger.info(this.selNode);
});
this.dataService.getRecommendedFeeRates().pipe(takeUntil(this.unSubs[1])).subscribe({
next: (rfRes: RecommendedFeeRates) => {
this.recommendedFee = rfRes;
}, error: (err) => {
this.logger.error(err);
}
});
this.dataService.getBlockExplorerTransaction(this.bumpFeeChannel?.channel?.channel_point).
pipe(takeUntil(this.unSubs[1])).subscribe({
this.dataService.getBlockExplorerTransaction(this.txid).
pipe(takeUntil(this.unSubs[2])).subscribe({
next: (txRes: BlockExplorerTransaction) => {
this.dustOutputValue = txRes.vout[this.outputIndex].value;
this.flgShowDustWarning = this.dustOutputValue < 1000;
@ -71,14 +82,18 @@ export class BumpFeeComponent implements OnInit, OnDestroy {
}
onBumpFee(): boolean | void {
if (this.outputIndex === this.bumpFeeChannel.channel?.output_index) {
this.outputIdx.control.setErrors({ pendingChannelOutputIndex: true });
return true;
if (this.data.pendingChannel && this.data.pendingChannel.channel) {
const channelPointArr = this.data.pendingChannel.channel?.channel_point?.split(':') || [];
const chanIdx = channelPointArr.length > 1 && channelPointArr[1] && channelPointArr[1] !== '' ? +channelPointArr[1] : null;
if (chanIdx && this.outputIndex === chanIdx) {
this.outputIdx.control.setErrors({ pendingChannelOutputIndex: true });
return true;
}
}
if ((!this.outputIndex && this.outputIndex !== 0) || (this.selTransType === '1' && (!this.blocks || this.blocks === 0)) || (this.selTransType === '2' && (!this.fees || this.fees === 0))) {
return true;
}
this.dataService.bumpFee((this.bumpFeeChannel && this.bumpFeeChannel.channel && this.bumpFeeChannel.channel.txid_str ? this.bumpFeeChannel.channel.txid_str : ''), this.outputIndex, (this.blocks || null), (this.fees || null)).pipe(takeUntil(this.unSubs[0])).
this.dataService.bumpFee(this.txid, this.outputIndex, (this.blocks || null), (this.fees || null)).pipe(takeUntil(this.unSubs[3])).
subscribe({
next: (res) => {
this.dialogRef.close(false);
@ -89,8 +104,8 @@ export class BumpFeeComponent implements OnInit, OnDestroy {
});
}
onCopyID(payload: string) {
this.snackBar.open('Transaction ID copied.');
onExplorerClicked() {
window.open(this.selNode.settings.blockExplorerUrl + '/tx/' + this.txid, '_blank');
}
resetData() {

@ -336,7 +336,7 @@
<td *matCellDef="let channel" mat-cell><span fxLayoutAlign="end center">{{channel.channel.remote_balance | number}}</span></td>
</ng-container>
<ng-container matColumnDef="actions">
<th *matHeaderCellDef mat-header-cell> fxLayoutAlign="end center"
<th *matHeaderCellDef mat-header-cell>
<div class="bordered-box table-actions-select" fxLayoutAlign="center center">Actions</div>
</th>
<td *matCellDef="let channel" mat-cell fxLayoutAlign="end center">

@ -4,7 +4,7 @@ import { GetInfo, Invoice, Channel, Peer, PendingOpenChannel, UTXO } from './lnd
import { Invoice as InvoiceCLN, GetInfo as GetInfoCLN, Peer as PeerCLN, Channel as ChannelCLN, UTXO as UTXOCLN, Offer as OfferCLN, LookupNode as LookupNodeCLN } from './clnModels';
import { GetInfo as GetInfoECL, Peer as PeerECL, Channel as ChannelECL, Invoice as InvoiceECL, PaymentSent as PaymentSentECL } from './eclModels';
import { LoopQuote } from './loopModels';
import { BoltzInfo, ServiceInfo } from './boltzModels';
import { ServiceInfo } from './boltzModels';
export interface MessageErrorField {
code: number;
@ -157,8 +157,9 @@ export interface ECLChannelInformation {
component?: any;
}
export interface PendingOpenChannelInformation {
pendingChannel: PendingOpenChannel;
export interface BumpFeeInformation {
pendingChannel?: PendingOpenChannel;
selUTXO?: UTXO;
component?: any;
}
@ -242,6 +243,6 @@ export interface DialogConfig {
minHeight?: string;
data: AlertData | ConfirmationData | ErrorData | ChannelRebalanceAlert | ECLChannelRebalanceAlert | OpenChannelAlert | CLNOpenChannelAlert | InvoiceInformation |
CLNPaymentInformation | CLNInvoiceInformation | CLNOfferInformation | ECLInvoiceInformation | ECLPaymentInformation | ChannelInformation | CLNChannelInformation |
PendingOpenChannelInformation | OnChainAddressInformation | ShowPubkeyData | LoopAlert | SwapAlert | AuthConfig |
BumpFeeInformation | OnChainAddressInformation | ShowPubkeyData | LoopAlert | SwapAlert | AuthConfig |
OnChainLabelUTXO | OnChainSendFunds | CLNOnChainSendFunds | ECLChannelInformation | ECLOpenChannelAlert;
}

@ -206,7 +206,7 @@ export class DataService implements OnDestroy {
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.LABEL_UTXO }));
return res;
}), catchError((err) => {
this.handleErrorWithoutAlert('Lease UTXO', UI_MESSAGES.LABEL_UTXO, err);
this.handleErrorWithoutAlert('Label UTXO', UI_MESSAGES.LABEL_UTXO, err);
return throwError(() => new Error(this.extractErrorMessage(err)));
})
);

Loading…
Cancel
Save