Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lnd: Onchain CPFP #1394

Merged
merged 1 commit into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/controllers/lnd/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down
2 changes: 1 addition & 1 deletion backend/utils/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
1 change: 1 addition & 0 deletions frontend/125.652a194bbd78e174.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion frontend/125.df4ebfbf2688940a.js

This file was deleted.

1 change: 1 addition & 0 deletions frontend/570.37090718556d71ce.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion frontend/570.58fb22012be84615.js

This file was deleted.

2 changes: 1 addition & 1 deletion frontend/index.html

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion frontend/runtime.07f90b3998cf8be8.js

This file was deleted.

1 change: 1 addition & 0 deletions frontend/runtime.bd6dd4a2efc59e8f.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion server/controllers/lnd/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down
2 changes: 1 addition & 1 deletion server/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand All @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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';
Expand All @@ -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;
Expand All @@ -44,22 +45,28 @@ 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) => {
this.logger.error(err);
}
});
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;
Expand Down Expand Up @@ -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);
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
12 changes: 12 additions & 0 deletions src/app/lnd/on-chain/utxo-tables/utxos/utxos.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand All @@ -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;">
Expand Down
Loading
Loading