Skip to main content
Glama

ldk_generate_invoice

Create Lightning invoices with a real payment hash for testing purposes by specifying amount, description, and expiry time. Ideal for iOS Lightning wallet development and integration.

Instructions

Generate a Lightning invoice with real payment hash for testing

Input Schema

NameRequiredDescriptionDefault
amountSatsYesAmount in satoshis
descriptionNoInvoice description
expirySecondsNoInvoice expiry time in seconds (default: 3600)

Input Schema (JSON Schema)

{ "properties": { "amountSats": { "description": "Amount in satoshis", "minimum": 1, "type": "number" }, "description": { "description": "Invoice description", "type": "string" }, "expirySeconds": { "default": 3600, "description": "Invoice expiry time in seconds (default: 3600)", "type": "number" } }, "required": [ "amountSats" ], "type": "object" }

Implementation Reference

  • The main handler function (execute) for the ldk_generate_invoice tool. Converts satoshis to millisatoshis, calls LightningService to generate the invoice, and returns a rich response with the bolt11 string, payment hash, and embedded SwiftUI code example for iOS QR display and sharing.
    execute: async (args: any): Promise<ToolResult> => { try { const amountMsat = args.amountSats * 1000; const invoice = await lightningService.generateInvoice( amountMsat, args.description, args.expirySeconds || 3600 ); return { content: [{ type: 'text', text: JSON.stringify({ success: true, invoice: invoice.bolt11, paymentHash: invoice.paymentHash, amountSats: args.amountSats, expiryTime: invoice.expiryTime, description: invoice.description, swiftExample: ` // Swift code to generate and display Lightning invoice using LDK import SwiftUI import LightningDevKit import CoreImage.CIFilterBuiltins class InvoiceGenerator { let channelManager: Bindings.ChannelManager let logger: Bindings.Logger let keys: Bindings.KeysManager init(channelManager: Bindings.ChannelManager, logger: Bindings.Logger, keys: Bindings.KeysManager) { self.channelManager = channelManager self.logger = logger self.keys = keys } func createInvoice(amountMsat: UInt64?, description: String, expirySecs: UInt32 = 3600) -> Result<Bindings.Bolt11Invoice, Error> { let invoiceParams = Bindings.InvoiceBuilder.newInvoiceBuilder() if let amount = amountMsat { invoiceParams.amountMsat(amount) } invoiceParams.description(description.asLdkStr()) invoiceParams.expiryTime(expirySecs) do { let invoice = try invoiceParams.build() return .success(invoice) } catch { return .failure(error) } } } struct InvoiceView: View { let invoice = "${invoice.bolt11}" let amountSats = ${args.amountSats} @State private var isCopied = false var body: some View { VStack(spacing: 20) { Text("Lightning Invoice") .font(.title) // QR Code Image(uiImage: generateQRCode(from: invoice)) .interpolation(.none) .resizable() .scaledToFit() .frame(width: 250, height: 250) .overlay( RoundedRectangle(cornerRadius: 16) .stroke(Color.secondary.opacity(0.3), lineWidth: 1) ) // Amount VStack(spacing: 4) { Text("\\(amountSats)") .font(.system(size: 36, weight: .bold, design: .rounded)) Text("sats") .font(.subheadline) .foregroundColor(.secondary) } // Invoice details Text("${args.description || 'Lightning Payment'}") .font(.subheadline) .foregroundColor(.secondary) .multilineTextAlignment(.center) // Copy button with feedback Button(action: { UIPasteboard.general.string = invoice withAnimation(.easeInOut(duration: 0.2)) { isCopied = true } DispatchQueue.main.asyncAfter(deadline: .now() + 2) { withAnimation(.easeInOut(duration: 0.2)) { isCopied = false } } }) { Label( isCopied ? "Copied!" : "Copy Invoice", systemImage: isCopied ? "checkmark.circle.fill" : "doc.on.doc" ) .frame(minWidth: 150) } .buttonStyle(.borderedProminent) .tint(isCopied ? .green : .accentColor) // Share button ShareLink(item: invoice) { Label("Share", systemImage: "square.and.arrow.up") } .buttonStyle(.bordered) } .padding() } func generateQRCode(from string: String) -> UIImage { let context = CIContext() let filter = CIFilter.qrCodeGenerator() filter.message = Data(string.utf8) if let outputImage = filter.outputImage { let transform = CGAffineTransform(scaleX: 10, y: 10) let scaledImage = outputImage.transformed(by: transform) if let cgImage = context.createCGImage(scaledImage, from: scaledImage.extent) { return UIImage(cgImage: cgImage) } } return UIImage(systemName: "xmark.circle") ?? UIImage() } }`.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 }; } }
  • Input schema defining the parameters for generating the invoice: required amountSats (number, min 1), optional description (string), and expirySeconds (number, default 3600).
    inputSchema: { type: 'object', properties: { amountSats: { type: 'number', description: 'Amount in satoshis', minimum: 1 }, description: { type: 'string', description: 'Invoice description' }, expirySeconds: { type: 'number', description: 'Invoice expiry time in seconds (default: 3600)', default: 3600 } }, required: ['amountSats'] },
  • src/index.ts:38-62 (registration)
    Registration of the tool in the central tools array used by the MCP server for listing and dispatching tool calls.
    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, ];
  • src/index.ts:13-13 (registration)
    Import statement that brings the generateInvoiceTool into the main server index for registration.
    import { generateInvoiceTool } from './tools/generateInvoice.js';
  • Supporting helper method in LightningService that implements the core invoice generation logic using bolt11 library for encoding and signing, generating random preimage and payment hash.
    async generateInvoice( amountMsat: number, description?: string, expiry: number = 3600 ): Promise<LightningInvoice> { const preimage = crypto.randomBytes(32); const paymentHash = crypto.createHash('sha256').update(preimage).digest(); // Create network object compatible with bolt11 const bolt11Network = { bech32: this.network.bech32, pubKeyHash: this.network.pubKeyHash, scriptHash: this.network.scriptHash, validWitnessVersions: [0, 1] }; const invoice: bolt11.PaymentRequestObject = { network: bolt11Network as any, timestamp: Math.floor(Date.now() / 1000), tags: [ { tagName: 'payment_hash', data: paymentHash.toString('hex') }, { tagName: 'description', data: description || 'LDK MCP Invoice' }, { tagName: 'expire_time', data: expiry } ], millisatoshis: amountMsat.toString() }; const privateKey = ECPair.makeRandom({ network: this.network }).privateKey!; const encoded = bolt11.encode(invoice); const signed = bolt11.sign(encoded, privateKey); return { bolt11: signed.paymentRequest || '', paymentHash: paymentHash.toString('hex'), amountMsat, description: description || '', expiryTime: expiry, timestamp: invoice.timestamp || 0 }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/StevenGeller/ldk-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server