Skip to content

Commit

Permalink
Mempool openchannel minfee (#1388)
Browse files Browse the repository at this point in the history
Open channel model block if min fee is higher
  • Loading branch information
ShahanaFarooqui authored May 11, 2024
1 parent 40f6c4d commit a96422f
Show file tree
Hide file tree
Showing 18 changed files with 108 additions and 31 deletions.
1 change: 0 additions & 1 deletion frontend/125.2d8b0d451f9e6528.js

This file was deleted.

1 change: 1 addition & 0 deletions frontend/125.c9e382333be6e677.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion frontend/456.a7433b9c5b34e0df.js

This file was deleted.

1 change: 1 addition & 0 deletions frontend/456.b73706bd7985d63a.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions frontend/570.58fb22012be84615.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion frontend/570.a47a5e74ba9177e8.js

This file was deleted.

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

Large diffs are not rendered by default.

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

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

1 change: 0 additions & 1 deletion frontend/runtime.9565333e3d711f1e.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ export class CLNBumpFeeComponent implements OnInit, OnDestroy {
public bumpFeeError = '';
public flgShowDustWarning = false;
public dustOutputValue = 0;
public recommendedFee = { fastestFee: 0, halfHourFee: 0, hourFee: 0 };
public recommendedFee: RecommendedFeeRates = { fastestFee: 0, halfHourFee: 0, hourFee: 0 };
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) { }

ngOnInit() {
this.bumpFeeChannel = this.data.channel;
this.logger.info(this.bumpFeeChannel);
this.dataService.getRecommendedFeeRates().pipe(takeUntil(this.unSubs[0])).subscribe({
next: (rfRes: RecommendedFeeRates) => {
this.recommendedFee = rfRes;
Expand Down Expand Up @@ -81,7 +82,7 @@ export class CLNBumpFeeComponent implements OnInit, OnDestroy {
payload: {
destination: action.payload,
satoshi: 'all',
feerate: (+(this.fees || 0) * 1000).toString(),
feerate: (+(this.fees || 0) * 1000).toString() + 'perkb',
utxos: [this.bumpFeeChannel.funding_txid + ':' + (this.outputIndex || '').toString()]
}
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,24 @@
</mat-expansion-panel-header>
<div fxLayout="column" fxFlex="100" fxLayoutAlign="start stretch">
<div fxLayout="column" fxLayoutAlign="space-between stretch" fxLayoutAlign.gt-sm="space-between center" fxLayout.gt-sm="row wrap">
<div fxFlex="54" fxLayout="row" fxLayoutAlign="space-between center">
<mat-form-field fxLayout="column" fxLayoutAlign="start center" [fxFlex]="selFeeRate === 'customperkb' && !flgMinConf ? '48' : '100'">
<div fxFlex="64" fxLayout="row" fxLayoutAlign="space-between center">
<mat-form-field fxLayout="column" fxLayoutAlign="start center" [fxFlex]="selFeeRate === 'customperkb' && !flgMinConf ? '40' : '100'">
<mat-label>Fee Rate</mat-label>
<mat-select tabindex="4" [disabled]="flgMinConf" [(value)]="selFeeRate" (selectionChange)="customFeeRate=null">
<mat-select tabindex="4" [disabled]="flgMinConf" [(value)]="selFeeRate" (selectionChange)="onSelFeeRateChanged($event)">
<mat-option *ngFor="let feeRateType of feeRateTypes" [value]="feeRateType.feeRateId">
{{feeRateType.feeRateType}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="selFeeRate === 'customperkb' && !flgMinConf" fxLayout="column" fxFlex="48" fxLayoutAlign="end center">
<mat-form-field *ngIf="selFeeRate === 'customperkb' && !flgMinConf" fxLayout="column" fxFlex="58" fxLayoutAlign="end center">
<mat-label>Fee Rate (Sats/vByte)</mat-label>
<input #custFeeRate="ngModel" matInput type="number" name="custFeeRate" tabindex="4" [step]="0.1" [min]="0" [required]="selFeeRate === 'customperkb' && !flgMinConf" [(ngModel)]="customFeeRate">
<input #custFeeRate="ngModel" matInput type="number" name="custFeeRate" tabindex="4" [step]="1" [min]="recommendedFee.minimumFee" [required]="selFeeRate === 'customperkb' && !flgMinConf" [(ngModel)]="customFeeRate">
<mat-hint>Mempool Min: {{recommendedFee.minimumFee}} (Sats/vByte)</mat-hint>
<mat-error *ngIf="selFeeRate === 'customperkb' && !flgMinConf && !customFeeRate">Fee Rate is required.</mat-error>
<mat-error *ngIf="selFeeRate === 'customperkb' && !flgMinConf && customFeeRate && customFeeRate < recommendedFee.minimumFee">Lower than min feerate {{recommendedFee.minimumFee}} in the mempool.</mat-error>
</mat-form-field>
</div>
<div fxFlex="42" fxLayout="row" fxLayoutAlign="start center">
<div fxFlex="32" fxLayout="row" fxLayoutAlign="start center">
<mat-checkbox fxFlex="7" tabindex="5" color="primary" name="flgMinConf" fxLayoutAlign="stretch start" [ngClass]="{'mr-6': screenSize === screenSizeEnum.XS || screenSize === screenSizeEnum.SM, 'mr-2': screenSize === screenSizeEnum.MD || screenSize === screenSizeEnum.LG || screenSize === screenSizeEnum.XL}" [(ngModel)]="flgMinConf" (change)="flgMinConf ? selFeeRate=null : minConfValue=null" />
<mat-form-field fxLayout="column" fxFlex="93">
<mat-label>Min Confirmation Blocks</mat-label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ import { Store } from '@ngrx/store';
import { Actions } from '@ngrx/effects';
import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';

import { LoggerService } from '../../../../shared/services/logger.service';
import { DataService } from '../../../../shared/services/data.service';
import { CommonService } from '../../../../shared/services/common.service';
import { Peer, GetInfo, UTXO } from '../../../../shared/models/clnModels';
import { Peer, GetInfo, UTXO, SaveChannel } from '../../../../shared/models/clnModels';
import { CLNOpenChannelAlert } from '../../../../shared/models/alertData';
import { APICallStatusEnum, CLNActions, FEE_RATE_TYPES, ScreenSizeEnum } from '../../../../shared/services/consts-enums-functions';

import { RecommendedFeeRates } from '../../../../shared/models/rtlModels';
import { RTLState } from '../../../../store/rtl.state';
import { saveNewChannel } from '../../../store/cln.actions';
import { rootSelectedNode } from '../../../../store/rtl.selector';
Expand Down Expand Up @@ -52,9 +55,13 @@ export class CLNOpenChannelComponent implements OnInit, OnDestroy {
public minConfValue = null;
public screenSize = '';
public screenSizeEnum = ScreenSizeEnum;
public recommendedFee: RecommendedFeeRates = { fastestFee: 0, halfHourFee: 0, hourFee: 0 };
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];

constructor(public dialogRef: MatDialogRef<CLNOpenChannelComponent>, @Inject(MAT_DIALOG_DATA) public data: CLNOpenChannelAlert, private store: Store<RTLState>, private actions: Actions, private decimalPipe: DecimalPipe, private commonService: CommonService) {
constructor(private logger: LoggerService, public dialogRef: MatDialogRef<CLNOpenChannelComponent>,
@Inject(MAT_DIALOG_DATA) public data: CLNOpenChannelAlert, private store: Store<RTLState>,
private actions: Actions, private decimalPipe: DecimalPipe, private commonService: CommonService,
private dataService: DataService) {
this.screenSize = this.commonService.getScreenSize();
}

Expand Down Expand Up @@ -185,18 +192,35 @@ export class CLNOpenChannelComponent implements OnInit, OnDestroy {
}

onOpenChannel(): boolean | void {
if ((!this.peer && !this.selectedPubkey) || (!this.fundingAmount || ((this.totalBalance - this.fundingAmount) < 0) || (this.flgMinConf && !this.minConfValue)) || (this.selFeeRate === 'customperkb' && !this.flgMinConf && !this.customFeeRate)) {
if ((!this.peer && !this.selectedPubkey) ||
(!this.fundingAmount || ((this.totalBalance - this.fundingAmount) < 0) ||
(this.flgMinConf && !this.minConfValue)) ||
(this.selFeeRate === 'customperkb' && !this.flgMinConf && !this.customFeeRate) ||
(this.selFeeRate === 'customperkb' && this.recommendedFee.minimumFee > this.customFeeRate)) {
return true;
}
const newChannel = { peerId: ((!this.peer || !this.peer.id) ? this.selectedPubkey : this.peer.id), amount: (this.flgUseAllBalance) ? 'all' : this.fundingAmount.toString(), announce: !this.isPrivate, minconf: this.flgMinConf ? this.minConfValue : null };
newChannel['feerate'] = (this.selFeeRate === 'customperkb' && !this.flgMinConf && this.customFeeRate) ? (this.customFeeRate * 1000) + 'perkb' : this.selFeeRate;
const newChannel: SaveChannel = { peerId: ((!this.peer || !this.peer.id) ? this.selectedPubkey : this.peer.id), amount: (this.flgUseAllBalance) ? 'all' : this.fundingAmount.toString(), announce: !this.isPrivate, minconf: this.flgMinConf ? this.minConfValue : null };
newChannel.feeRate = (this.selFeeRate === 'customperkb' && !this.flgMinConf && this.customFeeRate) ? (this.customFeeRate * 1000) + 'perkb' : this.selFeeRate;
if (this.selUTXOs.length && this.selUTXOs.length > 0) {
newChannel['utxos'] = [];
this.selUTXOs.forEach((utxo: UTXO) => newChannel['utxos'].push(utxo.txid + ':' + utxo.output));
}
this.store.dispatch(saveNewChannel({ payload: newChannel }));
}

onSelFeeRateChanged(event) {
this.customFeeRate = null;
if (event.value === 'customperkb') {
this.dataService.getRecommendedFeeRates().pipe(takeUntil(this.unSubs[3])).subscribe({
next: (rfRes: RecommendedFeeRates) => {
this.recommendedFee = rfRes;
}, error: (err) => {
this.logger.error(err);
}
});
}
}

ngOnDestroy() {
this.unSubs.forEach((completeSub) => {
completeSub.next(<any>null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@
<div fxFlex="100" fxLayout="row" fxLayoutAlign="space-between center">
<mat-form-field fxLayout="column" fxFlex="49">
<mat-label>Fee (Sats/vByte)</mat-label>
<input #fee="ngModel" matInput type="number" name="fee" tabindex="7" [step]="1" [min]="0" [(ngModel)]="feeRate">
<input #fee="ngModel" matInput type="number" name="fee" tabindex="7" [step]="1" [min]="recommendedFee.minimumFee" [(ngModel)]="feeRate">
<mat-hint>Mempool Min: {{recommendedFee.minimumFee}} (Sats/vByte)</mat-hint>
<mat-error *ngIf="feeRate && feeRate < recommendedFee.minimumFee">Lower than min feerate {{recommendedFee.minimumFee}} in the mempool.</mat-error>
</mat-form-field>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ 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 { mockCLEffects, mockECLEffects, mockLNDEffects, mockMatDialogRef, mockRTLEffects } from '../../../../shared/test-helpers/mock-services';
import { SharedModule } from '../../../../shared/shared.module';

import { DataService } from '../../../../shared/services/data.service';
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 { mockCLEffects, mockDataService, mockECLEffects, mockLNDEffects, mockMatDialogRef, mockRTLEffects } from '../../../../shared/test-helpers/mock-services';
import { ECLOpenChannelComponent } from './open-channel.component';

describe('ECLOpenChannelComponent', () => {
Expand All @@ -26,6 +27,7 @@ describe('ECLOpenChannelComponent', () => {
EffectsModule.forRoot([mockRTLEffects, mockLNDEffects, mockCLEffects, mockECLEffects])
],
providers: [
{ provide: DataService, useClass: mockDataService },
{ provide: MatDialogRef, useClass: mockMatDialogRef },
{ provide: MAT_DIALOG_DATA, useValue: { message: {} } }
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import { RTLState } from '../../../../store/rtl.state';
import { rootSelectedNode } from '../../../../store/rtl.selector';
import { saveNewChannel } from '../../../store/ecl.actions';
import { Node } from '../../../../shared/models/RTLconfig';
import { RecommendedFeeRates } from '../../../../shared/models/rtlModels';
import { LoggerService } from '../../../../shared/services/logger.service';
import { DataService } from '../../../../shared/services/data.service';

@Component({
selector: 'rtl-ecl-open-channel',
Expand All @@ -40,9 +43,12 @@ export class ECLOpenChannelComponent implements OnInit, OnDestroy {
public selectedPubkey = '';
public isPrivate = false;
public feeRate: number | null = null;
public recommendedFee: RecommendedFeeRates = { fastestFee: 0, halfHourFee: 0, hourFee: 0 };
private unSubs: Array<Subject<void>> = [new Subject(), new Subject(), new Subject(), new Subject()];

constructor(public dialogRef: MatDialogRef<ECLOpenChannelComponent>, @Inject(MAT_DIALOG_DATA) public data: ECLOpenChannelAlert, private store: Store<RTLState>, private actions: Actions) { }
constructor(private logger: LoggerService, public dialogRef: MatDialogRef<ECLOpenChannelComponent>,
@Inject(MAT_DIALOG_DATA) public data: ECLOpenChannelAlert, private store: Store<RTLState>,
private actions: Actions, private dataService: DataService) { }

ngOnInit() {
if (this.data.message) {
Expand Down Expand Up @@ -131,18 +137,31 @@ export class ECLOpenChannelComponent implements OnInit, OnDestroy {
if (this.feeRate && this.feeRate > 0) {
this.advancedTitle = this.advancedTitle + ' | Fee (Sats/vByte): ' + this.feeRate;
}
} else {
this.dataService.getRecommendedFeeRates().pipe(takeUntil(this.unSubs[3])).subscribe({
next: (rfRes: RecommendedFeeRates) => {
this.recommendedFee = rfRes;
}, error: (err) => {
this.logger.error(err);
}
});
}
}

onOpenChannel(): boolean | void {
if ((!this.peer && !this.selectedPubkey) || (!this.fundingAmount || ((this.totalBalance - this.fundingAmount) < 0))) {
if (
(!this.peer && !this.selectedPubkey) ||
(!this.fundingAmount || ((this.totalBalance - this.fundingAmount) < 0)) ||
(this.feeRate && this.recommendedFee.minimumFee > this.feeRate)
) {
return true;
}
const saveChannelPayload: SaveChannel = { nodeId: ((!this.peer || !this.peer.nodeId) ? this.selectedPubkey : this.peer.nodeId), amount: this.fundingAmount, private: this.isPrivate };
if (this.feeRate) { saveChannelPayload['feeRate'] = this.feeRate; }
this.store.dispatch(saveNewChannel({ payload: saveChannelPayload }));
}


ngOnDestroy() {
this.unSubs.forEach((completeSub) => {
completeSub.next(<any>null);
Expand Down
Loading

0 comments on commit a96422f

Please sign in to comment.