Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pending HTLCs view #2227

Merged
merged 5 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ import Contacts from './views/Settings/Contacts';
import AddContact from './views/Settings/AddContact';
import ContactDetails from './views/ContactDetails';
import CurrencyConverter from './views/Settings/CurrencyConverter';
import PendingHTLCs from './views/PendingHTLCs';

// POS
import Order from './views/Order';
Expand Down Expand Up @@ -852,6 +853,10 @@ export default class App extends React.PureComponent {
name="LSPS1Order"
component={Orders}
/>
<Stack.Screen
name="PendingHTLCs"
component={PendingHTLCs}
/>
</Stack.Navigator>
</NavigationContainer>
</>
Expand Down
20 changes: 20 additions & 0 deletions assets/images/SVG/Hourglass.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions assets/images/SVG/Stopwatch.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 14 additions & 1 deletion components/Channels/ChannelItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { themeColor } from './../../utils/ThemeUtils';
import Stores from '../../stores/Stores';

import ClockIcon from '../../assets/images/SVG/Clock.svg';
import HourglassIcon from '../../assets/images/SVG/Hourglass.svg';
import { localeString } from './../../utils/LocaleUtils';

export function ChannelItem({
Expand All @@ -22,6 +23,7 @@ export function ChannelItem({
outbound,
largestTotal,
status,
pendingHTLCs,
pendingTimelock,
noBorder,
hideLabels,
Expand All @@ -32,7 +34,8 @@ export function ChannelItem({
outbound: number;
largestTotal?: number;
status?: Status;
pendingTimelock?: String;
pendingHTLCs?: boolean;
pendingTimelock?: string;
noBorder?: boolean;
hideLabels?: boolean;
selected?: boolean;
Expand Down Expand Up @@ -70,6 +73,16 @@ export function ChannelItem({
</Body>
</View>
)}
{pendingHTLCs ? (
<View style={{ flexDirection: 'row', marginRight: 5 }}>
<HourglassIcon
fill={themeColor('highlight')}
width={17}
height={17}
style={{ marginRight: 5 }}
/>
</View>
) : null}
{pendingTimelock ? (
<View style={{ flexDirection: 'row', marginRight: 5 }}>
<ClockIcon
Expand Down
5 changes: 3 additions & 2 deletions components/Switch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ interface SwitchProps {
value: boolean;
onValueChange?: any;
disabled?: boolean;
trackEnabledColor?: string;
}

function Switch(props: SwitchProps) {
const { value, onValueChange, disabled } = props;
const { value, onValueChange, disabled, trackEnabledColor } = props;
return (
<RNSwitch
value={value}
onValueChange={onValueChange}
trackColor={{
false: themeColor('disabled'),
true: themeColor('highlight')
true: trackEnabledColor || themeColor('highlight')
}}
thumbColor={
value ? themeColor('highlight') : themeColor('disabled')
Expand Down
28 changes: 27 additions & 1 deletion components/WalletHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import Add from '../assets/images/SVG/Add.svg';
import Alert from '../assets/images/SVG/Alert.svg';
import ClipboardSVG from '../assets/images/SVG/Clipboard.svg';
import Gear from '../assets/images/SVG/Gear.svg';
import Hourglass from '../assets/images/SVG/Hourglass.svg';
import POS from '../assets/images/SVG/POS.svg';
import Search from '../assets/images/SVG/Search.svg';
import Temple from '../assets/images/SVG/Temple.svg';
Expand Down Expand Up @@ -156,6 +157,23 @@ const ClipboardBadge = ({
</TouchableOpacity>
);

const PendingHtlcBadge = ({
navigation
}: {
navigation: StackNavigationProp<any, any>;
clipboard: string;
}) => (
<TouchableOpacity
onPress={() =>
navigation.navigate('PendingHTLCs', {
animation: 'slide_from_bottom'
})
}
>
<Hourglass fill={themeColor('highlight')} width="35" height="35" />
</TouchableOpacity>
);

const POSBadge = ({
setPosStatus,
getOrders
Expand Down Expand Up @@ -244,7 +262,7 @@ export default class WalletHeader extends React.Component<
PosStore,
SyncStore
} = this.props;
const { filteredPendingChannels } = ChannelsStore!;
const { filteredPendingChannels, pendingHTLCs } = ChannelsStore!;
const { settings, posStatus, setPosStatus, implementation } =
SettingsStore!;
const { paid, redeemingAll } = LightningAddressStore!;
Expand Down Expand Up @@ -583,6 +601,14 @@ export default class WalletHeader extends React.Component<
/>
</View>
)}
{pendingHTLCs.length > 0 && (
<View style={{ marginRight: 15 }}>
<PendingHtlcBadge
navigation={navigation}
clipboard={clipboard}
/>
</View>
)}
{isSyncing && (
<View
style={{
Expand Down
9 changes: 8 additions & 1 deletion locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1192,5 +1192,12 @@
"components.AlertModal.resetEGS": "Reset express graph sync data",
"components.AlertModal.neutrinoPeers": "Problematic neutrino peers",
"components.AlertModal.neutrinoExplainer": "Neutrino peers with over 200ms ping time can cause performance issues in the app.",
"components.AlertModal.reviewPeers": "Review neutrino peers list"
"components.AlertModal.reviewPeers": "Review neutrino peers list",
"views.PendingHTLCs.title": "Pending HTLCs",
"views.PendingHTLCs.noPendingHTLCs": "No pending HTLCs",
"views.PendingHTLCs.incoming": "Incoming",
"views.PendingHTLCs.outgoing": "Outgoing",
"views.PendingHTLCs.expirationHeight": "Expiration height",
"views.PendingHTLCs.recommendationIOS": "It's recommended to leave ZEUS running while there are pending HTLCs to prevent force closes.",
"views.PendingHTLCs.recommendationAndroid": "It's recommended to enable Persistent LND or leave ZEUS running while there are pending HTLCs to prevent force closes."
}
33 changes: 31 additions & 2 deletions stores/ChannelsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ interface ChannelInfoIndex {
[key: string]: ChannelInfo;
}

interface PendingHTLC {
incoming: boolean;
amount: number;
hash_lock: string;
expiration_height: number;
htlc_index: number;
forwarding_channel: number;
forwarding_htlc_index: number;
}

export enum ChannelsType {
Open = 0,
Pending = 1,
Expand Down Expand Up @@ -76,6 +86,8 @@ export default class ChannelsStore {
// external account funding
@observable public funded_psbt: string = '';
@observable public pending_chan_ids: Array<string>;
// pending HTLCs
@observable public pendingHTLCs: Array<PendingHTLC>;

settingsStore: SettingsStore;

Expand All @@ -97,7 +109,8 @@ export default class ChannelsStore {
async () => {
if (this.channels) {
this.enrichedChannels = await this.enrichChannels(
this.channels
this.channels,
true
);
this.filterChannels();
}
Expand Down Expand Up @@ -173,6 +186,7 @@ export default class ChannelsStore {
this.totalInbound = 0;
this.totalOffline = 0;
this.channelsType = ChannelsType.Open;
this.pendingHTLCs = [];
};

@action
Expand Down Expand Up @@ -286,7 +300,10 @@ export default class ChannelsStore {
};

@action
enrichChannels = async (channels: Array<Channel>) => {
enrichChannels = async (
channels: Array<Channel>,
setPendingHtlcs?: boolean
) => {
if (channels.length === 0) return;

const channelsWithMissingAliases = channels?.filter(
Expand Down Expand Up @@ -323,6 +340,8 @@ export default class ChannelsStore {
this.aliasesById[channel.channelId!] = nodeInfo.alias;
}

if (setPendingHtlcs) this.pendingHTLCs = [];

for (const channel of channels) {
if (channel.alias == null) {
channel.alias = this.nodes[channel.remotePubkey]?.alias;
Expand All @@ -332,8 +351,18 @@ export default class ChannelsStore {
channel.remotePubkey ||
channel.channelId ||
localeString('models.Channel.unknownId');

if (BackendUtils.isLNDBased() && setPendingHtlcs) {
channel.pending_htlcs?.forEach((htlc: any) => {
htlc.channelDisplayName = channel.displayName;
});

this.pendingHTLCs.push(...channel.pending_htlcs);
}
}

console.log('Pending HTLCs', this.pendingHTLCs);

this.loading = false;
return channels;
};
Expand Down
49 changes: 45 additions & 4 deletions views/Channels/Channel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
View
} from 'react-native';

import { Divider } from 'react-native-elements';
import { Divider, Icon, ListItem } from 'react-native-elements';
import { inject, observer } from 'mobx-react';
import { Route } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
Expand Down Expand Up @@ -40,6 +40,7 @@ import SettingsStore from '../../stores/SettingsStore';
import NodeInfoStore from '../../stores/NodeInfoStore';

import Edit from '../../assets/images/SVG/Edit.svg';
import HourglassIcon from '../../assets/images/SVG/Hourglass.svg';

interface ChannelProps {
navigation: StackNavigationProp<any, any>;
Expand Down Expand Up @@ -205,7 +206,8 @@ export default class ChannelView extends React.Component<
pendingOpen,
closing,
zero_conf,
getCommitmentType
getCommitmentType,
pending_htlcs
} = channel;

const privateChannel = channel.private;
Expand Down Expand Up @@ -434,6 +436,45 @@ export default class ChannelView extends React.Component<
}
/>
)}
{!!pending_htlcs && pending_htlcs.length > 0 && (
<ListItem
containerStyle={{
backgroundColor: 'transparent',
marginLeft: -13,
marginRight: -20
}}
onPress={() =>
navigation.navigate('PendingHTLCs', {
pending_htlcs
})
}
>
<ListItem.Content>
<ListItem.Title
style={{
color: themeColor('highlight'),
fontFamily: 'PPNeueMontreal-Book'
}}
>
<View style={{ flexDirection: 'row' }}>
<HourglassIcon
fill={themeColor('highlight')}
width={17}
height={17}
style={{ marginRight: 5 }}
/>
</View>
{`${localeString(
'views.PendingHTLCs.title'
)} (${pending_htlcs.length})`}
</ListItem.Title>
</ListItem.Content>
<Icon
name="keyboard-arrow-right"
color={themeColor('secondaryText')}
/>
</ListItem>
)}
<KeyValue
keyValue={localeString('views.Channel.channelBalance')}
/>
Expand Down Expand Up @@ -712,8 +753,8 @@ const styles = StyleSheet.create({
fontFamily: 'PPNeueMontreal-Book'
},
content: {
paddingLeft: 20,
paddingRight: 20
marginLeft: 20,
marginRight: 20
},
center: {
alignItems: 'center'
Expand Down
2 changes: 2 additions & 0 deletions views/Channels/ChannelsPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export default class ChannelsPane extends React.PureComponent<ChannelsProps> {
<ChannelItem
title={item.displayName}
status={getStatus()}
pendingHTLCs={item?.pending_htlcs?.length > 0}
inbound={item.remoteBalance}
outbound={item.localBalance}
largestTotal={largestChannelSats}
Expand All @@ -139,6 +140,7 @@ export default class ChannelsPane extends React.PureComponent<ChannelsProps> {
inbound={item.remoteBalance}
outbound={item.localBalance}
status={getStatus()}
pendingHTLCs={item?.pending_htlcs?.length > 0}
pendingTimelock={
item.forceClose
? forceCloseTimeLabel(item.blocks_til_maturity)
Expand Down
Loading
Loading