Skip to content

Commit 41e7ec0

Browse files
Force close a Channel if peer is not connected
1 parent 8252ca7 commit 41e7ec0

3 files changed

Lines changed: 20 additions & 115 deletions

File tree

apps/frontend/src/components/cln/ChannelDetails/ChannelDetails.tsx

Lines changed: 8 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const ChannelDetails = (props) => {
2424
const nodeInfo = useSelector(selectNodeInfo);
2525
const showToast = useSelector(selectShowToast);
2626
const [showToastState, setShowToastState] = useState(false);
27-
const [channelClosed, setChannelClosed] = useState(props.selChannel.current_state !== 'ACTIVE');
27+
const [channelClosed, setChannelClosed] = useState(props.selChannel.current_state !== 'ACTIVE' && props.selChannel.state !== 'CHANNELD_NORMAL');
2828
const [responseStatus, setResponseStatus] = useState(CallStatus.NONE);
2929
const [responseMessage, setResponseMessage] = useState('');
3030

@@ -72,14 +72,17 @@ const ChannelDetails = (props) => {
7272
if (response) {
7373
setResponseStatus(CallStatus.PENDING);
7474
setResponseMessage('Closing Channel...');
75-
CLNService.closeChannel(props.selChannel.channel_id)
75+
CLNService.closeChannel(props.selChannel.channel_id, props.selChannel.current_state === 'INACTIVE')
7676
.then((response: any) => {
7777
logger.info(response);
7878
if (response.type) {
79-
props.selChannel.current_state = 'PENDING';
79+
props.onChannelStateChange('PENDING');
8080
setChannelClosed(true);
8181
setResponseStatus(CallStatus.SUCCESS);
82-
setResponseMessage('Channel ' + response.type + ' closed' + (response.txid ? (' with transaction id ' + response.txid) : ''));
82+
setResponseMessage('Channel ' + response.type + ' closed' +
83+
(response.txid ? (' with transaction id ' + response.txid) :
84+
response.txids && response.txids.length > 0 ? (' with transaction id ' + response.txids[0]) : '')
85+
);
8386
delayedClearStatusAlert();
8487
} else {
8588
setResponseStatus(CallStatus.ERROR);
@@ -190,113 +193,6 @@ const ChannelDetails = (props) => {
190193
<Col xs={1} onClick={openLinkHandler} className='btn-sm-svg btn-svg-open'><OpenLinkSVG id={props.selChannel.funding_txid} /></Col>
191194
</Row>
192195
</Row>
193-
<Row className="mt-12px">
194-
<Col xs={12} className="fs-7 text-light">
195-
Withdrawal Timelock
196-
</Col>
197-
<Col xs={12} className="pe-1 overflow-x-ellipsis fw-bold">
198-
{props.selChannel.their_to_self_delay} Blocks
199-
</Col>
200-
</Row>
201-
<Row className="mt-12px">
202-
<Col xs={12} className="fs-7 text-light">
203-
Opened By
204-
</Col>
205-
<Col xs={12} className="pe-1 overflow-x-ellipsis fw-bold">
206-
{titleCase(props.selChannel.opener)}
207-
</Col>
208-
</Row>
209-
<Row className="mt-12px">
210-
<Col xs={12} className="fs-7 text-light">
211-
Channel Type
212-
</Col>
213-
<Col xs={12} className="pe-1 overflow-x-ellipsis fw-bold">
214-
{props.selChannel.private ? 'Private' : 'Public'}
215-
</Col>
216-
</Row>
217-
<Row className="mt-12px">
218-
<Col xs={12} className="fs-7 text-light">
219-
Dust Limit
220-
</Col>
221-
<Col xs={12} className="pe-1 overflow-x-ellipsis fw-bold">
222-
{formatCurrency(
223-
props.selChannel.dust_limit_msat,
224-
Units.MSATS,
225-
uiConfigUnit,
226-
false,
227-
8,
228-
'string',
229-
)}{' '}
230-
{uiConfigUnit}
231-
</Col>
232-
</Row>
233-
<Row className="mt-12px">
234-
<Col xs={12} className="fs-7 text-light">
235-
Spendable
236-
</Col>
237-
<Col xs={12} className="pe-1 overflow-x-ellipsis fw-bold">
238-
{formatCurrency(
239-
props.selChannel.spendable_msat,
240-
Units.MSATS,
241-
uiConfigUnit,
242-
false,
243-
8,
244-
'string',
245-
)}{' '}
246-
{uiConfigUnit}
247-
</Col>
248-
</Row>
249-
<Row className="mt-12px">
250-
<Col xs={12} className="fs-7 text-light">
251-
Receivable
252-
</Col>
253-
<Col xs={12} className="pe-1 overflow-x-ellipsis fw-bold">
254-
{formatCurrency(
255-
props.selChannel.receivable_msat,
256-
Units.MSATS,
257-
uiConfigUnit,
258-
false,
259-
8,
260-
'string',
261-
)}{' '}
262-
{uiConfigUnit}
263-
</Col>
264-
</Row>
265-
<Row className="mt-12px">
266-
<Col xs={12} className="fs-7 text-light">
267-
Channel ID
268-
</Col>
269-
<Col xs={11} className="pe-1 overflow-x-ellipsis fw-bold">
270-
{props.selChannel.channel_id}
271-
</Col>
272-
<Col
273-
xs={1}
274-
onClick={copyHandler}
275-
className="btn-sm-svg btn-svg-copy"
276-
id="Channel ID"
277-
>
278-
<CopySVG id="Channel ID" showTooltip={true} />
279-
</Col>
280-
</Row>
281-
<Row className="mt-12px">
282-
<Col xs={12} className="fs-7 text-light">
283-
Funding ID
284-
</Col>
285-
<Col xs={10} className="pe-1 overflow-x-ellipsis fw-bold">
286-
{props.selChannel.funding_txid}
287-
</Col>
288-
<Col
289-
xs={1}
290-
onClick={copyHandler}
291-
className="btn-sm-svg btn-svg-copy"
292-
id="Funding ID"
293-
>
294-
<CopySVG id="Funding ID" showTooltip={true} />
295-
</Col>
296-
<Col xs={1} onClick={openLinkHandler} className="btn-sm-svg btn-svg-open">
297-
<OpenLinkSVG id={props.selChannel.funding_txid} />
298-
</Col>
299-
</Row>
300196
<ToastMessage
301197
showOnComponent={true}
302198
show={showToastState}
@@ -324,7 +220,7 @@ const ChannelDetails = (props) => {
324220
className="btn-rounded bg-primary"
325221
disabled={responseStatus === CallStatus.PENDING}
326222
>
327-
Close Channel
223+
{props.selChannel.current_state === 'INACTIVE' ? 'Force Close Channel' : 'Close Channel'}
328224
{responseStatus === CallStatus.PENDING ? (
329225
<Spinner className="mt-1 ms-2 text-white-dark" size="sm" />
330226
) : (

apps/frontend/src/components/cln/ChannelsCard/ChannelsCard.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,13 @@ const ChannelsCard = () => {
3636
{selChannelCard === 'open' ? (
3737
<ChannelOpen onClose={onCloseHandler} />
3838
) : selChannelCard === 'details' ? (
39-
<ChannelDetails onClose={() => setSelChannelCard('channels')} selChannel={selChannel} />
39+
<ChannelDetails
40+
onClose={() => setSelChannelCard('channels')}
41+
selChannel={selChannel}
42+
onChannelStateChange={(newState) => setSelChannel(prev =>
43+
prev ? { ...prev, current_state: newState } as PeerChannel : null
44+
)}
45+
/>
4046
) : (
4147
<Channels
4248
newlyOpenedChannelId={newlyOpenedChannelId}

apps/frontend/src/services/http.service.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,11 @@ export class CLNService {
320320
return HttpService.clnCall('fundchannel', { id: pubkey, amount, feerate: feeRate, announce });
321321
}
322322

323-
static async closeChannel(id: string) {
324-
return HttpService.clnCall('close', { id });
323+
static async closeChannel(id: string, force: boolean = false) {
324+
return HttpService.clnCall('close', {
325+
id,
326+
...(force && { unilateraltimeout: 1 }),
327+
});
325328
}
326329

327330
static async btcWithdraw(destination: string, satoshi: string, feerate: string) {

0 commit comments

Comments
 (0)