Skip to content

Commit 8813ddc

Browse files
committed
add support for HODL invoices
1 parent 244f44c commit 8813ddc

11 files changed

Lines changed: 1284 additions & 84 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,11 @@ The node currently exposes the following APIs:
203203
- `/assetmetadata` (POST)
204204
- `/backup` (POST)
205205
- `/btcbalance` (POST)
206+
- `/cancelhodlinvoice` (POST)
206207
- `/changepassword` (POST)
207208
- `/checkindexerurl` (POST)
208209
- `/checkproxyendpoint` (POST)
210+
- `/claimhodlinvoice` (POST)
209211
- `/closechannel` (POST)
210212
- `/connectpeer` (POST)
211213
- `/createutxos` (POST)

openapi.yaml

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,24 @@ paths:
115115
application/json:
116116
schema:
117117
$ref: '#/components/schemas/BtcBalanceResponse'
118+
/cancelhodlinvoice:
119+
post:
120+
tags:
121+
- Invoices
122+
summary: Cancel a HODL invoice
123+
description: Cancel a held HTLC for a HODL invoice. Rejects cancellation if a settlement is already in progress.
124+
requestBody:
125+
content:
126+
application/json:
127+
schema:
128+
$ref: '#/components/schemas/InvoiceCancelRequest'
129+
responses:
130+
'200':
131+
description: Successful operation
132+
content:
133+
application/json:
134+
schema:
135+
$ref: '#/components/schemas/EmptyResponse'
118136
/changepassword:
119137
post:
120138
tags:
@@ -169,6 +187,24 @@ paths:
169187
application/json:
170188
schema:
171189
$ref: '#/components/schemas/EmptyResponse'
190+
/claimhodlinvoice:
191+
post:
192+
tags:
193+
- Invoices
194+
summary: Claim a HODL invoice
195+
description: Claim a held HTLC for a HODL invoice
196+
requestBody:
197+
content:
198+
application/json:
199+
schema:
200+
$ref: '#/components/schemas/ClaimHodlInvoiceRequest'
201+
responses:
202+
'200':
203+
description: Successful operation
204+
content:
205+
application/json:
206+
schema:
207+
$ref: '#/components/schemas/ClaimHodlInvoiceResponse'
172208
/closechannel:
173209
post:
174210
tags:
@@ -674,7 +710,7 @@ paths:
674710
tags:
675711
- Invoices
676712
summary: Get a LN invoice
677-
description: Get a LN invoice to receive a payment
713+
description: Get a LN invoice to receive a payment. Provide `payment_hash` to create a HODL invoice.
678714
requestBody:
679715
content:
680716
application/json:
@@ -1416,6 +1452,14 @@ components:
14161452
$ref: '#/components/schemas/BtcBalance'
14171453
colored:
14181454
$ref: '#/components/schemas/BtcBalance'
1455+
CancelHodlInvoiceRequest:
1456+
type: object
1457+
required:
1458+
- payment_hash
1459+
properties:
1460+
payment_hash:
1461+
type: string
1462+
example: 3febfae1e68b190c15461f4c2a3290f9af1dae63fd7d620d2bd61601869026cd
14191463
ChangePasswordRequest:
14201464
type: object
14211465
required:
@@ -1538,6 +1582,24 @@ components:
15381582
proxy_endpoint:
15391583
type: string
15401584
example: rpc://127.0.0.1:3000/json-rpc
1585+
ClaimHodlInvoiceRequest:
1586+
type: object
1587+
required:
1588+
- payment_hash
1589+
- payment_preimage
1590+
properties:
1591+
payment_hash:
1592+
type: string
1593+
example: b4cb2da889477082a2e47f37a07e646e60ef6f97ffa7a4d88c823efd673da94b
1594+
payment_preimage:
1595+
type: string
1596+
example: eade701c7b23b8799465f4284ad84710fc16a776fbc6483001291149122695a8
1597+
ClaimHodlInvoiceResponse:
1598+
type: object
1599+
properties:
1600+
changed:
1601+
type: boolean
1602+
example: true
15411603
CloseChannelRequest:
15421604
type: object
15431605
required:
@@ -1819,7 +1881,10 @@ components:
18191881
type: string
18201882
enum:
18211883
- Pending
1884+
- Claimable
1885+
- Claiming
18221886
- Succeeded
1887+
- Cancelled
18231888
- Failed
18241889
IndexerProtocol:
18251890
type: string
@@ -1882,7 +1947,10 @@ components:
18821947
type: string
18831948
enum:
18841949
- Pending
1950+
- Claimable
1951+
- Claiming
18851952
- Succeeded
1953+
- Cancelled
18861954
- Failed
18871955
- Expired
18881956
InvoiceStatusRequest:
@@ -2238,6 +2306,10 @@ components:
22382306
- integer
22392307
- 'null'
22402308
example: 42
2309+
payment_hash:
2310+
type: string
2311+
description: Optional. When provided, the invoice is created as HODL.
2312+
example: 3febfae1e68b190c15461f4c2a3290f9af1dae63fd7d620d2bd61601869026cd
22412313
LNInvoiceResponse:
22422314
type: object
22432315
required:
@@ -2467,11 +2539,17 @@ components:
24672539
temporary_channel_id:
24682540
type: string
24692541
example: a8b60c8ce3067b5fc881d4831323e24751daec3b64353c8df3205ec5d838f1c5
2542+
PaymentType:
2543+
type: string
2544+
enum:
2545+
- Outbound
2546+
- InboundAutoClaim
2547+
- InboundHodl
24702548
Payment:
24712549
type: object
24722550
required:
24732551
- payment_hash
2474-
- inbound
2552+
- payment_type
24752553
- status
24762554
- created_at
24772555
- updated_at
@@ -2495,9 +2573,8 @@ components:
24952573
payment_hash:
24962574
type: string
24972575
example: 3febfae1e68b190c15461f4c2a3290f9af1dae63fd7d620d2bd61601869026cd
2498-
inbound:
2499-
type: boolean
2500-
example: true
2576+
payment_type:
2577+
$ref: '#/components/schemas/PaymentType'
25012578
status:
25022579
$ref: '#/components/schemas/HTLCStatus'
25032580
created_at:

src/error.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ pub enum APIError {
167167
#[error("Invalid payment hash: {0}")]
168168
InvalidPaymentHash(String),
169169

170+
#[error("Invalid payment preimage")]
171+
InvalidPaymentPreimage,
172+
170173
#[error("Invalid payment secret")]
171174
InvalidPaymentSecret,
172175

@@ -221,6 +224,24 @@ pub enum APIError {
221224
#[error("Invalid transport endpoints: {0}")]
222225
InvalidTransportEndpoints(String),
223226

227+
#[error("HTLC claim deadline exceeded")]
228+
ClaimDeadlineExceeded,
229+
230+
#[error("Invoice is already claimed")]
231+
InvoiceAlreadyClaimed,
232+
233+
#[error("Invoice is expired")]
234+
InvoiceExpired,
235+
236+
#[error("No claimable HTLC found for this invoice")]
237+
InvoiceNotClaimable,
238+
239+
#[error("Invoice is not marked as HODL")]
240+
InvoiceNotHodl,
241+
242+
#[error("Invoice settlement is in progress")]
243+
InvoiceSettlingInProgress,
244+
224245
#[error("IO error: {0}")]
225246
IO(#[from] std::io::Error),
226247

@@ -266,6 +287,9 @@ pub enum APIError {
266287
#[error("Output below the dust limit")]
267288
OutputBelowDustLimit,
268289

290+
#[error("Payment hash already used")]
291+
PaymentHashAlreadyUsed,
292+
269293
#[error("Payment not found: {0}")]
270294
PaymentNotFound(String),
271295

@@ -467,6 +491,8 @@ impl IntoResponse for APIError {
467491
| APIError::InvalidOnionData(_)
468492
| APIError::InvalidPassword(_)
469493
| APIError::InvalidPaymentHash(_)
494+
| APIError::PaymentHashAlreadyUsed
495+
| APIError::InvalidPaymentPreimage
470496
| APIError::InvalidPaymentSecret
471497
| APIError::InvalidPeerInfo(_)
472498
| APIError::InvalidPrecision(_)
@@ -482,10 +508,12 @@ impl IntoResponse for APIError {
482508
| APIError::InvalidTlvType(_)
483509
| APIError::InvalidTransportEndpoint(_)
484510
| APIError::InvalidTransportEndpoints(_)
511+
| APIError::InvoiceExpired
485512
| APIError::MediaFileEmpty
486513
| APIError::MediaFileNotProvided
487514
| APIError::MissingSwapPaymentPreimage
488515
| APIError::OutputBelowDustLimit
516+
| APIError::ClaimDeadlineExceeded
489517
| APIError::UnsupportedBackupVersion { .. } => {
490518
(StatusCode::BAD_REQUEST, self.to_string(), self.name())
491519
}
@@ -510,6 +538,8 @@ impl IntoResponse for APIError {
510538
| APIError::InvalidIndexer(_)
511539
| APIError::InvalidProxyEndpoint
512540
| APIError::InvalidProxyProtocol(_)
541+
| APIError::InvoiceNotHodl
542+
| APIError::InvoiceSettlingInProgress
513543
| APIError::LockedNode
514544
| APIError::MaxFeeExceeded(_)
515545
| APIError::MinFeeNotMet(_)
@@ -532,6 +562,10 @@ impl IntoResponse for APIError {
532562
| APIError::UnsupportedTransportType => {
533563
(StatusCode::FORBIDDEN, self.to_string(), self.name())
534564
}
565+
APIError::InvoiceAlreadyClaimed => {
566+
(StatusCode::CONFLICT, self.to_string(), self.name())
567+
}
568+
APIError::InvoiceNotClaimable => (StatusCode::NOT_FOUND, self.to_string(), self.name()),
535569
APIError::Network(_) | APIError::NoValidTransportEndpoint => (
536570
StatusCode::SERVICE_UNAVAILABLE,
537571
self.to_string(),

0 commit comments

Comments
 (0)