ldk_pay_invoice
Pay Lightning invoices to test payment flows, with optional maximum fee settings for development validation.
Instructions
Test payment flows by paying a Lightning invoice
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| invoice | Yes | BOLT11 Lightning invoice to pay | |
| maxFeeSats | No | Maximum fee in satoshis willing to pay |
Implementation Reference
- src/tools/payInvoice.ts:24-123 (handler)The main handler function for the 'ldk_pay_invoice' tool. It calls LightningService.payInvoice with the provided invoice and returns formatted results including payment details and example Swift code for iOS integration.execute: async (args: any): Promise<ToolResult> => { try { const payment = await lightningService.payInvoice(args.invoice); return { content: [{ type: 'text', text: JSON.stringify({ success: true, payment: { paymentHash: payment.paymentHash, paymentPreimage: payment.paymentPreimage, amountSats: Math.floor(payment.amountMsat / 1000), feeSats: Math.floor((payment.feeMsat || 0) / 1000), status: payment.status, timestamp: payment.timestamp }, swiftExample: ` // Swift code to handle payment in your iOS app import LightningDevKit func payInvoice(invoice: String, maxFeeSats: UInt64) async throws -> PaymentResult { let parsedInvoice = Bolt11Invoice.fromStr(s: invoice) guard let invoiceVal = parsedInvoice.getValue() else { throw PaymentError.invalidInvoice } let invoicePaymentResult = Bindings.paymentParametersFromInvoice(invoice: invoiceVal) guard invoicePaymentResult.isOk() else { throw PaymentError.invalidPaymentParams } let (paymentHash, recipientOnion, routeParams) = invoicePaymentResult.getValue()! let paymentId = invoiceVal.paymentHash()! // Set max fee routeParams.setMaxTotalFeeMsat(val: maxFeeSats * 1000) let res = channelManager.sendPayment( paymentHash: paymentHash, recipientOnion: recipientOnion, paymentId: paymentId, routeParams: routeParams, retryStrategy: .initWithTimeout(a: 15) ) if res.isOk() { // Payment initiated successfully return PaymentResult( paymentHash: paymentHash.toHex(), status: .pending ) } else { throw PaymentError.sendFailed(res.getError()!) } } // Handle payment events func handlePaymentEvent(event: Event) { if let paymentSent = event.getValueAsPaymentSent() { let paymentHash = paymentSent.getPaymentHash().toHex() let feePaidMsat = paymentSent.getFeePaidMsat()?.getValue() ?? 0 print("Payment sent successfully!") print("Payment hash: \\(paymentHash)") print("Fee paid: \\(feePaidMsat / 1000) sats") // Update UI DispatchQueue.main.async { self.updatePaymentStatus(hash: paymentHash, status: .succeeded) } } else if let paymentFailed = event.getValueAsPaymentFailed() { let paymentHash = paymentFailed.getPaymentHash().toHex() let reason = paymentFailed.getReason() print("Payment failed: \\(reason?.description ?? "Unknown")") // Update UI DispatchQueue.main.async { self.updatePaymentStatus(hash: paymentHash, status: .failed) } } }`.trim() }, null, 2) }] }; } catch (error) { return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error' }, null, 2) }], isError: true }; } }
- src/tools/payInvoice.ts:9-23 (schema)Input schema defining the parameters for paying a Lightning invoice: required 'invoice' string and optional 'maxFeeSats' number.inputSchema: { type: 'object', properties: { invoice: { type: 'string', description: 'BOLT11 Lightning invoice to pay' }, maxFeeSats: { type: 'number', description: 'Maximum fee in satoshis willing to pay', default: 10 } }, required: ['invoice'] },
- src/index.ts:38-62 (registration)Registration of the payInvoiceTool (line 40) in the central tools array used by the MCP server's ListTools and CallTool request handlers.const tools = [ generateInvoiceTool, payInvoiceTool, getChannelStatusTool, getNodeInfoTool, backupStateTool, keychainTestTool, backgroundTestTool, pushNotificationTool, biometricAuthTool, createChannelTool, closeChannelTool, getBalanceTool, decodeInvoiceTool, listPaymentsTool, estimateFeeTool, generateMnemonicTool, deriveAddressTool, getSwiftCodeTool, getArchitectureTool, testScenarioTool, networkGraphTool, eventHandlingTool, chainSyncTool, ];
- Helper method in LightningService that implements the core payment logic: decodes the BOLT11 invoice, simulates successful payment, calculates fee, generates preimage, and stores the payment.async payInvoice(bolt11Invoice: string): Promise<Payment> { try { const decoded = bolt11.decode(bolt11Invoice); const paymentHash = decoded.tags.find(t => t.tagName === 'payment_hash')?.data as string; const amountMsat = parseInt(decoded.millisatoshis || '0'); const description = decoded.tags.find(t => t.tagName === 'description')?.data as string; const payment: Payment = { paymentHash, amountMsat, status: PaymentStatus.Succeeded, timestamp: Date.now(), description, bolt11: bolt11Invoice, feeMsat: Math.floor(amountMsat * 0.001), // 0.1% fee paymentPreimage: crypto.randomBytes(32).toString('hex') }; this.payments.set(paymentHash, payment); return payment; } catch (error) { throw new Error(`Failed to pay invoice: ${error}`); } }
- src/index.ts:14-14 (registration)Import statement that brings the payInvoiceTool into the main index for registration.import { payInvoiceTool } from './tools/payInvoice.js';