Skip to content

feat: persist LNURL successAction with Lightning payments (LUD-09)#427

Open
al-munazzim wants to merge 2 commits intoblinkbitcoin:mainfrom
al-munazzim:fix/gh-397-lnurl-success-action
Open

feat: persist LNURL successAction with Lightning payments (LUD-09)#427
al-munazzim wants to merge 2 commits intoblinkbitcoin:mainfrom
al-munazzim:fix/gh-397-lnurl-success-action

Conversation

@al-munazzim
Copy link
Copy Markdown

Summary

  • Implements LUD-09 compliance by persisting LNURL successAction data with Lightning payment transactions
  • Adds domain types for three successAction variants: message, url, and aes
  • Extends MongoDB schema to store successAction alongside LnPayment records
  • Exposes successAction via GraphQL SettlementViaLn.successAction field for frontend consumption

Test plan

  • Unit tests for checkedToLnurlSuccessAction validation covering all tag types and error cases
  • Integration test with LNURL-pay endpoint that returns successAction
  • Verify successAction persists in MongoDB after LNURL payment
  • Verify GraphQL query returns successAction in transaction history

Fixes #397

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 noreply@anthropic.com

…aloyMoney#397)

Implements LUD-09 compliance by capturing and storing successAction data
from LNURL-pay flows, and exposing it through the GraphQL Transaction API.

Changes:
- Add LnurlSuccessAction domain types with validation
- Update LNURL service to capture successAction from requestInvoice
- Thread successAction through payment flow to persistence layer
- Add lnurlSuccessAction field to LnPayment MongoDB schema
- Expose successAction in GraphQL SettlementViaLn type
- Add unit tests for success action validation

Fixes GaloyMoney#397

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings January 25, 2026 20:17
@github-actions github-actions Bot added the core label Jan 25, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements LUD-09 compliance by modeling, persisting, and exposing LNURL successAction data end-to-end for Lightning payments.

Changes:

  • Adds domain types and validation for LNURL success actions (message, url, aes) plus unit tests for checkedToLnurlSuccessAction.
  • Extends the LND/Mongoose LnPayment schema and repository layer to store lnurlSuccessAction and wires it through the Lightning payment execution path for LNURL-pay sends.
  • Introduces a GraphQL LnurlSuccessAction object type and a SettlementViaLn.successAction field to expose stored success actions in the public schema.

Reviewed changes

Copilot reviewed 10 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
core/api/test/unit/domain/bitcoin/lnurl/success-action.spec.ts Adds unit tests validating checkedToLnurlSuccessAction behavior for all tag types and error/null cases.
core/api/src/services/mongoose/ln-payments.ts Maps the new lnurlSuccessAction field from raw LnPaymentType into partial and persisted domain payment types.
core/api/src/services/lnurl-pay/index.ts Changes LNURL-pay fetcher to return { invoice, successAction }, validating and normalizing successAction via the new domain helper.
core/api/src/services/lnd/schema.types.d.ts Extends LnPaymentType to include an optional lnurlSuccessAction field.
core/api/src/services/lnd/schema.ts Adds a subdocument schema and field for lnurlSuccessAction on the LnPayment Mongoose model.
core/api/src/graphql/shared/types/object/lnurl-success-action.ts Defines the GraphQL LnurlSuccessAction object type used in the schema.
core/api/src/graphql/shared/types/abstract/settlement-via.ts Adds a successAction field to SettlementViaLn, resolving via LnPaymentsRepository by paymentHash.
core/api/src/graphql/public/schema.graphql Updates the public GraphQL schema to declare LnurlSuccessAction and the SettlementViaLn.successAction field.
core/api/src/domain/bitcoin/lnurl/index.types.d.ts Adds ambient types for LnurlSuccessAction, LnurlSuccessActionTag, and the LnurlPayInvoiceResponse return type.
core/api/src/domain/bitcoin/lnurl/index.ts Introduces domain models, error type, and checkedToLnurlSuccessAction validator for LNURL success actions.
core/api/src/domain/bitcoin/lightning/payments/index.types.d.ts Threads lnurlSuccessAction through LnPaymentPartial and PersistedLnPaymentLookup types.
core/api/src/app/wallets/index.types.d.ts Extends PayInvoiceByWalletIdArgs with an optional lnurlSuccessAction parameter.
core/api/src/app/payments/send-lnurl.ts Updates LNURL send flows to consume the richer LNURL-pay response and pass lnurlSuccessAction into the Lightning payment pipeline.
core/api/src/app/payments/send-lightning.ts Threads the optional lnurlSuccessAction through execution and persistence of Lightning payments, storing it with the LnPayment record.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +33 to +40
const successAction = checkedToLnurlSuccessAction(response.successAction)
if (successAction instanceof Error) {
// Log the error but don't fail the payment - successAction is optional
// The payment can still proceed without successAction
return {
invoice: response.invoice,
successAction: null,
}
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

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

The comment indicates that errors from checkedToLnurlSuccessAction are logged before returning a null successAction, but the implementation only returns { invoice, successAction: null } without any logging. To avoid misleading future maintainers (and to help diagnose malformed LNURL responses), either add appropriate logging/telemetry for the validation error here or update the comment to reflect that the error is intentionally ignored without logging.

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +46
}): Promise<LnurlPayInvoiceResponse | LnurlServiceError> => {
try {
const invoice = await requestInvoice({
const response = await requestInvoice({
lnUrlOrAddress: lnAddressOrLnurl,
tokens: utils.toSats(toSats(amount.amount)),
})

if (!invoice.hasValidAmount) {
if (!response.hasValidAmount) {
return new ErrorFetchingLnurlInvoice(
"Lnurl service returned an invoice with an invalid amount",
)
}

return invoice.invoice
const successAction = checkedToLnurlSuccessAction(response.successAction)
if (successAction instanceof Error) {
// Log the error but don't fail the payment - successAction is optional
// The payment can still proceed without successAction
return {
invoice: response.invoice,
successAction: null,
}
}

return {
invoice: response.invoice,
successAction,
}
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

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

fetchInvoiceFromLnAddressOrLnurl now parses and returns an LnurlSuccessAction, but there are no tests covering the success path (only an invalid-lnurl error case in core/api/test/integration/services/lnurl-pay.spec.ts). Given this is the core entry point for LNURL-pay and is now responsible for enforcing LUD-09 semantics, please add tests that cover valid successAction payloads (message/url/aes) and invalid payloads (e.g., missing required fields, unknown tags) to ensure the new behavior and error-tolerant fallback (successAction: null) are exercised.

Copilot uses AI. Check for mistakes.
type: LnurlSuccessAction,
description: "LNURL success action returned after payment (LUD-09/10)",
// eslint-disable-next-line @typescript-eslint/no-explicit-any
resolve: async (source: any) => {
Copy link

Copilot AI Jan 25, 2026

Choose a reason for hiding this comment

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

Unexpected any. Specify a different type.

Copilot uses AI. Check for mistakes.
- Add error logging when successAction validation fails (lnurl-pay service)
- Add unit tests for fetchInvoiceFromLnAddressOrLnurl covering all
  successAction types (message/url/aes), invalid payloads, and null case
- Replace `any` type with proper SettlementViaLn intersection type in
  successAction resolver, remove unnecessary type cast

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Persist LNURL successAction data in Lightning transaction records (LUD-09 compliance)

2 participants