Parse & display liquidity ads on node page
This commit is contained in:
parent
010e9f2bb1
commit
c2ab0bc715
31
frontend/src/app/lightning/node/liquidity-ad.ts
Normal file
31
frontend/src/app/lightning/node/liquidity-ad.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
export interface ILiquidityAd {
|
||||||
|
funding_weight: number;
|
||||||
|
lease_fee_basis: number; // lease fee rate in parts-per-thousandth
|
||||||
|
lease_fee_base_sat: number; // fixed lease fee in sats
|
||||||
|
channel_fee_max_rate: number; // max routing fee rate in parts-per-thousandth
|
||||||
|
channel_fee_max_base: number; // max routing base fee in milli-sats
|
||||||
|
compact_lease?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseLiquidityAdHex(compact_lease: string): ILiquidityAd | false {
|
||||||
|
if (!compact_lease || compact_lease.length < 20 || compact_lease.length > 28) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const liquidityAd: ILiquidityAd = {
|
||||||
|
funding_weight: parseInt(compact_lease.slice(0, 4), 16),
|
||||||
|
lease_fee_basis: parseInt(compact_lease.slice(4, 8), 16),
|
||||||
|
channel_fee_max_rate: parseInt(compact_lease.slice(8, 12), 16),
|
||||||
|
lease_fee_base_sat: parseInt(compact_lease.slice(12, 20), 16),
|
||||||
|
channel_fee_max_base: compact_lease.length > 20 ? parseInt(compact_lease.slice(20), 16) : 0,
|
||||||
|
}
|
||||||
|
if (Object.values(liquidityAd).reduce((valid: boolean, value: number): boolean => (valid && !isNaN(value) && value >= 0), true)) {
|
||||||
|
liquidityAd.compact_lease = compact_lease;
|
||||||
|
return liquidityAd;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -127,19 +127,84 @@
|
|||||||
|
|
||||||
<div *ngIf="hasDetails" [hidden]="!showDetails" id="details" class="details mt-3">
|
<div *ngIf="hasDetails" [hidden]="!showDetails" id="details" class="details mt-3">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<h5 class="mb-3" i18n="node.tlv.records">TLV extension records</h5>
|
<ng-template [ngIf]="liquidityAd">
|
||||||
<div class="row">
|
<div class="detail-section">
|
||||||
<div class="col">
|
<h5 class="mb-3" i18n="node.liquidity-ad">Liquidity ad</h5>
|
||||||
<table class="table table-borderless table-striped">
|
<div class="row">
|
||||||
<tbody>
|
<div class="col-md">
|
||||||
<tr *ngFor="let recordItem of node.custom_records | keyvalue">
|
<table class="table table-borderless table-striped">
|
||||||
<td class="tlv-type">{{ recordItem.key }}</td>
|
<tbody>
|
||||||
<td class="tlv-payload">{{ recordItem.value }}</td>
|
<tr>
|
||||||
</tr>
|
<td class="label" i18n="liquidity-ad.lease-fee-rate|Liquidity ad lease fee rate">Lease fee rate</td>
|
||||||
</tbody>
|
<td>
|
||||||
</table>
|
<span class="d-inline-block">
|
||||||
|
{{ liquidityAd.lease_fee_basis !== null ? ((liquidityAd.lease_fee_basis * 1000) | amountShortener : 2 : undefined : true) : '-' }} <span class="symbol">ppm {{ liquidityAd.lease_fee_basis !== null ? '(' + (liquidityAd.lease_fee_basis / 10 | amountShortener : 2 : undefined : true) + '%)' : '' }}</span>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label" i18n="liquidity-ad.lease-base-fee">Lease base fee</td>
|
||||||
|
<td>
|
||||||
|
<app-sats [valueOverride]="liquidityAd.lease_fee_base_sat === null ? '- ' : undefined" [satoshis]="liquidityAd.lease_fee_base_sat"></app-sats>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label" i18n="liquidity-ad.funding-weight">Funding weight</td>
|
||||||
|
<td [innerHTML]="'‎' + (liquidityAd.funding_weight | wuBytes: 2)"></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="col-md">
|
||||||
|
<table class="table table-borderless table-striped">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="label" i18n="liquidity-ad.channel-fee-rate|Liquidity ad channel fee rate">Channel fee rate</td>
|
||||||
|
<td>
|
||||||
|
<span class="d-inline-block">
|
||||||
|
{{ liquidityAd.channel_fee_max_rate !== null ? ((liquidityAd.channel_fee_max_rate * 1000) | amountShortener : 2 : undefined : true) : '-' }} <span class="symbol">ppm {{ liquidityAd.channel_fee_max_rate !== null ? '(' + (liquidityAd.channel_fee_max_rate / 10 | amountShortener : 2 : undefined : true) + '%)' : '' }}</span>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label" i18n="liquidity-ad.channel-base-fee">Channel base fee</td>
|
||||||
|
<td>
|
||||||
|
<span *ngIf="liquidityAd.channel_fee_max_base !== null">
|
||||||
|
{{ liquidityAd.channel_fee_max_base | amountShortener : 0 }}
|
||||||
|
<span class="symbol" i18n="shared.m-sats">mSats</span>
|
||||||
|
</span>
|
||||||
|
<span *ngIf="liquidityAd.channel_fee_max_base === null">
|
||||||
|
-
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label" i18n="liquidity-ad.compact-lease">Compact lease</td>
|
||||||
|
<td class="compact-lease">{{ liquidityAd.compact_lease }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ng-template>
|
||||||
|
<ng-template [ngIf]="tlvRecords?.length">
|
||||||
|
<div class="detail-section">
|
||||||
|
<h5 class="mb-3" i18n="node.tlv.records">TLV extension records</h5>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<table class="table table-borderless table-striped">
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let recordItem of tlvRecords">
|
||||||
|
<td class="tlv-type">{{ recordItem.type }}</td>
|
||||||
|
<td class="tlv-payload">{{ recordItem.payload }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -73,17 +73,31 @@ app-fiat {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
.details tbody {
|
.details {
|
||||||
font-size: 12px;
|
|
||||||
|
.detail-section {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.tlv-type {
|
.tlv-type {
|
||||||
|
font-size: 12px;
|
||||||
color: #ffffff66;
|
color: #ffffff66;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tlv-payload {
|
.tlv-payload {
|
||||||
|
font-size: 12px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
font-family: "Courier New", Courier, monospace;
|
font-family: "Courier New", Courier, monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.compact-lease {
|
||||||
|
word-break: break-all;
|
||||||
|
white-space: normal;
|
||||||
|
font-family: "Courier New", Courier, monospace;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,12 @@ import { catchError, map, switchMap, tap } from 'rxjs/operators';
|
|||||||
import { SeoService } from '../../services/seo.service';
|
import { SeoService } from '../../services/seo.service';
|
||||||
import { LightningApiService } from '../lightning-api.service';
|
import { LightningApiService } from '../lightning-api.service';
|
||||||
import { GeolocationData } from '../../shared/components/geolocation/geolocation.component';
|
import { GeolocationData } from '../../shared/components/geolocation/geolocation.component';
|
||||||
|
import { ILiquidityAd, parseLiquidityAdHex } from './liquidity-ad';
|
||||||
|
|
||||||
|
interface CustomRecord {
|
||||||
|
type: string;
|
||||||
|
payload: string;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-node',
|
selector: 'app-node',
|
||||||
@ -26,6 +32,8 @@ export class NodeComponent implements OnInit {
|
|||||||
torSocketCount = 0;
|
torSocketCount = 0;
|
||||||
hasDetails = false;
|
hasDetails = false;
|
||||||
showDetails = false;
|
showDetails = false;
|
||||||
|
liquidityAd: ILiquidityAd;
|
||||||
|
tlvRecords: CustomRecord[];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private lightningApiService: LightningApiService,
|
private lightningApiService: LightningApiService,
|
||||||
@ -38,6 +46,8 @@ export class NodeComponent implements OnInit {
|
|||||||
.pipe(
|
.pipe(
|
||||||
switchMap((params: ParamMap) => {
|
switchMap((params: ParamMap) => {
|
||||||
this.publicKey = params.get('public_key');
|
this.publicKey = params.get('public_key');
|
||||||
|
this.tlvRecords = [];
|
||||||
|
this.liquidityAd = null;
|
||||||
return this.lightningApiService.getNode$(params.get('public_key'));
|
return this.lightningApiService.getNode$(params.get('public_key'));
|
||||||
}),
|
}),
|
||||||
map((node) => {
|
map((node) => {
|
||||||
@ -83,6 +93,23 @@ export class NodeComponent implements OnInit {
|
|||||||
}),
|
}),
|
||||||
tap((node) => {
|
tap((node) => {
|
||||||
this.hasDetails = Object.keys(node.custom_records).length > 0;
|
this.hasDetails = Object.keys(node.custom_records).length > 0;
|
||||||
|
for (const [type, payload] of Object.entries(node.custom_records)) {
|
||||||
|
if (typeof payload !== 'string') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let parsed = false;
|
||||||
|
if (type === '1') {
|
||||||
|
const ad = parseLiquidityAdHex(payload);
|
||||||
|
if (ad) {
|
||||||
|
parsed = true;
|
||||||
|
this.liquidityAd = ad;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!parsed) {
|
||||||
|
this.tlvRecords.push({ type, payload });
|
||||||
|
}
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
catchError(err => {
|
catchError(err => {
|
||||||
this.error = err;
|
this.error = err;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user