LIGHTNING-HOOK-HTLC_ACCEPTED(7)

πŸ“¦
version 26.06.9 Β· 2 versions
, in nixpkgs unstable

πŸ’… LIGHTNING-HOOK-HTLC_ACCEPTED(7)

okay so bestie, welcome to lightning-hook-htlc_accepted (that's the manual page name, and yes it's a mouthful, we love her anyway) β€” the hook you call when an incoming HTLC shows up and you're like "hmm, what do we do with this one". πŸŽ€


✨ NAME ✨

htlc_accepted β€” the hook for handling incoming HTLCs πŸ¦‹


🌸 DESCRIPTION 🌸

The htlc_accepted hook gets called, like, every single time an incoming HTLC is accepted. No cap.

Your plugin gets to peek at the HTLC and then decide: keep processing it, fail it, or resolve it. Main character choice, honestly. πŸ‘‘

Okay but here's the important bit, so listen up: lightningd will replay the HTLCs it doesn't have a final verdict for during startup. Which literally means that if your plugin's response wasn't processed before the HTLC got forwarded, failed, or resolved, your plugin might see the same HTLC again during startup. So it is paramount that your plugin is idempotent if it talks to an external system. fr fr, don't skip this part. 😭

Also! This is a chained hook. Plugins get called in order until one of them returns a result other than continue. Once that happens, the event is considered handled and all the remaining plugins get skipped. Bye besties. πŸ‘‹


πŸ§… HOOK PAYLOAD πŸ§…

  • onion (object):
    • payload (hex): the raw, unparsed onion payload we got from the sender. untouched, unbothered. ✨
    • next_onion (hex): the fully processed onion that we should be sending on to the next hop as part of the outgoing HTLC. and "processed" here means we took the incoming onion, decrypted it, pulled out the payload that was destined for us, and serialised the resulting onion again. cute, right?
    • shared_secret (secret): the shared secret used to decrypt the incoming onion. it's shared with the sender that built the onion. 🀝
    • type (string, optional) (always "tlv"): tells you the payload is TLV formatted. only present if the payload was successfully parsed.
    • short_channel_id (short_channel_id, optional): the channel the sender is hinting should be used next. not present if this node is the final destination. πŸ™ˆ
    • next_node_id (pubkey, optional): the node_id of the next hop. only present if it was specified in the onion payload.
    • forward_msat (msat, optional): how much to forward to the next hop.
    • outgoing_cltv_value (u32, optional): determines the CLTV value for the HTLC we forward to the next hop.
    • total_msat (msat, optional): the total payment amount. only present for final recipients using modern TLV payloads.
    • payment_secret (secret, optional): the payment secret (the one the payer should've gotten from the invoice) provided by the sender. only present for final recipients.
    • payment_metadata (hex, optional): extra metadata provided in the onion payload. only present if the sender included it.
  • htlc (object):
    • short_channel_id (short_channel_id): the channel this HTLC is coming from. (added v0.12.0)
    • id (u64): the unique HTLC identifier assigned by the channel peer. (added v0.12.0)
    • amount_msat (msat): the amount received in this HTLC. this amount minus the forward_msat amount is the fee that stays with us. (added v0.12.0)
    • cltv_expiry (u32): determines when the HTLC reverts back to the sender. cltv_expiry minus outgoing_cltv_value should be equal to or larger than our cltv_delta setting. ⏰
    • cltv_expiry_relative (u32): a hint for how much time we still have to claim the HTLC. it's the cltv_expiry minus the current blockheight, and it's passed along mainly so the plugin doesn't have to go look up the current blockheight itself. considerate icon. πŸ’…
    • payment_hash (hash): the payment hash used to identify the payment.
    • extra_tlvs (hex, optional): optional TLV stream attached to the HTLC. (added v25.09)
  • peer_id (pubkey, optional): the node_id of the peer that offered this HTLC. this field may be absent if the peer is unknown. (added v25.12)
  • forward_to (hash, optional): the channel_id we intend to forward the HTLC to. won't be present if the short_channel_id was invalid or if we were the final destination.

πŸ”₯ HOOK RETURN πŸ”₯

  • result (string) (one of "continue", "fail", "resolve"): determines how the HTLC should be handled. big decision energy.

continue means the plugin doesn't want to do anything special and lightningd should continue processing it normally β€” i.e. resolve the payment if we're the recipient, or attempt to forward it otherwise. heads up though: the usual checks like sufficient fees and CLTV deltas are still enforced. no sneaking past those. πŸ’€

It can also replace the onion.payload by specifying a payload in the response. note that this is always a TLV-style payload, so unlike onion.payload there's no length prefix (and it must be at least 4 hex digits long). this gets re-parsed; it's useful for removing onion fields a plugin doesn't want lightningd to consider. 🧚

It can also specify forward_to in the response, replacing the destination. this usually only makes sense if it wants to choose an alternate channel to the same next peer, but it's useful if the payload is also replaced.

Also, it can specify extra_tlvs in the response. this replaces the TLV-stream update_add_htlc_tlvs in the update_add_htlc message for forwarded htlcs.

If the node is the final destination, the plugin can also replace the amount of the invoice that belongs to the payment_hash by specifying invoice_msat.

fail tells lightningd to fail the HTLC with a given hex-encoded failure_message (please refer to BOLT #4 for details: incorrect_or_unknown_payment_details is the most common). πŸ™ƒ

Instead of failure_message, the response can contain a hex-encoded failure_onion that will be used instead (please refer to the BOLT #4 for details). this can be used, for example, if you're writing a bridge between two Lightning Networks. note that lightningd will apply the obfuscation step to the value returned here with its own shared secret (and key type ammag) before returning it to the previous hop. πŸ”

resolve instructs lightningd to claim the HTLC by providing the preimage matching the payment_hash presented in the call. Notice that the plugin must ensure that the payment_key really matches the payment_hash since lightningd will not check, and the wrong value could result in the channel being closed. 😭 like genuinely, do not mess this one up.

  • payload (hex, optional): replacement TLV payload to use instead of the original onion payload.
  • forward_to (hash, optional): overrides the forwarding destination.
  • extra_tlvs (hex, optional): replacement TLV stream for forwarded HTLCs. (added v25.09)
  • invoice_msat (msat, optional): overrides the invoice amount for final destination checks. (added v25.12)
  • failure_message (hex, optional): failure message to return if result is fail.
  • failure_onion (hex, optional): serialized failure onion to return if result is fail.
  • payment_key (secret, optional): preimage used to resolve the HTLC if result is resolve.

okay that's the whole page bestie, go forth and handle those HTLCs πŸ’œ

this has been LIGHTNING-HOOK-HTLC_ACCEPTED(7) from Core Lightning v26.06.9 β€” ty for reading, ily, mwah πŸ«ΆπŸŽ€βœ¨

πŸ“¦ where this page comes from