diff --git a/cli/README.md b/cli/README.md index 1cd4fe0f82..d5cf211887 100644 --- a/cli/README.md +++ b/cli/README.md @@ -249,7 +249,7 @@ $ amy relay publish-lists # broadcast updated kind:10002/10050/10051 | Command | What it does | |---|---| | `amy offer info NOFFER` | Decode a `noffer1…` pointer (pubkey, relays, price type/amount). Local, no network. | -| `amy offer request NOFFER [--amount SATS] [--timeout MS]` | kind:21001 round-trip: publish the request to the pointer's relays and print the returned BOLT11. `--amount` is required for spontaneous offers; fixed offers default to the pointer's price. | +| `amy offer request NOFFER [--amount SATS] [--timeout MS] [--payer-data K=V,…]` | kind:21001 round-trip: publish the request to the pointer's relays and print the returned BOLT11. `--amount` is required for spontaneous offers; fixed offers default to the pointer's price. `--payer-data` attaches payer fields (e.g. `email=a@b.c`) for offers that require them — Lightning.Pub answers "Invalid Offer" (code 1) when they are missing. | ### CLINK Debits diff --git a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/OfferCommands.kt b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/OfferCommands.kt index 1986e9305c..388e9291f8 100644 --- a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/OfferCommands.kt +++ b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/OfferCommands.kt @@ -39,9 +39,10 @@ import com.vitorpamplona.quartz.nip05DnsIdentifiers.Nip05Id * * - `info ` decodes a pointer locally (no network). * - `discover ` resolves a profile's advertised offer from its NIP-05 `.well-known`. - * - `request [--amount N] [--timeout MS] [--follow]` runs the kind-21001 round-trip: - * publishes the request to the pointer's relays and prints the returned BOLT-11. With - * `--follow` it chases an "Expired or Moved" (code 3) reply to the `latest` pointer. + * - `request [--amount N] [--timeout MS] [--follow] [--payer-data k=v,…]` runs the + * kind-21001 round-trip: publishes the request to the pointer's relays and prints the + * returned BOLT-11. With `--follow` it chases an "Expired or Moved" (code 3) reply to the + * `latest` pointer. `--payer-data` attaches the payer fields some offers require. * - `pay --with [--amount N]` fetches the invoice and settles it end-to-end * through a CLINK debit pointer (offer round-trip → debit round-trip). * @@ -137,6 +138,15 @@ object OfferCommands { val amount = args.flag("amount")?.toLongOrNull() val timeoutMs = args.longFlag("timeout", 15_000) val follow = args.bool("follow") + // Offers can be configured to require payer fields (e.g. email); Lightning.Pub + // rejects a request missing them as "Invalid Offer" (code 1), so the round-trip + // is untestable against such offers without a way to attach them. + val payerData: Map? = + args.flag("payer-data")?.split(',')?.associate { pair -> + val idx = pair.indexOf('=') + if (idx <= 0) return Output.error("bad_args", "--payer-data expects key=value[,key2=value2…]") + pair.take(idx) to pair.substring(idx + 1) + } var offer = ClinkPointerParser.parse(args.positional(0, "noffer").trim()) as? NOffer @@ -151,7 +161,7 @@ object OfferCommands { if (relays.isEmpty()) return Output.error("bad_pointer", "noffer carries no relay to reach") val client = OfferClient(offer, ctx.signer) - val requestEvent = client.requestInvoice(amountSats = amount) + val requestEvent = client.requestInvoice(amountSats = amount, payerData = payerData) val reply = ctx.requestResponse(requestEvent, relays, client.responseFilter(requestEvent.id), timeoutMs) if (reply == null) {