From c2ab0bc7155ad2aa0cbc10a578e270904359536c Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 4 Nov 2022 23:24:44 -0600 Subject: [PATCH] Parse & display liquidity ads on node page --- .../src/app/lightning/node/liquidity-ad.ts | 31 +++++++ .../app/lightning/node/node.component.html | 89 ++++++++++++++++--- .../app/lightning/node/node.component.scss | 18 +++- .../src/app/lightning/node/node.component.ts | 27 ++++++ 4 files changed, 151 insertions(+), 14 deletions(-) create mode 100644 frontend/src/app/lightning/node/liquidity-ad.ts diff --git a/frontend/src/app/lightning/node/liquidity-ad.ts b/frontend/src/app/lightning/node/liquidity-ad.ts new file mode 100644 index 000000000..4b0e04b0b --- /dev/null +++ b/frontend/src/app/lightning/node/liquidity-ad.ts @@ -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; + } +} \ No newline at end of file diff --git a/frontend/src/app/lightning/node/node.component.html b/frontend/src/app/lightning/node/node.component.html index 9c8fc6149..858aa9b48 100644 --- a/frontend/src/app/lightning/node/node.component.html +++ b/frontend/src/app/lightning/node/node.component.html @@ -127,19 +127,84 @@
-
TLV extension records
-
-
- - - - - - - -
{{ recordItem.key }}{{ recordItem.value }}
+ +
+
Liquidity ad
+
+
+ + + + + + + + + + + + + + + +
Lease fee rate + + {{ liquidityAd.lease_fee_basis !== null ? ((liquidityAd.lease_fee_basis * 1000) | amountShortener : 2 : undefined : true) : '-' }} ppm {{ liquidityAd.lease_fee_basis !== null ? '(' + (liquidityAd.lease_fee_basis / 10 | amountShortener : 2 : undefined : true) + '%)' : '' }} + +
Lease base fee + +
Funding weight
+
+
+ + + + + + + + + + + + + + + +
Channel fee rate + + {{ liquidityAd.channel_fee_max_rate !== null ? ((liquidityAd.channel_fee_max_rate * 1000) | amountShortener : 2 : undefined : true) : '-' }} ppm {{ liquidityAd.channel_fee_max_rate !== null ? '(' + (liquidityAd.channel_fee_max_rate / 10 | amountShortener : 2 : undefined : true) + '%)' : '' }} + +
Channel base fee + + {{ liquidityAd.channel_fee_max_base | amountShortener : 0 }} + mSats + + + - + +
Compact lease{{ liquidityAd.compact_lease }}
+
+
-
+ + +
+
TLV extension records
+
+
+ + + + + + + +
{{ recordItem.type }}{{ recordItem.payload }}
+
+
+
+
diff --git a/frontend/src/app/lightning/node/node.component.scss b/frontend/src/app/lightning/node/node.component.scss index fe9737b85..d54b1851b 100644 --- a/frontend/src/app/lightning/node/node.component.scss +++ b/frontend/src/app/lightning/node/node.component.scss @@ -73,17 +73,31 @@ app-fiat { }; } -.details tbody { - font-size: 12px; +.details { + + .detail-section { + margin-bottom: 1.5rem; + &:last-child { + margin-bottom: 0; + } + } .tlv-type { + font-size: 12px; color: #ffffff66; } .tlv-payload { + font-size: 12px; width: 100%; word-break: break-all; white-space: normal; font-family: "Courier New", Courier, monospace; } + + .compact-lease { + word-break: break-all; + white-space: normal; + font-family: "Courier New", Courier, monospace; + } } diff --git a/frontend/src/app/lightning/node/node.component.ts b/frontend/src/app/lightning/node/node.component.ts index 161a53e37..ec2edd252 100644 --- a/frontend/src/app/lightning/node/node.component.ts +++ b/frontend/src/app/lightning/node/node.component.ts @@ -5,6 +5,12 @@ import { catchError, map, switchMap, tap } from 'rxjs/operators'; import { SeoService } from '../../services/seo.service'; import { LightningApiService } from '../lightning-api.service'; import { GeolocationData } from '../../shared/components/geolocation/geolocation.component'; +import { ILiquidityAd, parseLiquidityAdHex } from './liquidity-ad'; + +interface CustomRecord { + type: string; + payload: string; +} @Component({ selector: 'app-node', @@ -26,6 +32,8 @@ export class NodeComponent implements OnInit { torSocketCount = 0; hasDetails = false; showDetails = false; + liquidityAd: ILiquidityAd; + tlvRecords: CustomRecord[]; constructor( private lightningApiService: LightningApiService, @@ -38,6 +46,8 @@ export class NodeComponent implements OnInit { .pipe( switchMap((params: ParamMap) => { this.publicKey = params.get('public_key'); + this.tlvRecords = []; + this.liquidityAd = null; return this.lightningApiService.getNode$(params.get('public_key')); }), map((node) => { @@ -83,6 +93,23 @@ export class NodeComponent implements OnInit { }), tap((node) => { 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 => { this.error = err;