#include "invoice.h"
#include "json.h"
#include "jsonrpc.h"
#include "lightningd.h"
#include <bitcoin/address.h>
#include <bitcoin/base58.h>
#include <bitcoin/script.h>
#include <ccan/str/hex/hex.h>
#include <ccan/structeq/structeq.h>
#include <ccan/tal/str/str.h>
#include <common/bech32.h>
#include <common/bolt11.h>
#include <common/json_escaped.h>
#include <common/utils.h>
#include <errno.h>
#include <hsmd/gen_hsm_client_wire.h>
#include <inttypes.h>
#include <lightningd/hsm_control.h>
#include <lightningd/jsonrpc_errors.h>
#include <lightningd/log.h>
#include <lightningd/options.h>
#include <sodium/randombytes.h>
#include <wire/wire_sync.h>

static const char *invoice_status_str(const struct invoice_details *inv)
{
	if (inv->state == PAID)
		return "paid";
	if (inv->state == EXPIRED)
		return "expired";
	return "unpaid";
}

static void json_add_invoice(struct json_result *response,
			     const struct invoice_details *inv,
			     bool modern)
{
	json_object_start(response, NULL);
	json_add_escaped_string(response, "label", inv->label);
	json_add_string(response, "bolt11", inv->bolt11);
	json_add_hex(response, "payment_hash", &inv->rhash, sizeof(inv->rhash));
	if (inv->msatoshi)
		json_add_u64(response, "msatoshi", *inv->msatoshi);
	if (modern)
		json_add_string(response, "status", invoice_status_str(inv));
	else if (deprecated_apis && !modern)
		json_add_bool(response, "complete", inv->state == PAID);
	if (inv->state == PAID) {
		json_add_u64(response, "pay_index", inv->pay_index);
		json_add_u64(response, "msatoshi_received",
			     inv->msatoshi_received);
		if (deprecated_apis)
			json_add_u64(response, "paid_timestamp",
				     inv->paid_timestamp);
		json_add_u64(response, "paid_at", inv->paid_timestamp);
	}
	if (deprecated_apis)
		json_add_u64(response, "expiry_time", inv->expiry_time);
	json_add_u64(response, "expires_at", inv->expiry_time);

	json_object_end(response);
}

static void tell_waiter(struct command *cmd, const struct invoice *inv)
{
	struct json_result *response = new_json_result(cmd);
	struct invoice_details details;

	wallet_invoice_details(cmd, cmd->ld->wallet, *inv, &details);
	json_add_invoice(response, &details, true);
	if (details.state == PAID)
		command_success(cmd, response);
	else
		command_fail_detailed(cmd, -2, response,
				      "invoice expired during wait");
}
static void tell_waiter_deleted(struct command *cmd)
{
	command_fail(cmd, "Invoice deleted during wait");
}
static void wait_on_invoice(const struct invoice *invoice, void *cmd)
{
	if (invoice)
		tell_waiter((struct command *) cmd, invoice);
	else
		tell_waiter_deleted((struct command *) cmd);
}

static bool hsm_sign_b11(const u5 *u5bytes,
			 const u8 *hrpu8,
			 secp256k1_ecdsa_recoverable_signature *rsig,
			 struct lightningd *ld)
{
	u8 *msg = towire_hsm_sign_invoice(ld, u5bytes, hrpu8);

	if (!wire_sync_write(ld->hsm_fd, take(msg)))
		fatal("Could not write to HSM: %s", strerror(errno));

	msg = hsm_sync_read(ld, ld);
        if (!fromwire_hsm_sign_invoice_reply(msg, rsig))
		fatal("HSM gave bad sign_invoice_reply %s",
		      tal_hex(msg, msg));

	tal_free(msg);
	return true;
}

/* We allow a string, or a literal number, for labels */
static struct json_escaped *json_tok_label(const tal_t *ctx,
					   const char *buffer,
					   const jsmntok_t *tok)
{
	struct json_escaped *label;

	label = json_tok_escaped_string(ctx, buffer, tok);
	if (label)
		return label;

	/* Allow literal numbers */
	if (tok->type != JSMN_PRIMITIVE)
		return NULL;

	for (int i = tok->start; i < tok->end; i++)
		if (!cisdigit(buffer[i]))
			return NULL;

	return json_escaped_string_(ctx, buffer + tok->start,
				    tok->end - tok->start);
}

static bool parse_fallback(struct command *cmd,
			   const char *buffer, const jsmntok_t *fallback,
			   const u8 **fallback_script)

{
	enum address_parse_result fallback_parse;

	fallback_parse
		= json_tok_address_scriptpubkey(cmd,
						get_chainparams(cmd->ld),
						buffer, fallback,
						fallback_script);
	if (fallback_parse == ADDRESS_PARSE_UNRECOGNIZED) {
		command_fail(cmd, "Fallback address not valid");
		return false;
	} else if (fallback_parse == ADDRESS_PARSE_WRONG_NETWORK) {
		command_fail(cmd, "Fallback address does not match our network %s",
			     get_chainparams(cmd->ld)->network_name);
		return false;
	}
	return true;
}

static void json_invoice(struct command *cmd,
			 const char *buffer, const jsmntok_t *params)
{
	struct invoice invoice;
	struct invoice_details details;
	jsmntok_t *msatoshi, *label, *desctok, *exp, *fallback, *fallbacks;
	jsmntok_t *preimagetok;
	u64 *msatoshi_val;
	const struct json_escaped *label_val, *desc;
	const char *desc_val;
	struct json_result *response = new_json_result(cmd);
	struct wallet *wallet = cmd->ld->wallet;
	struct bolt11 *b11;
	char *b11enc;
	const u8 **fallback_scripts = NULL;
	u64 expiry = 3600;
	bool result;

	if (!json_get_params(cmd, buffer, params,
			     "msatoshi", &msatoshi,
			     "label", &label,
			     "description", &desctok,
			     "?expiry", &exp,
			     "?fallback", &fallback,
			     "?fallbacks", &fallbacks,
			     "?preimage", &preimagetok,
			     NULL)) {
		return;
	}

	/* Get arguments. */
	/* msatoshi */
	if (json_tok_streq(buffer, msatoshi, "any"))
		msatoshi_val = NULL;
	else {
		msatoshi_val = tal(cmd, u64);
		if (!json_tok_u64(buffer, msatoshi, msatoshi_val)
		    || *msatoshi_val == 0) {
			command_fail(cmd,
				     "'%.*s' is not a valid positive number",
				     msatoshi->end - msatoshi->start,
				     buffer + msatoshi->start);
			return;
		}
	}
	/* label */
	label_val = json_tok_label(cmd, buffer, label);
	if (!label_val) {
		command_fail(cmd, "label '%.*s' not a string or number",
			     label->end - label->start, buffer + label->start);
		return;
	}
	if (wallet_invoice_find_by_label(wallet, &invoice, label_val)) {
		command_fail_detailed(cmd, INVOICE_LABEL_ALREADY_EXISTS,
				      NULL,
				      "Duplicate label '%s'", label_val->s);
		return;
	}
	if (strlen(label_val->s) > INVOICE_MAX_LABEL_LEN) {
		command_fail(cmd, "Label '%s' over %u bytes", label_val->s,
			     INVOICE_MAX_LABEL_LEN);
		return;
	}

	desc = json_tok_escaped_string(cmd, buffer, desctok);
	if (!desc) {
		command_fail(cmd, "description '%.*s' not a string",
			     desctok->end - desctok->start,
			     buffer + desctok->start);
		return;
	}
	desc_val = json_escaped_unescape(cmd, desc);
	if (!desc_val) {
		command_fail(cmd, "description '%s' is invalid"
			     " (note: we don't allow \\u)",
			     desc->s);
		return;
	}
	/* description */
	if (strlen(desc_val) >= BOLT11_FIELD_BYTE_LIMIT) {
		command_fail(cmd,
			     "Descriptions greater than %d bytes "
			     "not yet supported "
			     "(description length %zu)",
			     BOLT11_FIELD_BYTE_LIMIT,
			     strlen(desc_val));
		return;
	}
	/* expiry */
	if (exp && !json_tok_u64(buffer, exp, &expiry)) {
		command_fail(cmd, "Expiry '%.*s' invalid seconds",
			     exp->end - exp->start,
			     buffer + exp->start);
		return;
	}

	/* fallback addresses */
	if (fallback) {
		if (deprecated_apis) {
			fallback_scripts = tal_arr(cmd, const u8 *, 1);
			if (!parse_fallback(cmd, buffer, fallback,
					    &fallback_scripts[0]))
				return;
		} else {
			command_fail(cmd, "fallback is deprecated: use fallbacks");
			return;
		}
	}

	if (fallbacks) {
		const jsmntok_t *i, *end = json_next(fallbacks);
		size_t n = 0;

		if (fallback) {
			command_fail(cmd, "Cannot use fallback and fallbacks");
			return;
		}

		if (fallbacks->type != JSMN_ARRAY) {
			command_fail(cmd, "fallback must be an array");
			return;
		}
		fallback_scripts = tal_arr(cmd, const u8 *, n);
		for (i = fallbacks + 1; i < end; i = json_next(i)) {
			tal_resize(&fallback_scripts, n+1);
			if (!parse_fallback(cmd, buffer, i,
					    &fallback_scripts[n]))
				return;
			n++;
		}
	}

	struct preimage r;
	struct sha256 rhash;

	if (preimagetok) {
		/* Get secret preimage from user. */
		if (!hex_decode(buffer + preimagetok->start,
				preimagetok->end - preimagetok->start,
				r.r, sizeof(r.r))) {
			command_fail(cmd, "preimage must be 64 hex digits");
			return;
		}
	} else
		/* Generate random secret preimage. */
		randombytes_buf(r.r, sizeof(r.r));
	/* Generate preimage hash. */
	sha256(&rhash, r.r, sizeof(r.r));

	/* Check duplicate preimage if explicitly specified.
	 * We do not check when it is randomly generated, since
	 * the probability of that matching is very low.
	 */
	if (preimagetok &&
	    wallet_invoice_find_by_rhash(cmd->ld->wallet, &invoice, &rhash)) {
		command_fail_detailed(cmd, INVOICE_PREIMAGE_ALREADY_EXISTS,
				      NULL, "preimage already used");
		return;
	}

	/* Construct bolt11 string. */
	b11 = new_bolt11(cmd, msatoshi_val);
	b11->chain = get_chainparams(cmd->ld);
	b11->timestamp = time_now().ts.tv_sec;
	b11->payment_hash = rhash;
	b11->receiver_id = cmd->ld->id;
	b11->min_final_cltv_expiry = cmd->ld->config.cltv_final;
	b11->expiry = expiry;
	b11->description = tal_steal(b11, desc_val);
	b11->description_hash = NULL;
	if (fallback_scripts)
		b11->fallbacks = tal_steal(b11, fallback_scripts);

	/* FIXME: add private routes if necessary! */
	b11enc = bolt11_encode(cmd, b11, false, hsm_sign_b11, cmd->ld);

	result = wallet_invoice_create(cmd->ld->wallet,
				       &invoice,
				       take(msatoshi_val),
				       take(label_val),
				       expiry,
				       b11enc,
				       &r,
				       &rhash);

	if (!result) {
		   command_fail(cmd, "Failed to create invoice on database");
		   return;
	}

	/* Get details */
	wallet_invoice_details(cmd, cmd->ld->wallet, invoice, &details);

	json_object_start(response, NULL);
	json_add_hex(response, "payment_hash",
		     &details.rhash, sizeof(details.rhash));
	if (deprecated_apis)
		json_add_u64(response, "expiry_time", details.expiry_time);
	json_add_u64(response, "expires_at", details.expiry_time);
	json_add_string(response, "bolt11", details.bolt11);
	json_object_end(response);

	command_success(cmd, response);
}

static const struct json_command invoice_command = {
	"invoice",
	json_invoice,
	"Create an invoice for {msatoshi} with {label} and {description} with optional {expiry} seconds (default 1 hour) and optional {preimage} (default autogenerated)"
};
AUTODATA(json_command, &invoice_command);

static void json_add_invoices(struct json_result *response,
			      struct wallet *wallet,
			      const struct json_escaped *label,
			      bool modern)
{
	struct invoice_iterator it;
	struct invoice_details details;

	memset(&it, 0, sizeof(it));
	while (wallet_invoice_iterate(wallet, &it)) {
		wallet_invoice_iterator_deref(response, wallet, &it, &details);
		if (label && !json_escaped_eq(details.label, label))
			continue;
		json_add_invoice(response, &details, modern);
	}
}

static void json_listinvoice_internal(struct command *cmd,
				      const char *buffer,
				      const jsmntok_t *params,
				      bool modern)
{
	jsmntok_t *labeltok = NULL;
	struct json_escaped *label;
	struct json_result *response = new_json_result(cmd);
	struct wallet *wallet = cmd->ld->wallet;

	if (!json_get_params(cmd, buffer, params,
			     "?label", &labeltok,
			     NULL)) {
		return;
	}

	if (labeltok) {
		label = json_tok_label(cmd, buffer, labeltok);
		if (!label) {
			command_fail(cmd, "label '%.*s' is not a string or number",
				     labeltok->end - labeltok->start,
				     buffer + labeltok->start);
			return;
		}
	} else
		label = NULL;

	if (modern) {
		json_object_start(response, NULL);
		json_array_start(response, "invoices");
	} else
		json_array_start(response, NULL);
	json_add_invoices(response, wallet, label, modern);
	json_array_end(response);
	if (modern)
		json_object_end(response);
	command_success(cmd, response);
}

/* FIXME: Deprecated! */
static void json_listinvoice(struct command *cmd,
			     const char *buffer, const jsmntok_t *params)
{
	return json_listinvoice_internal(cmd, buffer, params, false);
}

static const struct json_command listinvoice_command = {
	"listinvoice",
	json_listinvoice,
	"(DEPRECATED) Show invoice {label} (or all, if no {label}))",
	.deprecated = true
};
AUTODATA(json_command, &listinvoice_command);

static void json_listinvoices(struct command *cmd,
			     const char *buffer, const jsmntok_t *params)
{
	return json_listinvoice_internal(cmd, buffer, params, true);
}

static const struct json_command listinvoices_command = {
	"listinvoices",
	json_listinvoices,
	"Show invoice {label} (or all, if no {label})"
};
AUTODATA(json_command, &listinvoices_command);

static void json_delinvoice(struct command *cmd,
			    const char *buffer, const jsmntok_t *params)
{
	struct invoice i;
	struct invoice_details details;
	jsmntok_t *labeltok, *statustok;
	struct json_result *response = new_json_result(cmd);
	const char *status, *actual_status;
	struct json_escaped *label;
	struct wallet *wallet = cmd->ld->wallet;

	if (!json_get_params(cmd, buffer, params,
			     "label", &labeltok,
			     "status", &statustok,
			     NULL)) {
		return;
	}

	label = json_tok_label(cmd, buffer, labeltok);
	if (!label) {
		command_fail(cmd, "label '%.*s' is not a string or number",
			     labeltok->end - labeltok->start,
			     buffer + labeltok->start);
		return;
	}
	if (!wallet_invoice_find_by_label(wallet, &i, label)) {
		command_fail(cmd, "Unknown invoice");
		return;
	}
	wallet_invoice_details(cmd, cmd->ld->wallet, i, &details);

	status = tal_strndup(cmd, buffer + statustok->start,
			     statustok->end - statustok->start);
	/* This is time-sensitive, so only call once; otherwise error msg
	 * might not make sense if it changed! */
	actual_status = invoice_status_str(&details);
	if (!streq(actual_status, status)) {
		command_fail(cmd, "Invoice status is %s not %s",
			     actual_status, status);
		return;
	}

	/* Get invoice details before attempting to delete, as
	 * otherwise the invoice will be freed. */
	json_add_invoice(response, &details, true);

	if (!wallet_invoice_delete(wallet, i)) {
		log_broken(cmd->ld->log,
			   "Error attempting to remove invoice %"PRIu64,
			   i.id);
		command_fail(cmd, "Database error");
		return;
	}

	command_success(cmd, response);
}

static const struct json_command delinvoice_command = {
	"delinvoice",
	json_delinvoice,
	"Delete unpaid invoice {label} with {status}",
};
AUTODATA(json_command, &delinvoice_command);

static void json_delexpiredinvoice(struct command *cmd, const char *buffer,
				   const jsmntok_t *params)
{
	jsmntok_t *maxexpirytimetok;
	u64 maxexpirytime = time_now().ts.tv_sec;
	struct json_result *result;

	if (!json_get_params(cmd, buffer, params,
			     "?maxexpirytime", &maxexpirytimetok,
			     NULL)) {
		return;
	}

	if (maxexpirytimetok) {
		if (!json_tok_u64(buffer, maxexpirytimetok, &maxexpirytime)) {
			command_fail(cmd, "'%.*s' is not a valid number",
				     maxexpirytimetok->end - maxexpirytimetok->start,
				     buffer + maxexpirytimetok->start);
			return;
		}
	}

	wallet_invoice_delete_expired(cmd->ld->wallet, maxexpirytime);

	result = new_json_result(cmd);
	json_object_start(result, NULL);
	json_object_end(result);
	command_success(cmd, result);
}
static const struct json_command delexpiredinvoice_command = {
	"delexpiredinvoice",
	json_delexpiredinvoice,
	"Delete all expired invoices that expired as of given {maxexpirytime} (a UNIX epoch time), or all expired invoices if not specified"
};
AUTODATA(json_command, &delexpiredinvoice_command);

static void json_autocleaninvoice(struct command *cmd,
				  const char *buffer,
				  const jsmntok_t *params)
{
	jsmntok_t *cycletok;
	jsmntok_t *exbytok;
	u64 cycle = 3600;
	u64 exby = 86400;
	struct json_result *result;

	if (!json_get_params(cmd, buffer, params,
			     "?cycle_seconds", &cycletok,
			     "?expired_by", &exbytok,
			     NULL)) {
		return;
	}

	if (cycletok) {
		if (!json_tok_u64(buffer, cycletok, &cycle)) {
			command_fail(cmd, "'%.*s' is not a valid number",
				     cycletok->end - cycletok->start,
				     buffer + cycletok->start);
			return;
		}
	}
	if (exbytok) {
		if (!json_tok_u64(buffer, exbytok, &exby)) {
			command_fail(cmd, "'%.*s' is not a valid number",
				     exbytok->end - exbytok->start,
				     buffer + exbytok->start);
			return;
		}
	}

	wallet_invoice_autoclean(cmd->ld->wallet, cycle, exby);

	result = new_json_result(cmd);
	json_object_start(result, NULL);
	json_object_end(result);
	command_success(cmd, result);
}
static const struct json_command autocleaninvoice_command = {
	"autocleaninvoice",
	json_autocleaninvoice,
	"Set up autoclean of expired invoices. "
	"Perform cleanup every {cycle_seconds} (default 3600), or disable autoclean if 0. "
	"Clean up expired invoices that have expired for {expired_by} seconds (default 86400). "
};
AUTODATA(json_command, &autocleaninvoice_command);

static void json_waitanyinvoice(struct command *cmd,
			    const char *buffer, const jsmntok_t *params)
{
	jsmntok_t *pay_indextok;
	u64 pay_index;
	struct wallet *wallet = cmd->ld->wallet;

	if (!json_get_params(cmd, buffer, params,
			     "?lastpay_index", &pay_indextok,
			     NULL)) {
		return;
	}

	if (!pay_indextok) {
		pay_index = 0;
	} else {
		if (!json_tok_u64(buffer, pay_indextok, &pay_index)) {
			command_fail(cmd, "'%.*s' is not a valid number",
				     pay_indextok->end - pay_indextok->start,
				     buffer + pay_indextok->start);
			return;
		}
	}

	/* Set command as pending. We do not know if
	 * wallet_invoice_waitany will return immediately
	 * or not, so indicating pending is safest.  */
	command_still_pending(cmd);

	/* Find next paid invoice. */
	wallet_invoice_waitany(cmd, wallet, pay_index,
			       &wait_on_invoice, (void*) cmd);
}

static const struct json_command waitanyinvoice_command = {
	"waitanyinvoice",
	json_waitanyinvoice,
	"Wait for the next invoice to be paid, after {lastpay_index} (if supplied)"
};
AUTODATA(json_command, &waitanyinvoice_command);


/* Wait for an incoming payment matching the `label` in the JSON
 * command.  This will either return immediately if the payment has
 * already been received or it may add the `cmd` to the list of
 * waiters, if the payment is still pending.
 */
static void json_waitinvoice(struct command *cmd,
			      const char *buffer, const jsmntok_t *params)
{
	struct invoice i;
	struct invoice_details details;
	struct wallet *wallet = cmd->ld->wallet;
	jsmntok_t *labeltok;
	struct json_escaped *label;

	if (!json_get_params(cmd, buffer, params, "label", &labeltok, NULL)) {
		return;
	}

	/* Search for invoice */
	label = json_tok_label(cmd, buffer, labeltok);
	if (!label) {
		command_fail(cmd, "label '%.*s' is not a string or number",
			     labeltok->end - labeltok->start,
			     buffer + labeltok->start);
		return;
	}

	if (!wallet_invoice_find_by_label(wallet, &i, label)) {
		command_fail(cmd, "Label not found");
		return;
	}
	wallet_invoice_details(cmd, cmd->ld->wallet, i, &details);

	/* If paid or expired return immediately */
	if (details.state == PAID || details.state == EXPIRED) {
		tell_waiter(cmd, &i);
		return;
	} else {
		/* There is an unpaid one matching, let's wait... */
		command_still_pending(cmd);
		wallet_invoice_waitone(cmd, wallet, i,
				       &wait_on_invoice, (void *) cmd);
	}
}

static const struct json_command waitinvoice_command = {
	"waitinvoice",
	json_waitinvoice,
	"Wait for an incoming payment matching the invoice with {label}, or if the invoice expires"
};
AUTODATA(json_command, &waitinvoice_command);

static void json_add_fallback(struct json_result *response,
			      const char *fieldname,
			      const u8 *fallback,
			      const struct chainparams *chain)
{
	struct bitcoin_address pkh;
	struct ripemd160 sh;
	struct sha256 wsh;

	json_object_start(response, fieldname);
	if (is_p2pkh(fallback, &pkh)) {
		json_add_string(response, "type", "P2PKH");
		json_add_string(response, "addr",
				bitcoin_to_base58(tmpctx, chain->testnet, &pkh));
	} else if (is_p2sh(fallback, &sh)) {
		json_add_string(response, "type", "P2SH");
		json_add_string(response, "addr",
				p2sh_to_base58(tmpctx, chain->testnet, &sh));
	} else if (is_p2wpkh(fallback, &pkh)) {
		char out[73 + strlen(chain->bip173_name)];
		json_add_string(response, "type", "P2WPKH");
		if (segwit_addr_encode(out, chain->bip173_name, 0,
				       (const u8 *)&pkh, sizeof(pkh)))
			json_add_string(response, "addr", out);
	} else if (is_p2wsh(fallback, &wsh)) {
		char out[73 + strlen(chain->bip173_name)];
		json_add_string(response, "type", "P2WSH");
		if (segwit_addr_encode(out, chain->bip173_name, 0,
				       (const u8 *)&wsh, sizeof(wsh)))
			json_add_string(response, "addr", out);
	}
	json_add_hex(response, "hex", fallback, tal_len(fallback));
	json_object_end(response);
}

static void json_decodepay(struct command *cmd,
                           const char *buffer, const jsmntok_t *params)
{
	jsmntok_t *bolt11tok, *desctok;
	struct bolt11 *b11;
	struct json_result *response;
        char *str, *desc, *fail;

	if (!json_get_params(cmd, buffer, params,
			     "bolt11", &bolt11tok,
			     "?description", &desctok,
			     NULL)) {
		return;
	}

        str = tal_strndup(cmd, buffer + bolt11tok->start,
                          bolt11tok->end - bolt11tok->start);

        if (desctok)
                desc = tal_strndup(cmd, buffer + desctok->start,
                                   desctok->end - desctok->start);
        else
                desc = NULL;

	b11 = bolt11_decode(cmd, str, desc, &fail);

	if (!b11) {
		command_fail(cmd, "Invalid bolt11: %s", fail);
		return;
	}

	response = new_json_result(cmd);
	json_object_start(response, NULL);

	json_add_string(response, "currency", b11->chain->bip173_name);
	if (deprecated_apis)
		json_add_u64(response, "timestamp", b11->timestamp);
	json_add_u64(response, "created_at", b11->timestamp);
	json_add_u64(response, "expiry", b11->expiry);
	json_add_pubkey(response, "payee", &b11->receiver_id);
        if (b11->msatoshi)
                json_add_u64(response, "msatoshi", *b11->msatoshi);
        if (b11->description) {
		struct json_escaped *esc = json_escape(NULL, b11->description);
                json_add_escaped_string(response, "description", take(esc));
	}
        if (b11->description_hash)
                json_add_hex(response, "description_hash",
                             b11->description_hash,
                             sizeof(*b11->description_hash));
	json_add_num(response, "min_final_cltv_expiry",
		     b11->min_final_cltv_expiry);
        if (tal_count(b11->fallbacks)) {
		if (deprecated_apis)
			json_add_fallback(response, "fallback",
					  b11->fallbacks[0], b11->chain);
		json_array_start(response, "fallbacks");
		for (size_t i = 0; i < tal_count(b11->fallbacks); i++)
			json_add_fallback(response, NULL,
					  b11->fallbacks[i], b11->chain);
		json_array_end(response);
        }

        if (tal_count(b11->routes)) {
                size_t i, n;

                json_array_start(response, "routes");
                for (i = 0; i < tal_count(b11->routes); i++) {
                        json_array_start(response, NULL);
                        for (n = 0; n < tal_count(b11->routes[i]); n++) {
                                json_object_start(response, NULL);
                                json_add_pubkey(response, "pubkey",
                                                &b11->routes[i][n].pubkey);
                                json_add_short_channel_id(response,
                                                          "short_channel_id",
                                                          &b11->routes[i][n]
                                                          .short_channel_id);
                                json_add_u64(response, "fee_base_msat",
                                             b11->routes[i][n].fee_base_msat);
                                json_add_u64(response, "fee_proportional_millionths",
                                             b11->routes[i][n].fee_proportional_millionths);
                                json_add_num(response, "cltv_expiry_delta",
                                             b11->routes[i][n]
                                             .cltv_expiry_delta);
                                json_object_end(response);
                        }
                        json_array_end(response);
                }
                json_array_end(response);
        }

        if (!list_empty(&b11->extra_fields)) {
                struct bolt11_field *extra;

                json_array_start(response, "extra");
                list_for_each(&b11->extra_fields, extra, list) {
                        char *data = tal_arr(cmd, char, tal_len(extra->data)+1);
                        size_t i;

                        for (i = 0; i < tal_len(extra->data); i++)
                                data[i] = bech32_charset[extra->data[i]];
                        data[i] = '\0';
                        json_object_start(response, NULL);
                        json_add_string(response, "tag",
                                        tal_fmt(data, "%c", extra->tag));
                        json_add_string(response, "data", data);
                        tal_free(data);
                        json_object_end(response);
                }
                json_array_end(response);
        }

	json_add_hex(response, "payment_hash",
                     &b11->payment_hash, sizeof(b11->payment_hash));

	json_add_string(response, "signature",
                        type_to_string(cmd, secp256k1_ecdsa_signature,
                                       &b11->sig));
	json_object_end(response);
	command_success(cmd, response);
}

static const struct json_command decodepay_command = {
	"decodepay",
	json_decodepay,
	"Decode {bolt11}, using {description} if necessary"
};
AUTODATA(json_command, &decodepay_command);
