@ -5,12 +5,12 @@ import { Store } from '@ngrx/store';
import { MatTableDataSource } from '@angular/material/table' ;
import { MatTableDataSource } from '@angular/material/table' ;
import { MatSort } from '@angular/material/sort' ;
import { MatSort } from '@angular/material/sort' ;
import { MatPaginator , MatPaginatorIntl } from '@angular/material/paginator' ;
import { MatPaginator , MatPaginatorIntl } from '@angular/material/paginator' ;
import { faBullhorn , faExclamationTriangle } from '@fortawesome/free-solid-svg-icons' ;
import { faBullhorn , faExclamationTriangle , faUsers } from '@fortawesome/free-solid-svg-icons' ;
import { DataService } from '../../../shared/services/data.service' ;
import { DataService } from '../../../shared/services/data.service' ;
import { LoggerService } from '../../../shared/services/logger.service' ;
import { LoggerService } from '../../../shared/services/logger.service' ;
import { CommonService } from '../../../shared/services/common.service' ;
import { CommonService } from '../../../shared/services/common.service' ;
import { AlertTypeEnum , APICallStatusEnum , DataTypeEnum , getPaginatorLabel , PAGE_SIZE , PAGE_SIZE_OPTIONS , ScreenSizeEnum } from '../../../shared/services/consts-enums-functions' ;
import { AlertTypeEnum , APICallStatusEnum , DataTypeEnum , getPaginatorLabel , PAGE_SIZE , PAGE_SIZE_OPTIONS , ScreenSizeEnum , NODE_FEATURES_CLN } from '../../../shared/services/consts-enums-functions' ;
import { GetInfo , LookupNode } from '../../../shared/models/clnModels' ;
import { GetInfo , LookupNode } from '../../../shared/models/clnModels' ;
import { ApiCallStatusPayload } from '../../../shared/models/apiCallsPayload' ;
import { ApiCallStatusPayload } from '../../../shared/models/apiCallsPayload' ;
import { openAlert , openConfirmation } from '../../../store/rtl.actions' ;
import { openAlert , openConfirmation } from '../../../store/rtl.actions' ;
@ -19,6 +19,7 @@ import { RTLState } from '../../../store/rtl.state';
import { RTLEffects } from '../../../store/rtl.effects' ;
import { RTLEffects } from '../../../store/rtl.effects' ;
import { CLNOpenLiquidityChannelComponent } from '../open-liquidity-channel-modal/open-liquidity-channel-modal.component' ;
import { CLNOpenLiquidityChannelComponent } from '../open-liquidity-channel-modal/open-liquidity-channel-modal.component' ;
import { nodeInfoAndNodeSettingsAndBalance } from '../../store/cln.selector' ;
import { nodeInfoAndNodeSettingsAndBalance } from '../../store/cln.selector' ;
import { DecimalPipe } from '@angular/common' ;
@Component ( {
@Component ( {
selector : 'rtl-cln-liquidity-ads-list' ,
selector : 'rtl-cln-liquidity-ads-list' ,
@ -37,6 +38,7 @@ export class CLNLiquidityAdsListComponent implements OnInit, OnDestroy {
public displayedColumns : any [ ] = [ ] ;
public displayedColumns : any [ ] = [ ] ;
public faBullhorn = faBullhorn ;
public faBullhorn = faBullhorn ;
public faExclamationTriangle = faExclamationTriangle ;
public faExclamationTriangle = faExclamationTriangle ;
public faUsers = faUsers ;
public totalBalance = 0 ;
public totalBalance = 0 ;
public information : GetInfo ;
public information : GetInfo ;
public channelAmount = 100000 ;
public channelAmount = 100000 ;
@ -51,11 +53,12 @@ export class CLNLiquidityAdsListComponent implements OnInit, OnDestroy {
public screenSize = '' ;
public screenSize = '' ;
public screenSizeEnum = ScreenSizeEnum ;
public screenSizeEnum = ScreenSizeEnum ;
public errorMessage = '' ;
public errorMessage = '' ;
public selFilter = '' ;
public apiCallStatus : ApiCallStatusPayload = { status : APICallStatusEnum.INITIATED } ;
public apiCallStatus : ApiCallStatusPayload = { status : APICallStatusEnum.INITIATED } ;
public apiCallStatusEnum = APICallStatusEnum ;
public apiCallStatusEnum = APICallStatusEnum ;
private unSubs : Array < Subject < void > > = [ new Subject ( ) , new Subject ( ) , new Subject ( ) , new Subject ( ) ] ;
private unSubs : Array < Subject < void > > = [ new Subject ( ) , new Subject ( ) , new Subject ( ) , new Subject ( ) ] ;
constructor ( private logger : LoggerService , private store : Store < RTLState > , private dataService : DataService , private commonService : CommonService , private rtlEffects : RTLEffects ) {
constructor ( private logger : LoggerService , private store : Store < RTLState > , private dataService : DataService , private commonService : CommonService , private rtlEffects : RTLEffects , private decimalPipe : DecimalPipe ) {
this . askTooltipMsg = 'Specify the liquidity requirements for your node: \n 1. Channel Amount - Amount in Sats you need on the channel opened to your node \n 2. Channel opening fee rate - Rate in Sats/vByte that you are willing to pay to open the channel to you' ;
this . askTooltipMsg = 'Specify the liquidity requirements for your node: \n 1. Channel Amount - Amount in Sats you need on the channel opened to your node \n 2. Channel opening fee rate - Rate in Sats/vByte that you are willing to pay to open the channel to you' ;
this . nodesTooltipMsg = 'These nodes are advertising their liquidity offering on the network.\nYou should pay attention to the following aspects to evaluate each node offer: \n- The total bitcoin deployed on the node, the more the better\n' ;
this . nodesTooltipMsg = 'These nodes are advertising their liquidity offering on the network.\nYou should pay attention to the following aspects to evaluate each node offer: \n- The total bitcoin deployed on the node, the more the better\n' ;
this . nodesTooltipMsg = this . nodesTooltipMsg + '- The number of channels open on the node, the more the better\n- The channel open fee which the node will charge from you\n- The routing fee which the node will charge on the payments, the lesser the better\n- The reliability of the node, ideally uptime. Refer to the information being provided by the node explorers' ;
this . nodesTooltipMsg = this . nodesTooltipMsg + '- The number of channels open on the node, the more the better\n- The channel open fee which the node will charge from you\n- The routing fee which the node will charge on the payments, the lesser the better\n- The reliability of the node, ideally uptime. Refer to the information being provided by the node explorers' ;
@ -85,8 +88,7 @@ export class CLNLiquidityAdsListComponent implements OnInit, OnDestroy {
if ( nodeListRes && ! ( < any [ ] > nodeListRes ) . length ) { nodeListRes = [ ] ; }
if ( nodeListRes && ! ( < any [ ] > nodeListRes ) . length ) { nodeListRes = [ ] ; }
this . logger . info ( 'Received Liquidity Ads Enabled Nodes: ' + JSON . stringify ( nodeListRes ) ) ;
this . logger . info ( 'Received Liquidity Ads Enabled Nodes: ' + JSON . stringify ( nodeListRes ) ) ;
this . apiCallStatus . status = APICallStatusEnum . COMPLETED ;
this . apiCallStatus . status = APICallStatusEnum . COMPLETED ;
this . liquidityNodesData = ( < LookupNode [ ] > nodeListRes ) ;
( < any [ ] > nodeListRes ) . forEach ( ( lqNode ) = > {
this . liquidityNodesData . forEach ( ( lqNode ) = > {
const a : string [ ] = [ ] ;
const a : string [ ] = [ ] ;
lqNode . address_types = Array . from ( new Set ( lqNode . addresses ? . reduce ( ( acc , addr ) = > {
lqNode . address_types = Array . from ( new Set ( lqNode . addresses ? . reduce ( ( acc , addr ) = > {
if ( addr . type ? . includes ( 'ipv' ) || addr . type ? . includes ( 'tor' ) ) {
if ( addr . type ? . includes ( 'ipv' ) || addr . type ? . includes ( 'tor' ) ) {
@ -95,6 +97,7 @@ export class CLNLiquidityAdsListComponent implements OnInit, OnDestroy {
return acc ;
return acc ;
} , a ) ) ) ;
} , a ) ) ) ;
} ) ;
} ) ;
this . liquidityNodesData = ( < LookupNode [ ] > nodeListRes ) . filter ( node = > node . nodeid !== this . information . id ) ;
this . onCalculateOpeningFee ( ) ;
this . onCalculateOpeningFee ( ) ;
this . loadLiqNodesTable ( this . liquidityNodesData ) ;
this . loadLiqNodesTable ( this . liquidityNodesData ) ;
} , error : ( err ) = > {
} , error : ( err ) = > {
@ -118,14 +121,26 @@ export class CLNLiquidityAdsListComponent implements OnInit, OnDestroy {
// this.liquidityNodes.filter = 'Changed';
// this.liquidityNodes.filter = 'Changed';
}
}
applyFilter() {
this . liquidityNodes . filter = this . selFilter . trim ( ) . toLowerCase ( ) ;
}
loadLiqNodesTable ( liqNodes : LookupNode [ ] ) {
loadLiqNodesTable ( liqNodes : LookupNode [ ] ) {
this . liquidityNodes = new MatTableDataSource < LookupNode > ( [ . . . liqNodes ] ) ;
this . liquidityNodes = new MatTableDataSource < LookupNode > ( [ . . . liqNodes ] ) ;
this . liquidityNodes . sortingDataAccessor = ( data : any , sortHeaderId : string ) = > ( ( data [ sortHeaderId ] && isNaN ( data [ sortHeaderId ] ) ) ? data [ sortHeaderId ] . toLocaleLowerCase ( ) : data [ sortHeaderId ] ? + data [ sortHeaderId ] : null ) ;
this . liquidityNodes . sortingDataAccessor = ( data : any , sortHeaderId : string ) = > ( ( data [ sortHeaderId ] && isNaN ( data [ sortHeaderId ] ) ) ? data [ sortHeaderId ] . toLocaleLowerCase ( ) : data [ sortHeaderId ] ? + data [ sortHeaderId ] : null ) ;
this . liquidityNodes . sort = this . sort ;
this . liquidityNodes . sort = this . sort ;
this . liquidityNodes . paginator = this . paginator ;
this . liquidityNodes . paginator = this . paginator ;
if ( this . sort ) { this . sort . sort ( { id : 'channelOpeningFee' , start : 'asc' , disableClear : true } ) ; }
if ( this . sort ) { this . sort . sort ( { id : 'channelOpeningFee' , start : 'asc' , disableClear : true } ) ; }
this . liquidityNodes . filterPredicate = ( node : LookupNode , fltr : string ) = > ( node . channelCount || 0 ) >= this . channelCount && ( node . nodeCapacity || 0 ) >= this . nodeCapacity ;
this . liquidityNodes . filterPredicate = ( node : LookupNode , fltr : string ) = > {
this . onFilter ( ) ;
const newNode = ( ( node . alias ) ? node . alias . toLocaleLowerCase ( ) : '' ) + ( node . channelOpeningFee ? node . channelOpeningFee + ' Sats' : '' )
+ ( node . option_will_fund ? . lease_fee_base_msat ? ( node . option_will_fund ? . lease_fee_base_msat / 1000 ) + ' Sats' : '' ) + ( node . option_will_fund ? . lease_fee_basis ? ( this . decimalPipe . transform ( node . option_will_fund ? . lease_fee_basis / 100 , '1.2-2' ) + '%' ) : '' )
+ ( node . option_will_fund ? . channel_fee_max_base_msat ? ( node . option_will_fund ? . channel_fee_max_base_msat / 1000 ) + ' Sats' : '' ) + ( node . option_will_fund ? . channel_fee_max_proportional_thousandths ? ( node . option_will_fund ? . channel_fee_max_proportional_thousandths * 1000 ) + ' ppm' : '' )
+ ( node . address_types ? node . address_types . reduce ( ( acc , curr ) = > acc + ( curr === 'tor' ? ' tor' : curr === 'ipv' ? ' clearnet' : ( ' ' + curr . toLowerCase ( ) ) ) , '' ) : '' ) ;
return newNode . includes ( fltr ) ;
}
this . applyFilter ( ) ;
// this.liquidityNodes.filterPredicate = (node: LookupNode, fltr: string) => node.channelCount >= this.channelCount && node.nodeCapacity >= this.nodeCapacity;
// this.onFilter();
}
}
viewLeaseOn ( lqNode : LookupNode , link : string ) {
viewLeaseOn ( lqNode : LookupNode , link : string ) {
@ -158,17 +173,28 @@ export class CLNLiquidityAdsListComponent implements OnInit, OnDestroy {
onViewLeaseInfo ( lqNode : LookupNode ) {
onViewLeaseInfo ( lqNode : LookupNode ) {
const addArr = lqNode . addresses ? . reduce ( ( acc , curr ) = > {
const addArr = lqNode . addresses ? . reduce ( ( acc , curr ) = > {
if ( curr . address && curr . address . length > 40 ) { curr . address = curr . address . substring ( 0 , 39 ) + '...' ; }
if ( curr . address && curr . address . length > 40 ) { curr . address = curr . address . substring ( 0 , 39 ) + '...' ; }
return acc . concat ( JSON . stringify ( curr ) ? . replace ( '{' , '' ) ? . replace ( '}' , '' ) ? . replace ( /:/g , ': ' ) ? . replace ( /,/g , ' ' ) ? . replace ( /"/g , '' ) ) ;
return acc . concat ( JSON . stringify ( curr ) . replace ( '{' , '' ) . replace ( '}' , '' ) . replace ( /:/g , ': ' ) . replace ( /,/g , ' ' ) . replace ( /"/g , '' ) ) ;
} , < any [ ] > [ ] ) ;
} , < any > [ ] ) ;
const featureDescriptions : string [ ] = [ ] ;
if ( lqNode . features && lqNode . features . trim ( ) !== '' ) {
const featureHex = parseInt ( lqNode . features , 16 ) ;
NODE_FEATURES_CLN . forEach ( ( feature ) = > {
if ( ! ! ( featureHex & ( ( 1 << feature . range . min ) | ( 1 << feature . range . max ) ) ) ) {
featureDescriptions . push ( feature . description ) ;
}
} ) ;
}
const reorderedLQNode = [
const reorderedLQNode = [
[ { key : 'alias' , value : lqNode.alias , title : 'Node Alias' , width : 50 , type : DataTypeEnum . STRING } ,
[ { key : 'alias' , value : lqNode.alias , title : 'Node Alias' , width : 50 , type : DataTypeEnum . STRING } ,
{ key : 'last_timestamp' , value : lqNode.last_timestamp , title : 'Last Timestamp' , width : 50 , type : DataTypeEnum . DATE_TIME } ] ,
{ key : 'last_timestamp' , value : lqNode.last_timestamp , title : 'Last Timestamp' , width : 50 , type : DataTypeEnum . DATE_TIME } ] ,
[ { key : 'nodeid' , value : lqNode.nodeid , title : 'Node ID' , width : 100 , type : DataTypeEnum . STRING } ] ,
[ { key : 'nodeid' , value : lqNode.nodeid , title : 'Node ID' , width : 100 , type : DataTypeEnum . STRING } ] ,
[ { key : 'base_fee' , value : ( ( lqNode . option_will_fund ? . lease_fee_base_msat || 0 ) / 1000 ) , title : 'Lease Base Fee (Sats)' , width : 50 , type : DataTypeEnum . NUMBER } ,
[ { key : 'compact_lease' , value : lqNode.option_will_fund?.compact_lease , title : 'Compact Lease' , width : 100 , type : DataTypeEnum . STRING } ] ,
[ { key : 'base_fee' , value : lqNode.option_will_fund?.lease_fee_base_msat ? ( lqNode . option_will_fund . lease_fee_base_msat / 1000 ) : 0 , title : 'Lease Base Fee (Sats)' , width : 50 , type : DataTypeEnum . NUMBER } ,
{ key : 'fee_basis' , value : lqNode.option_will_fund?.lease_fee_basis , title : 'Lease Base Basis (bps)' , width : 50 , type : DataTypeEnum . NUMBER } ] ,
{ key : 'fee_basis' , value : lqNode.option_will_fund?.lease_fee_basis , title : 'Lease Base Basis (bps)' , width : 50 , type : DataTypeEnum . NUMBER } ] ,
[ { key : 'channel_max_base' , value : ( lqNode . option_will_fund ? . channel_fee_max_base_msat || 0 ) / 1000 , title : 'Max Channel Routing Base Fee (Sats)' , width : 50 , type : DataTypeEnum . NUMBER } ,
[ { key : 'channel_max_base' , value : lqNode.option_will_fund?.channel_fee_max_base_msat ? ( lqNode . option_will_fund . channel_fee_max_base_msat / 1000 ) : 0, title : 'Max Channel Routing Base Fee (Sats)' , width : 50 , type : DataTypeEnum . NUMBER } ,
{ key : 'channel_max_rate' , value : ( lqNode . option_will_fund ? . channel_fee_max_proportional_thousandths || 0 ) * 1000 , title : 'Max Channel Routing Fee Rate (ppm)' , width : 50 , type : DataTypeEnum . NUMBER } ] ,
{ key : 'channel_max_rate' , value : ( lqNode . option_will_fund ? . channel_fee_max_proportional_thousandths || 0 ) * 1000 , title : 'Max Channel Routing Fee Rate (ppm)' , width : 50 , type : DataTypeEnum . NUMBER } ] ,
[ { key : 'funding_rate' , value : ( lqNode . option_will_fund ? . funding_weight || 0 ) , title : 'Funding Weight' , width : 100 , type : DataTypeEnum . NUMBER } ] ,
[ { key : 'funding_rate' , value : lqNode.option_will_fund?.funding_weight , title : 'Funding Weight' , width : 100 , type : DataTypeEnum . NUMBER } ] ,
[ { key : 'features' , value : featureDescriptions , title : 'Features' , width : 100 , type : DataTypeEnum . ARRAY } ] ,
[ { key : 'address' , value : addArr , title : 'Address' , width : 100 , type : DataTypeEnum . ARRAY } ]
[ { key : 'address' , value : addArr , title : 'Address' , width : 100 , type : DataTypeEnum . ARRAY } ]
] ;
] ;
this . store . dispatch ( openConfirmation ( {
this . store . dispatch ( openConfirmation ( {