This repository has been archived by the owner on Mar 14, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #131 from niteshbalusu11:niteshbalusu11/issue125
Adds a simple table on dashboard to get pending payments and channels on the node.
- Loading branch information
Showing
13 changed files
with
664 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
46
src/client/standard_components/app-components/BasicTable.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import getPending from './get_pending'; | ||
|
||
export { getPending }; |
Oops, something went wrong.