Skip to content

Add trampoline fee override for outgoing payments - #241

Open
ca-ruz wants to merge 3 commits into
ACINQ:masterfrom
ca-ruz:add-trampoline-fee-override
Open

ca-ruz wants to merge 3 commits into
ACINQ:masterfrom
ca-ruz:add-trampoline-fee-override

Conversation

@ca-ruz

@ca-ruz ca-ruz commented Sep 7, 2026

Copy link
Copy Markdown

Summary

This PR adds optional trampoline fee override parameters for outgoing Lightning payments.

The following endpoints now accept:

  • trampolineFeeBaseSat
  • trampolineFeeProportional
  • trampolineFeeCltvExpiryDelta

Supported endpoints:

  • /payinvoice
  • /payoffer
  • /paylnaddress
  • /lnurlpay

phoenix-cli also exposes matching flags for the same commands.

When these parameters are absent, behavior is unchanged and phoenixd uses its default configured trampoline fee.

Context

This came out of investigating Ambrosia PoS using phoenixd as its Lightning backend.

In the observed failures, Ambrosia submitted outgoing payments to phoenixd, phoenixd accepted the payment attempt, sent an HTLC through its trampoline/LSP peer, and then received a downstream failure. One plausible failure mode is that the trampoline node may require a higher fee or CLTV delta than phoenixd’s default single trampoline fee tier.

lightning-kmp already supports trampolineFeesOverride on outgoing payment commands. Phoenix mobile also has a similar concept where the send flow can pass a selected TrampolineFees value. phoenixd did not expose that capability through its HTTP API or CLI.

This PR exposes that existing lower-level capability so clients can opt into a higher trampoline fee policy when appropriate, without changing phoenixd’s default fee behavior for all users.

Note: this PR depends on ACINQ/lightning-kmp#875, which exposes trampoline fee overrides in the high-level Peer.payInvoice(...) and Peer.payOffer(...) APIs.

Compatibility

This is intended to be backward-compatible:

  • existing requests without the new parameters behave exactly as before
  • no default trampoline fee values are changed
  • no database migration is required
  • payment behavior only changes when the caller explicitly provides an override

Notes

The override is intentionally per request. This avoids silently increasing fees globally and lets clients decide when a higher trampoline fee is acceptable for their own UX or retry policy.
The CLTV override is optional. If only trampolineFeeBaseSat and trampolineFeeProportional are provided, phoenixd keeps the default trampoline CLTV expiry delta.

Tests

Added tests for:

  • no override when parameters are absent
  • valid override construction
  • default CLTV fallback
  • partial override rejection
  • invalid value rejection

Tested with:

./gradlew jvmTest --tests "fr.acinq.phoenixd.TrampolineFeesOverrideTestsCommon"
./gradlew jvmTest


private fun badRequest(message: String): Nothing = throw BadRequestException(message)

private suspend fun payInvoice(amount: MilliSatoshi, invoice: Bolt11Invoice, trampolineFeesOverride: TrampolineFees?): SendPaymentResult {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be done in lightning-kmp.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. The manual PayInvoice / PayOffer send/wait flow has been removed from phoenixd. This now uses the high-level lightning-kmp APIs added in ACINQ/lightning-kmp#875.

@ca-ruz

ca-ruz commented Sep 15, 2026

Copy link
Copy Markdown
Author

Updated this PR based on the review feedback.

Main changes:

  • removed the phoenixd-side manual PayInvoice / PayOffer send/wait flow
  • now uses the high-level lightning-kmp payment APIs from Expose trampoline fee overrides in Peer payment APIs lightning-kmp#875
  • kept phoenixd responsible only for HTTP parameter parsing and validation
  • kept the API parameters unchanged for phoenixd clients
  • updated the lightning-kmp dependency to 1.13.2-SNAPSHOT

Verification:

  • ./gradlew jvmTest --tests "fr.acinq.phoenixd.TrampolineFeesOverrideTestsCommon"
  • ./gradlew jvmTest

@ca-ruz
ca-ruz force-pushed the add-trampoline-fee-override branch from aea88cb to abf4a6b Compare September 15, 2026 21:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants