Skip to content
This repository has been archived by the owner on Mar 14, 2024. It is now read-only.

Commit

Permalink
Merge pull request #131 from niteshbalusu11:niteshbalusu11/issue125
Browse files Browse the repository at this point in the history
Adds a simple table on dashboard to get pending payments and channels on the node.
  • Loading branch information
niteshbalusu11 authored Nov 8, 2022
2 parents 9752ed4 + dd3e15d commit c541e26
Show file tree
Hide file tree
Showing 13 changed files with 664 additions and 21 deletions.
18 changes: 18 additions & 0 deletions src/client/dashboard/DefaultDashboardContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Box, Container, Grid, Paper, Toolbar } from '@mui/material';

import BalanceInfo from './BalanceInfo';
import NodeInfo from '~client/dashboard/NodeInfo';
import PendingChart from './PendingChart';
import RoutingFeeChart from './RoutingFeeChart';

// Renders the default dashboard on page load.
Expand Down Expand Up @@ -33,6 +34,7 @@ const DefaultDashboardContainer = () => {
<BalanceInfo />
</Paper>
</Grid>

{/* Walletinfo */}
<Grid item xs={12} md={5} lg={8}>
<Paper
Expand All @@ -46,6 +48,22 @@ const DefaultDashboardContainer = () => {
<NodeInfo />
</Paper>
</Grid>

{/* Pending Chart */}
<Grid item xs={12} md={5} lg={11}>
<Paper
sx={{
p: 2,
display: 'flex',
flexDirection: 'column',
height: '100%',
width: 800,
}}
>
<PendingChart />
</Paper>
</Grid>

{/* Chart */}
<Grid item xs={12} md={5} lg={11}>
<Paper
Expand Down
37 changes: 37 additions & 0 deletions src/client/dashboard/PendingChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { useEffect, useState } from 'react';

import { BasicTable } from '~client/standard_components/app-components';
import { axiosPost } from '~client/utils/axios';
import resgisterCharts from '~client/register_charts';
import { selectedSavedNode } from '~client/utils/constants';
import { useLoading } from '~client/hooks/useLoading';

// Calls NestJs Server and returns pending payments and channels

const PendingChart = () => {
const [data, setData] = useState(undefined);

useEffect(() => {
const fetchData = async () => {
const postBody = {
node: selectedSavedNode(),
};

useLoading({ isLoading: true });
const result = await axiosPost({ path: 'grpc/get-pending', postBody });
console.log(result);
if (!!result) {
setData(result);
}

useLoading({ isLoading: false });
};

fetchData();
}, []);

resgisterCharts();
return !!data && !!data.length ? <BasicTable rows={data} title={'Pending Things'} /> : null;
};

export default PendingChart;
46 changes: 46 additions & 0 deletions src/client/standard_components/app-components/BasicTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from 'react';

import Paper from '@mui/material/Paper';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';

// Creates a basic table with rows and title.

function createData(data: string) {
return { data };
}

type Args = {
rows: string[];
title: string;
};
const BasicTable = ({ rows, title }: Args) => {
const data = rows.map(n => createData(n));

return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell align="left">{title}</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data.map(row => (
<TableRow key={row.data} sx={{ '&:last-child td, &:last-child th': { border: 0 } }}>
<TableCell component="th" scope="row">
{row.data}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
};

export default BasicTable;
4 changes: 3 additions & 1 deletion src/client/standard_components/app-components/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import BasicDatePicker from './BasicDatePicker';
import BasicTable from './BasicTable';
import CenterFlexBox from './CenterFlexBox';
import ContainerStyle from './ContainerStyle';
import CopyText from './CopyText';
Expand All @@ -18,10 +19,11 @@ import StartFlexBoxBlack from './StartFlexBoxBlack';
import Startup from './Startup';
import SubmitButton from './SubmitButton';
export {
BasicDatePicker,
BasicTable,
CenterFlexBox,
ContainerStyle,
CopyText,
BasicDatePicker,
PositionedMenu,
ProgressBar,
ReactCron,
Expand Down
33 changes: 33 additions & 0 deletions src/server/commands/grpc_utils/format_tokens.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const fullTokensType = 'full';
const isString = (n: any) => typeof n === 'string';
const tokensAsBigUnit = (tokens: number) => (tokens / 1e8).toFixed(8);

/** Format tokens for display
{
[none]: <No Value Substitute String>
tokens: <Tokens Number>
}
@returns
{
display: <Formtted Tokens String>
}
*/

type Args = {
none?: string;
tokens: number;
};
const formatTokens = ({ none, tokens }: Args) => {
if (isString(none) && !tokens) {
return { display: none };
}

// Exit early for tokens environment displays the value with no leading zero
if (process.env.PREFERRED_TOKENS_TYPE === fullTokensType) {
return { display: tokens.toLocaleString() };
}

return { display: tokensAsBigUnit(tokens) };
};

export default formatTokens;
195 changes: 195 additions & 0 deletions src/server/commands/grpc_utils/get_pending.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import { AuthenticatedLnd, getChannels, getHeight, getPendingChannels } from 'lightning';
import { auto, map } from 'async';

import { getNodeAlias } from 'ln-sync';
import pendingPayments from './pending_payments';
import pendingSummary from './pending_summary';

const uniq = arr => Array.from(new Set(arr));

/** Handle pending command
{
lnd: <Authenticated Lnd Object>
}
@returns Promise
{
count: <Nodes Count Number>
htlcs: [{
forwarding: [{
fee: <Routing Fee Tokens Number>
in_peer: <Inbound Peer Public Key Hex String>
out_peer: <Outbound Peer Public Key Hex String>
tokens: <Routing Tokens Number>
}]
from: <From Node Named String>
nodes: [{
alias: <Node Alias String>
id: <Public Key Hex String>
}]
sending: [{
out_peer: <Outbound Peer Public Key Hex String>
}]
}]
pending: [{
closing: [{
partner_public_key: <Peer Public Key Hex String>
pending_balance: <Pending Balance Tokens Number>
timelock_expiration: <Funds Locked Until Height Number>
}]
from: <From Node Named String>
height: <Current Block Height Number>
nodes: [{
alias: <Node Alias String>
id: <Public Key Hex String>
}]
opening: [{
is_partner_initiated: <Opening Channel is Peer Initiated Bool>
local_balance: <Opening Channel Local Balance Tokens Number>
partner_public_key: <Opening Channel With Public Key Hex String>
remote_balance: <Opening Channel Remote Balance Tokens Number>
transaction_fee: <Commitment Transaction Fee Tokens Number>
transaction_id: <Funding Transaction Id Hex String>
}]
}]
}
*/
type Args = {
lnd: AuthenticatedLnd;
};
const getPending = async ({ lnd }: Args) => {
return (
await auto({
// Check arguments
validate: (cbk: any) => {
return cbk();
},

// Get HTLCs in channels
getHtlcs: [
'validate',
({}, cbk: any) => {
const nodes = [{ lnd }];
return map(
nodes,
({ lnd }, cbk: any) => {
return getChannels({ lnd }, (err, res) => {
if (!!err) {
return cbk(err);
}

const { forwarding, sending } = pendingPayments({
channels: res.channels,
});

const peers = []
.concat(forwarding.map(n => n.in_peer))
.concat(forwarding.map(n => n.out_peer))
.concat(sending.map(n => n.out_peer));

return map(
uniq(peers),
(id, cbk) => {
return getNodeAlias({ id, lnd }, cbk);
},
(err, nodes) => {
if (!!err) {
return cbk(err);
}

return cbk(null, { forwarding, nodes, sending });
}
);
});
},
cbk
);
},
],

// Get pending channels
getPending: [
'validate',
({}, cbk: any) => {
const nodes = [{ lnd }];

return map(
nodes,
({ lnd }, cbk: any) => {
return getPendingChannels({ lnd }, (err, res) => {
if (!!err) {
return cbk(err);
}

// Pending closing channels
const closing = res.pending_channels
.filter(n => !!n.is_closing)
.map(channel => ({
close_transaction_id: channel.close_transaction_id,
is_partner_initiated: channel.is_partner_initiated,
partner_public_key: channel.partner_public_key,
pending_balance: channel.pending_balance,
timelock_expiration: channel.timelock_expiration,
transaction_id: channel.transaction_id,
}));

// Pending opening channels
const opening = res.pending_channels
.filter(n => !!n.is_opening)
.map(channel => ({
is_partner_initiated: channel.is_partner_initiated,
local_balance: channel.local_balance,
partner_public_key: channel.partner_public_key,
remote_balance: channel.remote_balance,
transaction_fee: channel.transaction_fee,
transaction_id: channel.transaction_id,
}));

const peers = []
.concat(closing.map(n => n.partner_public_key))
.concat(opening.map(n => n.partner_public_key));

return map(
uniq(peers),
(id, cbk) => {
return getNodeAlias({ id, lnd }, cbk);
},
(err, nodes) => {
if (!!err) {
return cbk(err);
}

return getHeight({ lnd }, (err, res) => {
if (!!err) {
return cbk(err);
}

const height = res.current_block_height;

return cbk(null, { closing, height, nodes, opening });
});
}
);
});
},
cbk
);
},
],
// Notify of pending forwards and channels
notify: [
'getHtlcs',
'getPending',
async ({ getHtlcs, getPending }) => {
const summary = pendingSummary({
htlcs: getHtlcs,
pending: getPending,
});

return summary;
},
],
})
).notify;
};

export default getPending;
20 changes: 20 additions & 0 deletions src/server/commands/grpc_utils/icons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const icons = {
balanced_open: '⚖️',
block: '⏹',
bot: '🤖',
chain: '⛓',
closing: '⏳',
disconnected: '😵',
earn: '💰',
forwarding: '💸',
info: 'ℹ️',
liquidity: '🌊',
opening: '⏳',
probe: '👽',
rebalance: '☯️',
receive: '💵',
spent: '⚡️',
warning: '⚠️',
};

export default icons;
3 changes: 3 additions & 0 deletions src/server/commands/grpc_utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import getPending from './get_pending';

export { getPending };
Loading

0 comments on commit c541e26

Please sign in to comment.