mirror of
https://github.com/apotdevin/thunderhub.git
synced 2025-02-22 14:22:33 +01:00
chore: 🔧 add bos score to channels (#207)
This commit is contained in:
parent
343f0e79fd
commit
e438f85ddf
18 changed files with 726 additions and 402 deletions
|
@ -96,6 +96,7 @@ export const channelTypes = gql`
|
|||
channel_age: Int!
|
||||
pending_payments: [pendingPaymentType]!
|
||||
pending_resume: pendingResumeType!
|
||||
bosScore: BosScore
|
||||
}
|
||||
|
||||
type closeChannelType {
|
||||
|
|
|
@ -105,6 +105,18 @@ const getBosNodeScoresQuery = `
|
|||
}
|
||||
`;
|
||||
|
||||
const getLastNodeScoreQuery = `
|
||||
query GetLastNodeScore($publicKey: String!, $token: String!) {
|
||||
getLastNodeScore(publicKey: $publicKey, token: $token) {
|
||||
alias
|
||||
public_key
|
||||
score
|
||||
updated
|
||||
position
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const tbaseResolvers = {
|
||||
Query: {
|
||||
getBaseInfo: async (_: undefined, __: undefined, context: ContextType) => {
|
||||
|
@ -318,4 +330,42 @@ export const tbaseResolvers = {
|
|||
return true;
|
||||
},
|
||||
},
|
||||
channelType: {
|
||||
bosScore: async (
|
||||
{
|
||||
partner_public_key,
|
||||
}: {
|
||||
partner_public_key: string;
|
||||
},
|
||||
_: undefined,
|
||||
{ tokenAuth }: ContextType
|
||||
) => {
|
||||
if (!tokenAuth) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { data, error } = await graphqlFetchWithProxy(
|
||||
appUrls.tbase,
|
||||
getLastNodeScoreQuery,
|
||||
{
|
||||
publicKey: partner_public_key,
|
||||
token: tokenAuth,
|
||||
}
|
||||
);
|
||||
|
||||
if (error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
data?.getLastNodeScore || {
|
||||
alias: '',
|
||||
public_key: partner_public_key,
|
||||
score: 0,
|
||||
updated: '',
|
||||
position: 0,
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -54,6 +54,8 @@ interface GetPriceProps {
|
|||
noUnit?: boolean;
|
||||
}
|
||||
|
||||
export type FormatFnType = (options: GetPriceProps) => string;
|
||||
|
||||
export const getPrice = (
|
||||
currency: string,
|
||||
displayValues: boolean,
|
||||
|
|
|
@ -31,6 +31,9 @@ export type GetChannelsQuery = (
|
|||
{ __typename?: 'nodePolicyType' }
|
||||
& Pick<Types.NodePolicyType, 'base_fee_mtokens' | 'fee_rate' | 'cltv_delta'>
|
||||
)> }
|
||||
)>, bosScore?: Types.Maybe<(
|
||||
{ __typename?: 'BosScore' }
|
||||
& Pick<Types.BosScore, 'alias' | 'public_key' | 'score' | 'updated' | 'position'>
|
||||
)> }
|
||||
)>> }
|
||||
);
|
||||
|
@ -93,6 +96,13 @@ export const GetChannelsDocument = gql`
|
|||
cltv_delta
|
||||
}
|
||||
}
|
||||
bosScore {
|
||||
alias
|
||||
public_key
|
||||
score
|
||||
updated
|
||||
position
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -260,6 +260,7 @@ Object {
|
|||
"data": Object {
|
||||
"getChannels": Array [
|
||||
Object {
|
||||
"bosScore": null,
|
||||
"capacity": 1000,
|
||||
"channel_age": 123356,
|
||||
"commit_transaction_fee": 1000,
|
||||
|
@ -310,6 +311,7 @@ Object {
|
|||
"unsettled_balance": 1000,
|
||||
},
|
||||
Object {
|
||||
"bosScore": null,
|
||||
"capacity": 1000,
|
||||
"channel_age": 123356,
|
||||
"commit_transaction_fee": 1000,
|
||||
|
@ -360,6 +362,7 @@ Object {
|
|||
"unsettled_balance": 1000,
|
||||
},
|
||||
Object {
|
||||
"bosScore": null,
|
||||
"capacity": 1000,
|
||||
"channel_age": 123356,
|
||||
"commit_transaction_fee": 1000,
|
||||
|
|
|
@ -57,6 +57,13 @@ export const GET_CHANNELS = gql`
|
|||
cltv_delta
|
||||
}
|
||||
}
|
||||
bosScore {
|
||||
alias
|
||||
public_key
|
||||
score
|
||||
updated
|
||||
position
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -680,6 +680,7 @@ export type ChannelType = {
|
|||
channel_age: Scalars['Int'];
|
||||
pending_payments: Array<Maybe<PendingPaymentType>>;
|
||||
pending_resume: PendingResumeType;
|
||||
bosScore?: Maybe<BosScore>;
|
||||
};
|
||||
|
||||
export type CloseChannelType = {
|
||||
|
|
166
src/views/channels/channels/ChannelBars.tsx
Normal file
166
src/views/channels/channels/ChannelBars.tsx
Normal file
|
@ -0,0 +1,166 @@
|
|||
import { FC } from 'react';
|
||||
import { BalanceBars, SingleBar, SumBar } from 'src/components/balance';
|
||||
import { ProgressBar } from 'src/components/generic/CardGeneric';
|
||||
import { FormatFnType } from 'src/components/price/Price';
|
||||
import { useConfigState } from 'src/context/ConfigContext';
|
||||
import { ChannelType } from 'src/graphql/types';
|
||||
import { getPercent } from 'src/utils/helpers';
|
||||
import { ChannelStatsColumn, ChannelStatsLine } from './Channel.style';
|
||||
import { WUMBO_MIN_SIZE } from './Channels';
|
||||
|
||||
const MAX_HTLCS = 483;
|
||||
|
||||
const getBar = (top: number, bottom: number) => {
|
||||
const percent = (top / bottom) * 100;
|
||||
return Math.min(percent, 100);
|
||||
};
|
||||
|
||||
type ChannelBarsProps = {
|
||||
info: ChannelType;
|
||||
format: FormatFnType;
|
||||
details: {
|
||||
biggestRateFee: number;
|
||||
biggestBaseFee: number;
|
||||
biggestPartner: number;
|
||||
mostChannels: number;
|
||||
biggest: number;
|
||||
};
|
||||
};
|
||||
|
||||
export const ChannelBars: FC<ChannelBarsProps> = ({
|
||||
info,
|
||||
format,
|
||||
details: {
|
||||
biggestRateFee,
|
||||
biggestBaseFee,
|
||||
biggestPartner,
|
||||
mostChannels,
|
||||
biggest,
|
||||
},
|
||||
}) => {
|
||||
const {
|
||||
partner_fee_info,
|
||||
partner_node_info,
|
||||
local_balance,
|
||||
remote_balance,
|
||||
pending_resume,
|
||||
} = info;
|
||||
|
||||
const { incoming_amount = 200, outgoing_amount = 150 } = pending_resume;
|
||||
|
||||
const { capacity: partnerNodeCapacity = 0, channel_count } =
|
||||
partner_node_info?.node || {};
|
||||
|
||||
const { base_fee_mtokens, fee_rate } =
|
||||
partner_fee_info?.partner_node_policies || {};
|
||||
|
||||
const { base_fee_mtokens: node_base, fee_rate: node_rate } =
|
||||
partner_fee_info?.node_policies || {};
|
||||
|
||||
const { channelBarType, subBar } = useConfigState();
|
||||
|
||||
const maxRate = Math.min(fee_rate || 0, 10000);
|
||||
const maxNodeRate = Math.min(node_rate || 0, 10000);
|
||||
|
||||
const localBalance = format({
|
||||
amount: local_balance,
|
||||
breakNumber: true,
|
||||
noUnit: true,
|
||||
});
|
||||
const remoteBalance = format({
|
||||
amount: remote_balance,
|
||||
breakNumber: true,
|
||||
noUnit: true,
|
||||
});
|
||||
|
||||
switch (channelBarType) {
|
||||
case 'fees':
|
||||
return (
|
||||
<ChannelStatsColumn>
|
||||
<BalanceBars
|
||||
local={getBar(maxNodeRate, biggestRateFee)}
|
||||
remote={getBar(maxRate, biggestRateFee)}
|
||||
height={10}
|
||||
/>
|
||||
<BalanceBars
|
||||
local={getBar(Number(node_base), biggestBaseFee)}
|
||||
remote={getBar(Number(base_fee_mtokens), biggestBaseFee)}
|
||||
height={10}
|
||||
/>
|
||||
</ChannelStatsColumn>
|
||||
);
|
||||
case 'size':
|
||||
return (
|
||||
<ChannelStatsColumn>
|
||||
<ChannelStatsLine>
|
||||
<ProgressBar
|
||||
order={0}
|
||||
percent={getBar(Number(partnerNodeCapacity), biggestPartner)}
|
||||
/>
|
||||
<ProgressBar
|
||||
order={4}
|
||||
percent={getBar(
|
||||
biggestPartner - Number(partnerNodeCapacity),
|
||||
biggestPartner
|
||||
)}
|
||||
/>
|
||||
</ChannelStatsLine>
|
||||
{channel_count && (
|
||||
<ChannelStatsLine>
|
||||
<ProgressBar
|
||||
order={6}
|
||||
percent={getBar(channel_count, mostChannels)}
|
||||
/>
|
||||
<ProgressBar
|
||||
order={4}
|
||||
percent={getBar(mostChannels - channel_count, mostChannels)}
|
||||
/>
|
||||
</ChannelStatsLine>
|
||||
)}
|
||||
</ChannelStatsColumn>
|
||||
);
|
||||
case 'proportional':
|
||||
return (
|
||||
<ChannelStatsColumn>
|
||||
{subBar === 'fees' && (
|
||||
<SingleBar value={getBar(maxRate, 2000)} height={4} />
|
||||
)}
|
||||
<BalanceBars
|
||||
local={getBar(local_balance, biggest)}
|
||||
remote={getBar(remote_balance, biggest)}
|
||||
formatLocal={localBalance}
|
||||
formatRemote={remoteBalance}
|
||||
withBorderColor={local_balance + remote_balance >= WUMBO_MIN_SIZE}
|
||||
/>
|
||||
</ChannelStatsColumn>
|
||||
);
|
||||
case 'htlcs':
|
||||
return (
|
||||
<ChannelStatsColumn>
|
||||
{subBar === 'fees' && (
|
||||
<SingleBar value={getBar(maxRate, 2000)} height={4} />
|
||||
)}
|
||||
<SumBar
|
||||
values={[
|
||||
getPercent(incoming_amount, MAX_HTLCS - incoming_amount),
|
||||
getPercent(outgoing_amount, MAX_HTLCS - outgoing_amount),
|
||||
]}
|
||||
/>
|
||||
</ChannelStatsColumn>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<ChannelStatsColumn>
|
||||
{subBar === 'fees' && (
|
||||
<SingleBar value={getBar(maxRate, 2000)} height={4} />
|
||||
)}
|
||||
<BalanceBars
|
||||
local={getPercent(local_balance, remote_balance)}
|
||||
remote={getPercent(remote_balance, local_balance)}
|
||||
formatLocal={localBalance}
|
||||
formatRemote={remoteBalance}
|
||||
/>
|
||||
</ChannelStatsColumn>
|
||||
);
|
||||
}
|
||||
};
|
106
src/views/channels/channels/ChannelBarsInfo.tsx
Normal file
106
src/views/channels/channels/ChannelBarsInfo.tsx
Normal file
|
@ -0,0 +1,106 @@
|
|||
import { FC } from 'react';
|
||||
import { renderLine } from 'src/components/generic/helpers';
|
||||
import { Separation, SubTitle } from 'src/components/generic/Styled';
|
||||
import { FormatFnType } from 'src/components/price/Price';
|
||||
import { useConfigState } from 'src/context/ConfigContext';
|
||||
import { ChannelType } from 'src/graphql/types';
|
||||
|
||||
const MAX_HTLCS = 483;
|
||||
|
||||
type ChannelBarsInfoProps = {
|
||||
info: ChannelType;
|
||||
format: FormatFnType;
|
||||
};
|
||||
|
||||
export const ChannelBarsInfo: FC<ChannelBarsInfoProps> = ({
|
||||
info: {
|
||||
local_balance,
|
||||
remote_balance,
|
||||
partner_fee_info,
|
||||
partner_node_info,
|
||||
pending_resume,
|
||||
},
|
||||
format,
|
||||
}) => {
|
||||
const { channelBarType } = useConfigState();
|
||||
|
||||
const {
|
||||
total_amount,
|
||||
incoming_amount = 200,
|
||||
outgoing_amount = 150,
|
||||
} = pending_resume;
|
||||
|
||||
const { capacity: partnerNodeCapacity = 0, channel_count } =
|
||||
partner_node_info?.node || {};
|
||||
|
||||
const { base_fee_mtokens, fee_rate } =
|
||||
partner_fee_info?.partner_node_policies || {};
|
||||
|
||||
const { base_fee_mtokens: node_base, fee_rate: node_rate } =
|
||||
partner_fee_info?.node_policies || {};
|
||||
|
||||
const feeRate = format({ amount: fee_rate, override: 'ppm' });
|
||||
const nodeFeeRate = format({ amount: node_rate, override: 'ppm' });
|
||||
|
||||
const formatLocal = format({ amount: local_balance });
|
||||
const formatRemote = format({ amount: remote_balance });
|
||||
const nodeCapacity = format({ amount: partnerNodeCapacity });
|
||||
const baseFee = format({
|
||||
amount: Number(base_fee_mtokens) / 1000,
|
||||
override: 'sat',
|
||||
});
|
||||
|
||||
const nodeBaseFee = format({
|
||||
amount: Number(node_base) / 1000,
|
||||
override: 'sat',
|
||||
});
|
||||
|
||||
switch (channelBarType) {
|
||||
case 'fees':
|
||||
return (
|
||||
<>
|
||||
{renderLine('Fee Rate', nodeFeeRate)}
|
||||
{renderLine('Partner Fee Rate', feeRate)}
|
||||
<Separation />
|
||||
{renderLine('Base Fee', nodeBaseFee)}
|
||||
{renderLine('Partner Base Fee', baseFee)}
|
||||
</>
|
||||
);
|
||||
case 'size':
|
||||
return (
|
||||
<>
|
||||
{renderLine('Partner Capacity', nodeCapacity)}
|
||||
{renderLine('Partner Channels', channel_count)}
|
||||
</>
|
||||
);
|
||||
case 'proportional':
|
||||
return (
|
||||
<>
|
||||
{renderLine('Local Balance', formatLocal)}
|
||||
{renderLine('Remote Balance', formatRemote)}
|
||||
</>
|
||||
);
|
||||
case 'htlcs':
|
||||
return (
|
||||
<>
|
||||
<SubTitle>Pending HTLCS</SubTitle>
|
||||
{renderLine('Total', `${total_amount}/${MAX_HTLCS}`)}
|
||||
{renderLine(
|
||||
'Incoming',
|
||||
`${incoming_amount}/${MAX_HTLCS - outgoing_amount}`
|
||||
)}
|
||||
{renderLine(
|
||||
'Outgoing',
|
||||
`${outgoing_amount}/${MAX_HTLCS - incoming_amount}`
|
||||
)}
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<>
|
||||
{renderLine('Local Balance', formatLocal)}
|
||||
{renderLine('Remote Balance', formatRemote)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
62
src/views/channels/channels/ChannelBosScore.tsx
Normal file
62
src/views/channels/channels/ChannelBosScore.tsx
Normal file
|
@ -0,0 +1,62 @@
|
|||
import { FC } from 'react';
|
||||
import {
|
||||
getDateDif,
|
||||
getFormatDate,
|
||||
renderLine,
|
||||
} from 'src/components/generic/helpers';
|
||||
import { DarkSubTitle } from 'src/components/generic/Styled';
|
||||
import { Link } from 'src/components/link/Link';
|
||||
import { BosScore } from 'src/graphql/types';
|
||||
import { chartColors } from 'src/styles/Themes';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const S = {
|
||||
missingToken: styled.div`
|
||||
width: 100%;
|
||||
border: 1px solid ${chartColors.darkyellow};
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
margin: 8px 0 0;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
|
||||
:hover {
|
||||
background-color: ${chartColors.darkyellow};
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const ChannelBosScore: FC<{ score?: BosScore | null }> = ({ score }) => {
|
||||
if (!score) {
|
||||
return (
|
||||
<>
|
||||
BOS Score
|
||||
<Link to={'/token'} noStyling={true}>
|
||||
<S.missingToken>
|
||||
Get a token to view this nodes latest BOS score and historical info.
|
||||
</S.missingToken>
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (!score.alias) {
|
||||
return (
|
||||
<DarkSubTitle>This node has not appeared in the BOS list</DarkSubTitle>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
BOS Score
|
||||
{renderLine('Score', score.score)}
|
||||
{renderLine('Position', score.position)}
|
||||
{renderLine('Last Time on List', `${getDateDif(score.updated)} ago`)}
|
||||
{renderLine('Last Time Date', getFormatDate(score.updated))}
|
||||
{renderLine(
|
||||
'Historical',
|
||||
<Link to={`/scores/${score.public_key}`}>View History</Link>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from 'react';
|
||||
import React from 'react';
|
||||
import ReactTooltip from 'react-tooltip';
|
||||
import {
|
||||
ArrowDown,
|
||||
|
@ -9,56 +9,34 @@ import {
|
|||
X,
|
||||
} from 'react-feather';
|
||||
import { ChannelType } from 'src/graphql/types';
|
||||
import { BalanceBars, SingleBar, SumBar } from 'src/components/balance';
|
||||
import {
|
||||
useRebalanceState,
|
||||
useRebalanceDispatch,
|
||||
} from 'src/context/RebalanceContext';
|
||||
import { ChangeDetails } from 'src/components/modal/changeDetails/ChangeDetails';
|
||||
import {
|
||||
getPercent,
|
||||
formatSeconds,
|
||||
blockToTime,
|
||||
formatSats,
|
||||
} from '../../../utils/helpers';
|
||||
import { ProgressBar, MainInfo } from '../../../components/generic/CardGeneric';
|
||||
import differenceInDays from 'date-fns/differenceInDays';
|
||||
import { MainInfo } from '../../../components/generic/CardGeneric';
|
||||
import {
|
||||
SubCard,
|
||||
Separation,
|
||||
Sub4Title,
|
||||
ResponsiveLine,
|
||||
DarkSubTitle,
|
||||
SubTitle,
|
||||
} from '../../../components/generic/Styled';
|
||||
import { useConfigState } from '../../../context/ConfigContext';
|
||||
import {
|
||||
getFormatDate,
|
||||
getDateDif,
|
||||
renderLine,
|
||||
getTransactionLink,
|
||||
getNodeLink,
|
||||
} from '../../../components/generic/helpers';
|
||||
import Modal from '../../../components/modal/ReactModal';
|
||||
import { CloseChannel } from '../../../components/modal/closeChannel/CloseChannel';
|
||||
import { ColorButton } from '../../../components/buttons/colorButton/ColorButton';
|
||||
import { renderLine } from '../../../components/generic/helpers';
|
||||
import { getPrice } from '../../../components/price/Price';
|
||||
import { usePriceState } from '../../../context/PriceContext';
|
||||
import {
|
||||
ChannelNodeTitle,
|
||||
ChannelBarSide,
|
||||
ChannelIconPadding,
|
||||
ChannelStatsColumn,
|
||||
ChannelSingleLine,
|
||||
ChannelStatsLine,
|
||||
ChannelBalanceRow,
|
||||
ChannelBalanceButton,
|
||||
WumboTag,
|
||||
ChannelAlias,
|
||||
} from './Channel.style';
|
||||
import { WUMBO_MIN_SIZE } from './Channels';
|
||||
import { getTitleColor } from './helpers';
|
||||
|
||||
const MAX_HTLCS = 483;
|
||||
import { ChannelDetails } from './ChannelDetails';
|
||||
import { ChannelBars } from './ChannelBars';
|
||||
import { ChannelBarsInfo } from './ChannelBarsInfo';
|
||||
|
||||
const getSymbol = (status: boolean) => {
|
||||
return status ? <ArrowDown size={14} /> : <ArrowUp size={14} />;
|
||||
|
@ -68,11 +46,6 @@ const getPrivate = (status: boolean) => {
|
|||
return status && <EyeOff size={14} />;
|
||||
};
|
||||
|
||||
const getBar = (top: number, bottom: number) => {
|
||||
const percent = (top / bottom) * 100;
|
||||
return Math.min(percent, 100);
|
||||
};
|
||||
|
||||
interface ChannelCardProps {
|
||||
channelInfo: ChannelType;
|
||||
index: number;
|
||||
|
@ -99,8 +72,7 @@ export const ChannelCard: React.FC<ChannelCardProps> = ({
|
|||
const dispatch = useRebalanceDispatch();
|
||||
const { inChannel, outChannel } = useRebalanceState();
|
||||
|
||||
const { channelBarType, channelBarStyle, subBar } = useConfigState();
|
||||
const [modalOpen, setModalOpen] = useState<string>('none');
|
||||
const { channelBarStyle } = useConfigState();
|
||||
|
||||
const { currency, displayValues } = useConfigState();
|
||||
const priceContext = usePriceState();
|
||||
|
@ -108,103 +80,39 @@ export const ChannelCard: React.FC<ChannelCardProps> = ({
|
|||
|
||||
const {
|
||||
capacity,
|
||||
commit_transaction_fee,
|
||||
commit_transaction_weight,
|
||||
id,
|
||||
is_active,
|
||||
is_closing,
|
||||
is_opening,
|
||||
is_partner_initiated,
|
||||
is_private,
|
||||
is_static_remote_key,
|
||||
local_balance,
|
||||
local_reserve,
|
||||
partner_public_key,
|
||||
received,
|
||||
remote_balance,
|
||||
remote_reserve,
|
||||
sent,
|
||||
time_offline,
|
||||
time_online,
|
||||
transaction_id,
|
||||
transaction_vout,
|
||||
unsettled_balance,
|
||||
partner_node_info,
|
||||
partner_fee_info,
|
||||
channel_age,
|
||||
pending_resume,
|
||||
bosScore,
|
||||
} = channelInfo;
|
||||
|
||||
const {
|
||||
total_amount,
|
||||
total_tokens,
|
||||
incoming_tokens,
|
||||
incoming_amount = 200,
|
||||
outgoing_tokens,
|
||||
outgoing_amount = 150,
|
||||
} = pending_resume;
|
||||
const barDetails = {
|
||||
biggestRateFee,
|
||||
biggestBaseFee,
|
||||
biggestPartner,
|
||||
mostChannels,
|
||||
biggest,
|
||||
};
|
||||
|
||||
let withinAWeek = false;
|
||||
|
||||
if (bosScore?.updated) {
|
||||
withinAWeek = differenceInDays(new Date(), new Date(bosScore.updated)) < 7;
|
||||
}
|
||||
|
||||
const isBosNode = !!bosScore?.alias && withinAWeek;
|
||||
|
||||
const isIn = inChannel?.id === id;
|
||||
const isOut = outChannel?.id === id;
|
||||
|
||||
const {
|
||||
alias,
|
||||
capacity: partnerNodeCapacity = 0,
|
||||
channel_count,
|
||||
updated_at,
|
||||
} = partner_node_info?.node || {};
|
||||
|
||||
const { base_fee_mtokens, fee_rate, cltv_delta } =
|
||||
partner_fee_info?.partner_node_policies || {};
|
||||
|
||||
const {
|
||||
base_fee_mtokens: node_base,
|
||||
fee_rate: node_rate,
|
||||
cltv_delta: node_cltv,
|
||||
max_htlc_mtokens,
|
||||
min_htlc_mtokens,
|
||||
} = partner_fee_info?.node_policies || {};
|
||||
const { alias } = partner_node_info?.node || {};
|
||||
|
||||
const formatBalance = format({ amount: capacity });
|
||||
const formatLocal = format({ amount: local_balance });
|
||||
const formatRemote = format({ amount: remote_balance });
|
||||
const formatReceived = format({ amount: received });
|
||||
const formatSent = format({ amount: sent });
|
||||
const commitFee = format({ amount: commit_transaction_fee });
|
||||
const commitWeight = format({ amount: commit_transaction_weight });
|
||||
const localReserve = format({ amount: local_reserve });
|
||||
const remoteReserve = format({ amount: remote_reserve });
|
||||
const nodeCapacity = format({ amount: partnerNodeCapacity });
|
||||
|
||||
const localBalance = format({
|
||||
amount: local_balance,
|
||||
breakNumber: true,
|
||||
noUnit: true,
|
||||
});
|
||||
const remoteBalance = format({
|
||||
amount: remote_balance,
|
||||
breakNumber: true,
|
||||
noUnit: true,
|
||||
});
|
||||
|
||||
const baseFee = format({
|
||||
amount: Number(base_fee_mtokens) / 1000,
|
||||
override: 'sat',
|
||||
});
|
||||
|
||||
const nodeBaseFee = format({
|
||||
amount: Number(node_base) / 1000,
|
||||
override: 'sat',
|
||||
});
|
||||
|
||||
const maxRate = Math.min(fee_rate || 0, 10000);
|
||||
const feeRate = format({ amount: fee_rate, override: 'ppm' });
|
||||
|
||||
const maxNodeRate = Math.min(node_rate || 0, 10000);
|
||||
const nodeFeeRate = format({ amount: node_rate, override: 'ppm' });
|
||||
|
||||
const max_htlc = Number(max_htlc_mtokens) / 1000;
|
||||
const min_htlc = Number(min_htlc_mtokens) / 1000;
|
||||
|
||||
const handleClick = () => {
|
||||
if (indexOpen === index) {
|
||||
|
@ -214,256 +122,6 @@ export const ChannelCard: React.FC<ChannelCardProps> = ({
|
|||
}
|
||||
};
|
||||
|
||||
const renderPartner = () =>
|
||||
alias ? (
|
||||
<>
|
||||
{renderLine('Node Capacity:', nodeCapacity)}
|
||||
{renderLine('Channel Count:', channel_count)}
|
||||
{renderLine(
|
||||
'Last Update:',
|
||||
`${getDateDif(updated_at)} ago (${getFormatDate(updated_at)})`
|
||||
)}
|
||||
{renderLine('Base Fee:', baseFee)}
|
||||
{renderLine('Fee Rate:', `${feeRate}`)}
|
||||
{renderLine('CTLV Delta:', cltv_delta)}
|
||||
</>
|
||||
) : (
|
||||
<DarkSubTitle>Partner node not found</DarkSubTitle>
|
||||
);
|
||||
|
||||
const renderWumboInfo = () => {
|
||||
if (local_balance + remote_balance >= WUMBO_MIN_SIZE) {
|
||||
return (
|
||||
<>
|
||||
<Separation />
|
||||
<WumboTag>This channel is Wumbo!</WumboTag>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const renderDetails = () => {
|
||||
return (
|
||||
<>
|
||||
{renderWumboInfo()}
|
||||
<Separation />
|
||||
{renderLine('Status:', is_active ? 'Active' : 'Not Active')}
|
||||
{renderLine('Is Opening:', is_opening ? 'True' : 'False')}
|
||||
{renderLine('Is Closing:', is_closing ? 'True' : 'False')}
|
||||
{renderLine(
|
||||
'Balancedness:',
|
||||
getPercent(local_balance, remote_balance) / 100
|
||||
)}
|
||||
<Separation />
|
||||
{renderLine('Base Fee:', nodeBaseFee)}
|
||||
{renderLine('Fee Rate:', `${nodeFeeRate}`)}
|
||||
{renderLine('CTLV Delta:', node_cltv)}
|
||||
{renderLine('Max HTLC (sats)', formatSats(max_htlc))}
|
||||
{renderLine('Min HTLC (sats)', formatSats(min_htlc))}
|
||||
<ColorButton
|
||||
fullWidth={true}
|
||||
withBorder={true}
|
||||
arrow={true}
|
||||
onClick={() => setModalOpen('details')}
|
||||
>
|
||||
Update Details
|
||||
</ColorButton>
|
||||
<Separation />
|
||||
{renderLine('Local Balance:', formatLocal)}
|
||||
{renderLine('Remote Balance:', formatRemote)}
|
||||
{renderLine('Received:', formatReceived)}
|
||||
{renderLine('Sent:', formatSent)}
|
||||
{renderLine('Local Reserve:', localReserve)}
|
||||
{renderLine('Remote Reserve:', remoteReserve)}
|
||||
<Separation />
|
||||
{renderLine('Node Public Key:', getNodeLink(partner_public_key))}
|
||||
{renderLine('Transaction Id:', getTransactionLink(transaction_id))}
|
||||
<Separation />
|
||||
<Sub4Title>Pending HTLCS</Sub4Title>
|
||||
{!total_amount && renderLine('Total Amount', 'None')}
|
||||
{renderLine('Total Amount', total_amount)}
|
||||
{renderLine('Total Tokens', total_tokens)}
|
||||
{renderLine('Incoming Tokens', incoming_tokens)}
|
||||
{renderLine('Outgoing Tokens', outgoing_tokens)}
|
||||
{renderLine('Incoming Amount', incoming_amount)}
|
||||
{renderLine('Outgoing Amount', outgoing_amount)}
|
||||
<Separation />
|
||||
{renderLine('Channel Age:', blockToTime(channel_age))}
|
||||
{renderLine('Channel Block Age:', channel_age)}
|
||||
{renderLine('Channel Id:', id)}
|
||||
{renderLine('Commit Fee:', commitFee)}
|
||||
{renderLine('Commit Weight:', commitWeight)}
|
||||
<Separation />
|
||||
{renderLine(
|
||||
'Is Static Remote Key:',
|
||||
is_static_remote_key ? 'True' : 'False'
|
||||
)}
|
||||
{renderLine('Time Offline:', formatSeconds(time_offline))}
|
||||
{renderLine('Time Online:', formatSeconds(time_online))}
|
||||
{renderLine('Transaction Vout:', transaction_vout)}
|
||||
{renderLine('Unsettled Balance:', unsettled_balance)}
|
||||
<Separation />
|
||||
<Sub4Title>Partner Node Info</Sub4Title>
|
||||
{renderPartner()}
|
||||
<Separation />
|
||||
<ColorButton
|
||||
fullWidth={true}
|
||||
withBorder={true}
|
||||
arrow={true}
|
||||
onClick={() => setModalOpen('close')}
|
||||
>
|
||||
Close Channel
|
||||
</ColorButton>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const renderBars = () => {
|
||||
switch (channelBarType) {
|
||||
case 'fees':
|
||||
return (
|
||||
<ChannelStatsColumn>
|
||||
<BalanceBars
|
||||
local={getBar(maxNodeRate, biggestRateFee)}
|
||||
remote={getBar(maxRate, biggestRateFee)}
|
||||
height={10}
|
||||
/>
|
||||
<BalanceBars
|
||||
local={getBar(Number(node_base), biggestBaseFee)}
|
||||
remote={getBar(Number(base_fee_mtokens), biggestBaseFee)}
|
||||
height={10}
|
||||
/>
|
||||
</ChannelStatsColumn>
|
||||
);
|
||||
case 'size':
|
||||
return (
|
||||
<ChannelStatsColumn>
|
||||
<ChannelStatsLine>
|
||||
<ProgressBar
|
||||
order={0}
|
||||
percent={getBar(Number(partnerNodeCapacity), biggestPartner)}
|
||||
/>
|
||||
<ProgressBar
|
||||
order={4}
|
||||
percent={getBar(
|
||||
biggestPartner - Number(partnerNodeCapacity),
|
||||
biggestPartner
|
||||
)}
|
||||
/>
|
||||
</ChannelStatsLine>
|
||||
{channel_count && (
|
||||
<ChannelStatsLine>
|
||||
<ProgressBar
|
||||
order={6}
|
||||
percent={getBar(channel_count, mostChannels)}
|
||||
/>
|
||||
<ProgressBar
|
||||
order={4}
|
||||
percent={getBar(mostChannels - channel_count, mostChannels)}
|
||||
/>
|
||||
</ChannelStatsLine>
|
||||
)}
|
||||
</ChannelStatsColumn>
|
||||
);
|
||||
case 'proportional':
|
||||
return (
|
||||
<ChannelStatsColumn>
|
||||
{subBar === 'fees' && (
|
||||
<SingleBar value={getBar(maxRate, 2000)} height={4} />
|
||||
)}
|
||||
<BalanceBars
|
||||
local={getBar(local_balance, biggest)}
|
||||
remote={getBar(remote_balance, biggest)}
|
||||
formatLocal={localBalance}
|
||||
formatRemote={remoteBalance}
|
||||
withBorderColor={local_balance + remote_balance >= WUMBO_MIN_SIZE}
|
||||
/>
|
||||
</ChannelStatsColumn>
|
||||
);
|
||||
case 'htlcs':
|
||||
return (
|
||||
<ChannelStatsColumn>
|
||||
{subBar === 'fees' && (
|
||||
<SingleBar value={getBar(maxRate, 2000)} height={4} />
|
||||
)}
|
||||
<SumBar
|
||||
values={[
|
||||
getPercent(incoming_amount, MAX_HTLCS - incoming_amount),
|
||||
getPercent(outgoing_amount, MAX_HTLCS - outgoing_amount),
|
||||
]}
|
||||
/>
|
||||
</ChannelStatsColumn>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<ChannelStatsColumn>
|
||||
{subBar === 'fees' && (
|
||||
<SingleBar value={getBar(maxRate, 2000)} height={4} />
|
||||
)}
|
||||
<BalanceBars
|
||||
local={getPercent(local_balance, remote_balance)}
|
||||
remote={getPercent(remote_balance, local_balance)}
|
||||
formatLocal={localBalance}
|
||||
formatRemote={remoteBalance}
|
||||
/>
|
||||
</ChannelStatsColumn>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const renderBarsInfo = () => {
|
||||
switch (channelBarType) {
|
||||
case 'fees':
|
||||
return (
|
||||
<>
|
||||
{renderLine('Fee Rate', nodeFeeRate)}
|
||||
{renderLine('Partner Fee Rate', feeRate)}
|
||||
<Separation />
|
||||
{renderLine('Base Fee', nodeBaseFee)}
|
||||
{renderLine('Partner Base Fee', baseFee)}
|
||||
</>
|
||||
);
|
||||
case 'size':
|
||||
return (
|
||||
<>
|
||||
{renderLine('Partner Capacity', nodeCapacity)}
|
||||
{renderLine('Partner Channels', channel_count)}
|
||||
</>
|
||||
);
|
||||
case 'proportional':
|
||||
return (
|
||||
<>
|
||||
{renderLine('Local Balance', formatLocal)}
|
||||
{renderLine('Remote Balance', formatRemote)}
|
||||
</>
|
||||
);
|
||||
case 'htlcs':
|
||||
return (
|
||||
<>
|
||||
<SubTitle>Pending HTLCS</SubTitle>
|
||||
{renderLine('Total', `${total_amount}/${MAX_HTLCS}`)}
|
||||
{renderLine(
|
||||
'Incoming',
|
||||
`${incoming_amount}/${MAX_HTLCS - outgoing_amount}`
|
||||
)}
|
||||
{renderLine(
|
||||
'Outgoing',
|
||||
`${outgoing_amount}/${MAX_HTLCS - incoming_amount}`
|
||||
)}
|
||||
</>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<>
|
||||
{renderLine('Local Balance', formatLocal)}
|
||||
{renderLine('Remote Balance', formatRemote)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const getSubCardProps = () => {
|
||||
switch (channelBarStyle) {
|
||||
case 'ultracompact':
|
||||
|
@ -496,7 +154,12 @@ export const ChannelCard: React.FC<ChannelCardProps> = ({
|
|||
data-for={`node_status_tip_${index}`}
|
||||
>
|
||||
<ChannelAlias
|
||||
textColor={getTitleColor(is_active, is_opening, is_closing)}
|
||||
textColor={getTitleColor(
|
||||
is_active,
|
||||
is_opening,
|
||||
is_closing,
|
||||
isBosNode
|
||||
)}
|
||||
>
|
||||
{alias || partner_public_key?.substring(0, 6)}
|
||||
</ChannelAlias>
|
||||
|
@ -514,7 +177,11 @@ export const ChannelCard: React.FC<ChannelCardProps> = ({
|
|||
)}
|
||||
</ChannelNodeTitle>
|
||||
<ChannelBarSide data-tip data-for={`node_balance_tip_${index}`}>
|
||||
{renderBars()}
|
||||
<ChannelBars
|
||||
info={channelInfo}
|
||||
details={barDetails}
|
||||
format={format}
|
||||
/>
|
||||
{channelBarStyle === 'balancing' && (
|
||||
<ChannelBalanceRow>
|
||||
<ChannelBalanceButton
|
||||
|
@ -544,12 +211,15 @@ export const ChannelCard: React.FC<ChannelCardProps> = ({
|
|||
</ChannelBarSide>
|
||||
</ResponsiveLine>
|
||||
</MainInfo>
|
||||
{index === indexOpen && renderDetails()}
|
||||
{index === indexOpen && (
|
||||
<ChannelDetails info={channelInfo} format={format} />
|
||||
)}
|
||||
<ReactTooltip
|
||||
id={`node_status_tip_${index}`}
|
||||
effect={'solid'}
|
||||
place={'bottom'}
|
||||
>
|
||||
{isBosNode && renderLine('BOS Node', 'True')}
|
||||
{renderLine('Status:', is_active ? 'Active' : 'Not Active')}
|
||||
{is_opening && renderLine('Is Opening:', 'True')}
|
||||
{is_closing && renderLine('Is Closing:', 'True')}
|
||||
|
@ -559,31 +229,8 @@ export const ChannelCard: React.FC<ChannelCardProps> = ({
|
|||
effect={'solid'}
|
||||
place={'bottom'}
|
||||
>
|
||||
{renderBarsInfo()}
|
||||
<ChannelBarsInfo info={channelInfo} format={format} />
|
||||
</ReactTooltip>
|
||||
<Modal
|
||||
isOpen={modalOpen !== 'none'}
|
||||
closeCallback={() => setModalOpen('none')}
|
||||
>
|
||||
{modalOpen === 'close' ? (
|
||||
<CloseChannel
|
||||
callback={() => setModalOpen('none')}
|
||||
channelId={id}
|
||||
channelName={alias}
|
||||
/>
|
||||
) : (
|
||||
<ChangeDetails
|
||||
callback={() => setModalOpen('none')}
|
||||
transaction_id={transaction_id}
|
||||
transaction_vout={transaction_vout}
|
||||
base_fee_mtokens={node_base}
|
||||
max_htlc_mtokens={max_htlc_mtokens}
|
||||
min_htlc_mtokens={min_htlc_mtokens}
|
||||
fee_rate={node_rate}
|
||||
cltv_delta={node_cltv}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
</SubCard>
|
||||
);
|
||||
};
|
||||
|
|
247
src/views/channels/channels/ChannelDetails.tsx
Normal file
247
src/views/channels/channels/ChannelDetails.tsx
Normal file
|
@ -0,0 +1,247 @@
|
|||
import { FC, useState } from 'react';
|
||||
import { ColorButton } from 'src/components/buttons/colorButton/ColorButton';
|
||||
import {
|
||||
getDateDif,
|
||||
getFormatDate,
|
||||
getNodeLink,
|
||||
getTransactionLink,
|
||||
renderLine,
|
||||
} from 'src/components/generic/helpers';
|
||||
import {
|
||||
DarkSubTitle,
|
||||
Separation,
|
||||
Sub4Title,
|
||||
} from 'src/components/generic/Styled';
|
||||
import { ChangeDetails } from 'src/components/modal/changeDetails/ChangeDetails';
|
||||
import { CloseChannel } from 'src/components/modal/closeChannel/CloseChannel';
|
||||
import Modal from 'src/components/modal/ReactModal';
|
||||
import { ChannelType } from 'src/graphql/types';
|
||||
import {
|
||||
blockToTime,
|
||||
formatSats,
|
||||
formatSeconds,
|
||||
getPercent,
|
||||
} from 'src/utils/helpers';
|
||||
import { FormatFnType } from 'src/components/price/Price';
|
||||
import { ChannelBosScore } from './ChannelBosScore';
|
||||
import { WUMBO_MIN_SIZE } from './Channels';
|
||||
import { WumboTag } from './Channel.style';
|
||||
|
||||
type ChannelDetailsProps = {
|
||||
info: ChannelType;
|
||||
format: FormatFnType;
|
||||
};
|
||||
|
||||
export const ChannelDetails: FC<ChannelDetailsProps> = ({
|
||||
info: {
|
||||
commit_transaction_fee,
|
||||
commit_transaction_weight,
|
||||
id,
|
||||
is_active,
|
||||
is_closing,
|
||||
is_opening,
|
||||
is_static_remote_key,
|
||||
local_balance,
|
||||
local_reserve,
|
||||
partner_public_key,
|
||||
received,
|
||||
remote_balance,
|
||||
remote_reserve,
|
||||
sent,
|
||||
time_offline,
|
||||
time_online,
|
||||
transaction_id,
|
||||
transaction_vout,
|
||||
unsettled_balance,
|
||||
partner_node_info,
|
||||
partner_fee_info,
|
||||
channel_age,
|
||||
pending_resume,
|
||||
bosScore,
|
||||
},
|
||||
format,
|
||||
}) => {
|
||||
const [modalOpen, setModalOpen] = useState<string>('none');
|
||||
|
||||
const {
|
||||
total_amount,
|
||||
total_tokens,
|
||||
incoming_tokens,
|
||||
incoming_amount = 200,
|
||||
outgoing_tokens,
|
||||
outgoing_amount = 150,
|
||||
} = pending_resume;
|
||||
|
||||
const {
|
||||
alias,
|
||||
capacity: partnerNodeCapacity = 0,
|
||||
channel_count,
|
||||
updated_at,
|
||||
} = partner_node_info?.node || {};
|
||||
|
||||
const { base_fee_mtokens, fee_rate, cltv_delta } =
|
||||
partner_fee_info?.partner_node_policies || {};
|
||||
|
||||
const {
|
||||
base_fee_mtokens: node_base,
|
||||
fee_rate: node_rate,
|
||||
cltv_delta: node_cltv,
|
||||
max_htlc_mtokens,
|
||||
min_htlc_mtokens,
|
||||
} = partner_fee_info?.node_policies || {};
|
||||
|
||||
const formatLocal = format({ amount: local_balance });
|
||||
const formatRemote = format({ amount: remote_balance });
|
||||
const formatReceived = format({ amount: received });
|
||||
const formatSent = format({ amount: sent });
|
||||
const commitFee = format({ amount: commit_transaction_fee });
|
||||
const commitWeight = format({ amount: commit_transaction_weight });
|
||||
const localReserve = format({ amount: local_reserve });
|
||||
const remoteReserve = format({ amount: remote_reserve });
|
||||
const nodeCapacity = format({ amount: partnerNodeCapacity });
|
||||
|
||||
const baseFee = format({
|
||||
amount: Number(base_fee_mtokens) / 1000,
|
||||
override: 'sat',
|
||||
});
|
||||
|
||||
const nodeBaseFee = format({
|
||||
amount: Number(node_base) / 1000,
|
||||
override: 'sat',
|
||||
});
|
||||
|
||||
const feeRate = format({ amount: fee_rate, override: 'ppm' });
|
||||
const nodeFeeRate = format({ amount: node_rate, override: 'ppm' });
|
||||
|
||||
const max_htlc = Number(max_htlc_mtokens) / 1000;
|
||||
const min_htlc = Number(min_htlc_mtokens) / 1000;
|
||||
|
||||
const renderPartner = () =>
|
||||
alias ? (
|
||||
<>
|
||||
{renderLine('Node Capacity:', nodeCapacity)}
|
||||
{renderLine('Channel Count:', channel_count)}
|
||||
{renderLine(
|
||||
'Last Update:',
|
||||
`${getDateDif(updated_at)} ago (${getFormatDate(updated_at)})`
|
||||
)}
|
||||
{renderLine('Base Fee:', baseFee)}
|
||||
{renderLine('Fee Rate:', `${feeRate}`)}
|
||||
{renderLine('CTLV Delta:', cltv_delta)}
|
||||
</>
|
||||
) : (
|
||||
<DarkSubTitle>Partner node not found</DarkSubTitle>
|
||||
);
|
||||
|
||||
const renderWumboInfo = () => {
|
||||
if (local_balance + remote_balance >= WUMBO_MIN_SIZE) {
|
||||
return (
|
||||
<>
|
||||
<Separation />
|
||||
<WumboTag>This channel is Wumbo!</WumboTag>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderWumboInfo()}
|
||||
<Separation />
|
||||
{renderLine('Status:', is_active ? 'Active' : 'Not Active')}
|
||||
{renderLine('Is Opening:', is_opening ? 'True' : 'False')}
|
||||
{renderLine('Is Closing:', is_closing ? 'True' : 'False')}
|
||||
{renderLine(
|
||||
'Balancedness:',
|
||||
getPercent(local_balance, remote_balance) / 100
|
||||
)}
|
||||
<Separation />
|
||||
<ChannelBosScore score={bosScore} />
|
||||
<Separation />
|
||||
{renderLine('Base Fee:', nodeBaseFee)}
|
||||
{renderLine('Fee Rate:', `${nodeFeeRate}`)}
|
||||
{renderLine('CTLV Delta:', node_cltv)}
|
||||
{renderLine('Max HTLC (sats)', formatSats(max_htlc))}
|
||||
{renderLine('Min HTLC (sats)', formatSats(min_htlc))}
|
||||
<ColorButton
|
||||
fullWidth={true}
|
||||
withBorder={true}
|
||||
arrow={true}
|
||||
onClick={() => setModalOpen('details')}
|
||||
>
|
||||
Update Details
|
||||
</ColorButton>
|
||||
<Separation />
|
||||
{renderLine('Local Balance:', formatLocal)}
|
||||
{renderLine('Remote Balance:', formatRemote)}
|
||||
{renderLine('Received:', formatReceived)}
|
||||
{renderLine('Sent:', formatSent)}
|
||||
{renderLine('Local Reserve:', localReserve)}
|
||||
{renderLine('Remote Reserve:', remoteReserve)}
|
||||
<Separation />
|
||||
{renderLine('Node Public Key:', getNodeLink(partner_public_key))}
|
||||
{renderLine('Transaction Id:', getTransactionLink(transaction_id))}
|
||||
<Separation />
|
||||
<Sub4Title>Pending HTLCS</Sub4Title>
|
||||
{!total_amount && renderLine('Total Amount', 'None')}
|
||||
{renderLine('Total Amount', total_amount)}
|
||||
{renderLine('Total Tokens', total_tokens)}
|
||||
{renderLine('Incoming Tokens', incoming_tokens)}
|
||||
{renderLine('Outgoing Tokens', outgoing_tokens)}
|
||||
{renderLine('Incoming Amount', incoming_amount)}
|
||||
{renderLine('Outgoing Amount', outgoing_amount)}
|
||||
<Separation />
|
||||
{renderLine('Channel Age:', blockToTime(channel_age))}
|
||||
{renderLine('Channel Block Age:', channel_age)}
|
||||
{renderLine('Channel Id:', id)}
|
||||
{renderLine('Commit Fee:', commitFee)}
|
||||
{renderLine('Commit Weight:', commitWeight)}
|
||||
<Separation />
|
||||
{renderLine(
|
||||
'Is Static Remote Key:',
|
||||
is_static_remote_key ? 'True' : 'False'
|
||||
)}
|
||||
{renderLine('Time Offline:', formatSeconds(time_offline))}
|
||||
{renderLine('Time Online:', formatSeconds(time_online))}
|
||||
{renderLine('Transaction Vout:', transaction_vout)}
|
||||
{renderLine('Unsettled Balance:', unsettled_balance)}
|
||||
<Separation />
|
||||
<Sub4Title>Partner Node Info</Sub4Title>
|
||||
{renderPartner()}
|
||||
<Separation />
|
||||
<ColorButton
|
||||
fullWidth={true}
|
||||
withBorder={true}
|
||||
arrow={true}
|
||||
onClick={() => setModalOpen('close')}
|
||||
>
|
||||
Close Channel
|
||||
</ColorButton>
|
||||
<Modal
|
||||
isOpen={modalOpen !== 'none'}
|
||||
closeCallback={() => setModalOpen('none')}
|
||||
>
|
||||
{modalOpen === 'close' ? (
|
||||
<CloseChannel
|
||||
callback={() => setModalOpen('none')}
|
||||
channelId={id}
|
||||
channelName={alias}
|
||||
/>
|
||||
) : (
|
||||
<ChangeDetails
|
||||
callback={() => setModalOpen('none')}
|
||||
transaction_id={transaction_id}
|
||||
transaction_vout={transaction_vout}
|
||||
base_fee_mtokens={node_base}
|
||||
max_htlc_mtokens={max_htlc_mtokens}
|
||||
min_htlc_mtokens={min_htlc_mtokens}
|
||||
fee_rate={node_rate}
|
||||
cltv_delta={node_cltv}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -1,17 +1,20 @@
|
|||
import { themeColors } from 'src/styles/Themes';
|
||||
import { chartColors, themeColors } from 'src/styles/Themes';
|
||||
|
||||
export const getTitleColor = (
|
||||
active: boolean,
|
||||
opening: boolean,
|
||||
closing: boolean
|
||||
closing: boolean,
|
||||
isBosNode: boolean
|
||||
): string | undefined => {
|
||||
switch (true) {
|
||||
case active:
|
||||
return undefined;
|
||||
case !active:
|
||||
return 'red';
|
||||
case opening:
|
||||
case closing:
|
||||
return themeColors.blue2;
|
||||
case isBosNode && active:
|
||||
return chartColors.darkyellow;
|
||||
default:
|
||||
return 'red';
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -22,7 +22,7 @@ const tooltipStyles = {
|
|||
};
|
||||
|
||||
const getDate = (d: DataType) => new Date(d.date);
|
||||
const getValue = (d: DataType) => d.value;
|
||||
const getValue = (d: DataType) => d?.value || 0;
|
||||
const bisectDate = bisector<DataType, Date>(d => new Date(d.date)).left;
|
||||
|
||||
type DataType = {
|
||||
|
|
|
@ -50,6 +50,10 @@ export const Graph = () => {
|
|||
}))
|
||||
.reverse();
|
||||
|
||||
if (!final.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<ParentSize>
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
import React, { FC, useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import { isArray } from 'underscore';
|
||||
import { Card, CardWithTitle, SubTitle } from 'src/components/generic/Styled';
|
||||
import {
|
||||
Card,
|
||||
CardWithTitle,
|
||||
DarkSubTitle,
|
||||
SubTitle,
|
||||
} from 'src/components/generic/Styled';
|
||||
import { LoadingCard } from 'src/components/loading/LoadingCard';
|
||||
import { useBaseState } from 'src/context/BaseContext';
|
||||
import { useGetBosNodeScoresQuery } from 'src/graphql/queries/__generated__/getBosNodeScores.generated';
|
||||
|
@ -59,7 +64,15 @@ export const NodeScores: FC<NodeScoresProps> = ({
|
|||
<CardWithTitle>
|
||||
<SubTitle>Historical Scores</SubTitle>
|
||||
<Card>
|
||||
<Table withBorder={true} tableData={tableData} tableColumns={columns} />
|
||||
{!tableData.length ? (
|
||||
<DarkSubTitle>This node has no BOS score history</DarkSubTitle>
|
||||
) : (
|
||||
<Table
|
||||
withBorder={true}
|
||||
tableData={tableData}
|
||||
tableColumns={columns}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
</CardWithTitle>
|
||||
);
|
||||
|
|
|
@ -27,6 +27,7 @@ export const PaidCard: FC<{ id: string }> = ({ id }) => {
|
|||
const [getToken, { data, loading }] = useCreateBaseTokenMutation({
|
||||
onError: err => toast.error(getErrorContent(err)),
|
||||
variables: { id },
|
||||
refetchQueries: ['GetChannels'],
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
@ -15,6 +15,7 @@ export const RecoverToken = () => {
|
|||
const dispatch = useBaseDispatch();
|
||||
const [getToken, { data, loading }] = useCreateBaseTokenMutation({
|
||||
onError: err => toast.error(getErrorContent(err)),
|
||||
refetchQueries: ['GetChannels'],
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
|
Loading…
Add table
Reference in a new issue