2017-06-20 17:15:25 +02:00
# include <bitcoin/address.h>
# include <bitcoin/base58.h>
# include <bitcoin/script.h>
2019-08-12 21:29:13 +02:00
# include <ccan/cast/cast.h>
2017-06-20 17:15:25 +02:00
# include <ccan/tal/str/str.h>
2019-05-22 23:20:14 +02:00
# include <common/addr.h>
2017-12-11 04:43:11 +01:00
# include <common/bech32.h>
2018-12-08 01:39:28 +01:00
# include <common/json_command.h>
2019-06-05 09:00:05 +02:00
# include <common/json_helpers.h>
2018-12-08 01:39:28 +01:00
# include <common/jsonrpc_errors.h>
2017-08-28 18:05:01 +02:00
# include <common/key_derive.h>
2018-12-08 01:39:28 +01:00
# include <common/param.h>
2017-08-28 18:05:01 +02:00
# include <common/status.h>
# include <common/utxo.h>
2018-04-05 21:19:47 +02:00
# include <common/wallet_tx.h>
2017-08-28 18:02:01 +02:00
# include <common/withdraw_tx.h>
2017-06-24 08:50:14 +02:00
# include <errno.h>
2018-09-20 05:06:42 +02:00
# include <hsmd/gen_hsm_wire.h>
2017-12-19 21:10:19 +01:00
# include <inttypes.h>
2017-08-28 18:04:01 +02:00
# include <lightningd/bitcoind.h>
# include <lightningd/chaintopology.h>
2017-06-24 08:50:23 +02:00
# include <lightningd/hsm_control.h>
2018-03-16 04:45:08 +01:00
# include <lightningd/json.h>
2017-08-28 18:04:01 +02:00
# include <lightningd/jsonrpc.h>
2017-06-20 17:15:25 +02:00
# include <lightningd/lightningd.h>
2017-08-28 18:04:01 +02:00
# include <lightningd/log.h>
2019-03-04 04:13:49 +01:00
# include <lightningd/options.h>
2018-02-09 14:24:33 +01:00
# include <lightningd/peer_control.h>
2017-06-20 17:15:25 +02:00
# include <lightningd/subd.h>
2019-05-28 22:39:48 +02:00
# include <wallet/wallet.h>
2017-06-20 17:15:25 +02:00
# include <wally_bip32.h>
2017-06-24 08:50:14 +02:00
# include <wire/wire_sync.h>
2017-06-20 17:15:25 +02:00
/**
* wallet_withdrawal_broadcast - The tx has been broadcast ( or it failed )
*
* This is the final step in the withdrawal . We either successfully
* broadcast the withdrawal transaction or it failed somehow . So we
* report success or a broadcast failure . Upon success we also mark
* the used outputs as spent , and add the change output to our pool of
* available outputs .
*/
2018-02-06 14:00:12 +01:00
static void wallet_withdrawal_broadcast ( struct bitcoind * bitcoind UNUSED ,
2017-06-20 17:15:25 +02:00
int exitstatus , const char * msg ,
2019-06-05 09:00:05 +02:00
struct unreleased_tx * utx )
2017-06-20 17:15:25 +02:00
{
2019-06-05 09:00:05 +02:00
struct command * cmd = utx - > wtx - > cmd ;
struct lightningd * ld = cmd - > ld ;
2019-02-21 04:45:55 +01:00
struct amount_sat change = AMOUNT_SAT ( 0 ) ;
2017-06-20 17:15:25 +02:00
2019-06-05 09:00:05 +02:00
/* FIXME: This won't be necessary once we use ccan/json_out! */
2017-06-20 17:15:25 +02:00
/* Massage output into shape so it doesn't kill the JSON serialization */
char * output = tal_strjoin ( cmd , tal_strsplit ( cmd , msg , " \n " , STR_NO_EMPTY ) , " " , STR_NO_TRAIL ) ;
if ( exitstatus = = 0 ) {
2017-06-22 14:20:41 +02:00
/* Mark used outputs as spent */
2019-06-05 09:00:05 +02:00
wallet_confirm_utxos ( ld - > wallet , utx - > wtx - > utxos ) ;
2019-01-31 16:34:30 +01:00
/* Extract the change output and add it to the DB */
2019-06-05 09:00:05 +02:00
wallet_extract_owned_outputs ( ld - > wallet , utx - > tx , NULL , & change ) ;
2018-01-29 06:59:21 +01:00
2019-06-05 07:29:05 +02:00
/* Note normally, change_satoshi == withdraw->wtx->change, but
2018-01-29 06:59:21 +01:00
* not if we ' re actually making a payment to ourselves ! */
2019-06-05 09:00:05 +02:00
assert ( amount_sat_greater_eq ( change , utx - > wtx - > change ) ) ;
2017-06-22 14:20:41 +02:00
2018-10-19 03:17:49 +02:00
struct json_stream * response = json_stream_success ( cmd ) ;
2019-06-05 09:00:05 +02:00
json_add_tx ( response , " tx " , utx - > tx ) ;
2017-06-20 17:15:25 +02:00
json_add_string ( response , " txid " , output ) ;
2018-12-16 05:53:06 +01:00
was_pending ( command_success ( cmd , response ) ) ;
2017-06-20 17:15:25 +02:00
} else {
2018-12-16 05:53:06 +01:00
was_pending ( command_fail ( cmd , LIGHTNINGD ,
" Error broadcasting transaction: %s " ,
output ) ) ;
2017-06-20 17:15:25 +02:00
}
}
2019-06-05 07:29:03 +02:00
static struct command_result * param_bitcoin_address ( struct command * cmd ,
const char * name ,
const char * buffer ,
const jsmntok_t * tok ,
const u8 * * scriptpubkey )
{
/* Parse address. */
switch ( json_tok_address_scriptpubkey ( cmd ,
get_chainparams ( cmd - > ld ) ,
buffer , tok ,
scriptpubkey ) ) {
case ADDRESS_PARSE_UNRECOGNIZED :
return command_fail ( cmd , LIGHTNINGD ,
2019-08-15 19:41:23 +02:00
" Could not parse destination address, "
" %s should be a valid address " ,
name ? name : " address field " ) ;
2019-06-05 07:29:03 +02:00
case ADDRESS_PARSE_WRONG_NETWORK :
return command_fail ( cmd , LIGHTNINGD ,
" Destination address is not on network %s " ,
get_chainparams ( cmd - > ld ) - > network_name ) ;
case ADDRESS_PARSE_SUCCESS :
return NULL ;
}
abort ( ) ;
}
2019-06-05 09:00:05 +02:00
/* Signs the tx, broadcasts it: broadcast calls wallet_withdrawal_broadcast */
static struct command_result * broadcast_and_wait ( struct command * cmd ,
struct unreleased_tx * utx )
{
struct bitcoin_tx * signed_tx ;
struct bitcoin_txid signed_txid ;
/* FIXME: hsm will sign almost anything, but it should really
* fail cleanly ( not abort ! ) and let us report the error here . */
u8 * msg = towire_hsm_sign_withdrawal ( cmd ,
utx - > wtx - > amount ,
utx - > wtx - > change ,
utx - > wtx - > change_key_index ,
2019-08-15 19:41:23 +02:00
cast_const2 ( const struct bitcoin_tx_output * * ,
utx - > outputs ) ,
2019-06-05 09:00:05 +02:00
utx - > wtx - > utxos ) ;
if ( ! wire_sync_write ( cmd - > ld - > hsm_fd , take ( msg ) ) )
fatal ( " Could not write sign_withdrawal to HSM: %s " ,
strerror ( errno ) ) ;
msg = wire_sync_read ( cmd , cmd - > ld - > hsm_fd ) ;
if ( ! fromwire_hsm_sign_withdrawal_reply ( utx , msg , & signed_tx ) )
fatal ( " HSM gave bad sign_withdrawal_reply %s " ,
tal_hex ( tmpctx , msg ) ) ;
2019-07-30 16:14:43 +02:00
signed_tx - > chainparams = utx - > tx - > chainparams ;
2019-06-05 09:00:05 +02:00
/* Sanity check */
bitcoin_txid ( signed_tx , & signed_txid ) ;
if ( ! bitcoin_txid_eq ( & signed_txid , & utx - > txid ) )
fatal ( " HSM changed txid: unsigned %s, signed %s " ,
tal_hex ( tmpctx , linearize_tx ( tmpctx , utx - > tx ) ) ,
tal_hex ( tmpctx , linearize_tx ( tmpctx , signed_tx ) ) ) ;
/* Replace unsigned tx by signed tx. */
tal_free ( utx - > tx ) ;
utx - > tx = signed_tx ;
/* Now broadcast the transaction */
bitcoind_sendrawtx ( cmd - > ld - > topology - > bitcoind ,
tal_hex ( tmpctx , linearize_tx ( tmpctx , signed_tx ) ) ,
wallet_withdrawal_broadcast , utx ) ;
return command_still_pending ( cmd ) ;
}
/* Common code for withdraw and txprepare.
2017-06-20 17:15:25 +02:00
*
2019-08-15 19:41:23 +02:00
* Returns NULL on success , and fills in wtx , output and
2019-06-05 09:00:05 +02:00
* maybe changekey ( owned by cmd ) . Otherwise , cmd has failed , so don ' t
* access it ! ( It ' s been freed ) . */
static struct command_result * json_prepare_tx ( struct command * cmd ,
const char * buffer ,
const jsmntok_t * params ,
2019-08-15 19:41:23 +02:00
struct unreleased_tx * * utx ,
bool for_withdraw )
2017-06-20 17:15:25 +02:00
{
2018-08-28 22:46:32 +02:00
u32 * feerate_per_kw ;
2018-12-16 05:50:06 +01:00
struct command_result * res ;
2019-02-21 20:34:49 +01:00
u32 * minconf , maxheight ;
2019-06-05 09:00:05 +02:00
struct pubkey * changekey ;
2019-08-12 21:29:13 +02:00
struct bitcoin_tx_output * * outputs ;
2019-08-15 19:41:23 +02:00
const jsmntok_t * outputstok , * t ;
const u8 * destination = NULL ;
size_t out_len , i ;
2017-06-24 08:50:14 +02:00
2019-06-05 09:00:05 +02:00
* utx = tal ( cmd , struct unreleased_tx ) ;
( * utx ) - > wtx = tal ( * utx , struct wallet_tx ) ;
wtx_init ( cmd , ( * utx ) - > wtx , AMOUNT_SAT ( - 1ULL ) ) ;
2018-07-20 03:14:02 +02:00
2019-08-15 19:41:23 +02:00
if ( ! for_withdraw ) {
/* From v0.7.3, the new style for *txprepare* use array of outputs
* to replace original ' destination ' and ' satoshi ' parameters . */
if ( ! param ( cmd , buffer , params ,
p_req ( " outputs " , param_array , & outputstok ) ,
p_opt ( " feerate " , param_feerate , & feerate_per_kw ) ,
p_opt_def ( " minconf " , param_number , & minconf , 1 ) ,
NULL ) ) {
/* For generating help, give new-style. */
if ( ! params | | ! deprecated_apis )
return command_param_failed ( ) ;
/* For the old style:
* * txprepare * ' destination ' ' satoshi ' [ ' feerate ' ] [ ' minconf ' ] */
if ( ! param ( cmd , buffer , params ,
p_req ( " destination " , param_bitcoin_address ,
& destination ) ,
p_req ( " satoshi " , param_wtx , ( * utx ) - > wtx ) ,
p_opt ( " feerate " , param_feerate , & feerate_per_kw ) ,
p_opt_def ( " minconf " , param_number , & minconf , 1 ) ,
NULL ) )
/* If the parameters mixed the new style and the old style,
* fail it . */
return command_param_failed ( ) ;
}
} else {
/* *withdraw* command still use 'destination' and 'satoshi' as parameters. */
if ( ! param ( cmd , buffer , params ,
p_req ( " destination " , param_bitcoin_address ,
& destination ) ,
p_req ( " satoshi " , param_wtx , ( * utx ) - > wtx ) ,
p_opt ( " feerate " , param_feerate , & feerate_per_kw ) ,
p_opt_def ( " minconf " , param_number , & minconf , 1 ) ,
NULL ) )
2018-12-16 05:52:06 +01:00
return command_param_failed ( ) ;
2019-08-15 19:41:23 +02:00
}
2019-06-05 09:00:05 +02:00
2018-08-28 22:46:32 +02:00
if ( ! feerate_per_kw ) {
2018-12-16 05:50:06 +01:00
res = param_feerate_estimate ( cmd , & feerate_per_kw ,
FEERATE_NORMAL ) ;
if ( res )
2018-12-16 05:52:06 +01:00
return res ;
2018-08-28 22:46:32 +02:00
}
2018-08-23 01:27:25 +02:00
2019-02-21 20:34:49 +01:00
maxheight = minconf_to_maxheight ( * minconf , cmd - > ld ) ;
2019-08-15 19:41:23 +02:00
/* *withdraw* command or old *txprepare* command.
* Support only one output . */
if ( destination ) {
outputs = tal_arr ( tmpctx , struct bitcoin_tx_output * , 1 ) ;
outputs [ 0 ] = tal ( outputs , struct bitcoin_tx_output ) ;
outputs [ 0 ] - > script = tal_steal ( outputs [ 0 ] ,
cast_const ( u8 * , destination ) ) ;
outputs [ 0 ] - > amount = ( * utx ) - > wtx - > amount ;
out_len = tal_count ( outputs [ 0 ] - > script ) ;
goto create_tx ;
}
if ( outputstok - > size = = 0 )
return command_fail ( cmd , JSONRPC2_INVALID_PARAMS , " Empty outputs " ) ;
outputs = tal_arr ( tmpctx , struct bitcoin_tx_output * , outputstok - > size ) ;
out_len = 0 ;
( * utx ) - > wtx - > all_funds = false ;
( * utx ) - > wtx - > amount = AMOUNT_SAT ( 0 ) ;
json_for_each_arr ( i , t , outputstok ) {
struct amount_sat * amount ;
const u8 * destination ;
enum address_parse_result res ;
/* output format: {destination: amount} */
if ( t - > type ! = JSMN_OBJECT )
return command_fail ( cmd , JSONRPC2_INVALID_PARAMS ,
" The output format must be "
" {destination: amount} " ) ; ;
res = json_tok_address_scriptpubkey ( cmd ,
get_chainparams ( cmd - > ld ) ,
buffer , & t [ 1 ] ,
& destination ) ;
if ( res = = ADDRESS_PARSE_UNRECOGNIZED )
return command_fail ( cmd , JSONRPC2_INVALID_PARAMS ,
" Could not parse destination address " ) ;
else if ( res = = ADDRESS_PARSE_WRONG_NETWORK )
return command_fail ( cmd , JSONRPC2_INVALID_PARAMS ,
" Destination address is not on network %s " ,
get_chainparams ( cmd - > ld ) - > network_name ) ;
amount = tal ( tmpctx , struct amount_sat ) ;
if ( ! json_to_sat_or_all ( buffer , & t [ 2 ] , amount ) )
return command_fail ( cmd , JSONRPC2_INVALID_PARAMS ,
" '%.*s' is a invalid satoshi amount " ,
t [ 2 ] . end - t [ 2 ] . start , buffer + t [ 2 ] . start ) ;
out_len + = tal_count ( destination ) ;
outputs [ i ] = tal ( outputs , struct bitcoin_tx_output ) ;
outputs [ i ] - > amount = * amount ;
outputs [ i ] - > script = tal_steal ( outputs [ i ] ,
cast_const ( u8 * , destination ) ) ;
/* In fact, the maximum amount of bitcoin satoshi is 2.1e15.
* It can ' t be equal to / bigger than 2 ^ 64.
* On the hand , the maximum amount of litoshi is 8.4e15 ,
* which also can ' t overflow . */
/* This means this destination need "all" satoshi we have. */
if ( amount_sat_eq ( * amount , AMOUNT_SAT ( - 1ULL ) ) ) {
if ( outputstok - > size > 1 )
return command_fail ( cmd , JSONRPC2_INVALID_PARAMS ,
" outputs[%zi]: this destination wants "
" all satoshi. The count of outputs "
" can't be more than 1. " , i ) ;
( * utx ) - > wtx - > all_funds = true ;
/* `AMOUNT_SAT(-1ULL)` is the max permissible for `wallet_select_all`. */
( * utx ) - > wtx - > amount = * amount ;
break ;
}
if ( ! amount_sat_add ( & ( * utx ) - > wtx - > amount , ( * utx ) - > wtx - > amount , * amount ) )
return command_fail ( cmd , JSONRPC2_INVALID_PARAMS ,
" outputs: The sum of first %zi outputs "
" overflow. " , i ) ;
}
create_tx :
( * utx ) - > outputs = tal_steal ( * utx , outputs ) ;
2019-06-05 09:00:05 +02:00
res = wtx_select_utxos ( ( * utx ) - > wtx , * feerate_per_kw ,
2019-08-15 19:41:23 +02:00
out_len , maxheight ) ;
2018-12-16 05:51:06 +01:00
if ( res )
2018-12-16 05:52:06 +01:00
return res ;
2017-06-20 17:15:25 +02:00
2019-08-15 19:41:23 +02:00
/* Because of the max limit of AMOUNT_SAT(-1ULL),
* ` ( * utx ) - > wtx - > all_funds ` won ' t change in ` wtx_select_utxos ( ) ` */
if ( ( * utx ) - > wtx - > all_funds )
outputs [ 0 ] - > amount = ( * utx ) - > wtx - > amount ;
2019-06-05 09:00:05 +02:00
if ( ! amount_sat_eq ( ( * utx ) - > wtx - > change , AMOUNT_SAT ( 0 ) ) ) {
changekey = tal ( tmpctx , struct pubkey ) ;
if ( ! bip32_pubkey ( cmd - > ld - > wallet - > bip32_base , changekey ,
( * utx ) - > wtx - > change_key_index ) )
return command_fail ( cmd , LIGHTNINGD , " Keys generation failure " ) ;
2019-08-01 03:34:05 +02:00
} else
changekey = NULL ;
2019-08-12 21:29:13 +02:00
( * utx ) - > tx = withdraw_tx ( * utx , get_chainparams ( cmd - > ld ) ,
2019-08-15 19:41:23 +02:00
( * utx ) - > wtx - > utxos , ( * utx ) - > outputs ,
2019-06-05 09:00:05 +02:00
changekey , ( * utx ) - > wtx - > change ,
cmd - > ld - > wallet - > bip32_base ,
& ( * utx ) - > change_outnum ) ;
bitcoin_txid ( ( * utx ) - > tx , & ( * utx ) - > txid ) ;
2017-06-24 08:50:14 +02:00
2019-06-05 09:00:05 +02:00
return NULL ;
}
2017-06-24 08:50:14 +02:00
2019-06-05 09:00:05 +02:00
static struct command_result * json_txprepare ( struct command * cmd ,
const char * buffer ,
const jsmntok_t * obj UNNEEDED ,
const jsmntok_t * params )
{
struct unreleased_tx * utx ;
struct command_result * res ;
struct json_stream * response ;
2017-06-24 08:50:14 +02:00
2019-08-15 19:41:23 +02:00
res = json_prepare_tx ( cmd , buffer , params , & utx , false ) ;
2019-06-05 09:00:05 +02:00
if ( res )
return res ;
2017-06-24 08:50:14 +02:00
2019-06-05 09:00:05 +02:00
/* utx will persist past this command. */
tal_steal ( cmd - > ld - > wallet , utx ) ;
add_unreleased_tx ( cmd - > ld - > wallet , utx ) ;
response = json_stream_success ( cmd ) ;
json_add_tx ( response , " unsigned_tx " , utx - > tx ) ;
json_add_txid ( response , " txid " , & utx - > txid ) ;
return command_success ( cmd , response ) ;
}
static const struct json_command txprepare_command = {
" txprepare " ,
" bitcoin " ,
json_txprepare ,
" Create a transaction, with option to spend in future (either txsend and txdiscard) " ,
false
} ;
AUTODATA ( json_command , & txprepare_command ) ;
static struct command_result * param_unreleased_txid ( struct command * cmd ,
const char * name ,
const char * buffer ,
const jsmntok_t * tok ,
struct unreleased_tx * * utx )
{
struct command_result * res ;
struct bitcoin_txid * txid ;
res = param_txid ( cmd , name , buffer , tok , & txid ) ;
if ( res )
return res ;
* utx = find_unreleased_tx ( cmd - > ld - > wallet , txid ) ;
if ( ! * utx )
return command_fail ( cmd , LIGHTNINGD ,
" %s not an unreleased txid " ,
type_to_string ( cmd , struct bitcoin_txid ,
txid ) ) ;
tal_free ( txid ) ;
return NULL ;
}
static struct command_result * json_txsend ( struct command * cmd ,
const char * buffer ,
const jsmntok_t * obj UNNEEDED ,
const jsmntok_t * params )
{
struct unreleased_tx * utx ;
if ( ! param ( cmd , buffer , params ,
p_req ( " txid " , param_unreleased_txid , & utx ) ,
NULL ) )
return command_param_failed ( ) ;
/* We delete from list now, and this command owns it. */
remove_unreleased_tx ( utx ) ;
tal_steal ( cmd , utx ) ;
/* We're the owning cmd now. */
utx - > wtx - > cmd = cmd ;
2019-08-23 23:39:31 +02:00
wallet_transaction_add ( cmd - > ld - > wallet , utx - > tx , 0 , 0 ) ;
wallet_transaction_annotate ( cmd - > ld - > wallet , & utx - > txid ,
TX_UNKNOWN , 0 ) ;
2019-06-05 09:00:05 +02:00
return broadcast_and_wait ( cmd , utx ) ;
}
static const struct json_command txsend_command = {
" txsend " ,
" bitcoin " ,
json_txsend ,
" Sign and broadcast a transaction created by txprepare " ,
false
} ;
AUTODATA ( json_command , & txsend_command ) ;
static struct command_result * json_txdiscard ( struct command * cmd ,
const char * buffer ,
const jsmntok_t * obj UNNEEDED ,
const jsmntok_t * params )
{
struct unreleased_tx * utx ;
struct json_stream * response ;
if ( ! param ( cmd , buffer , params ,
p_req ( " txid " , param_unreleased_txid , & utx ) ,
NULL ) )
return command_param_failed ( ) ;
/* Free utx with this command */
tal_steal ( cmd , utx ) ;
response = json_stream_success ( cmd ) ;
json_add_tx ( response , " unsigned_tx " , utx - > tx ) ;
json_add_txid ( response , " txid " , & utx - > txid ) ;
return command_success ( cmd , response ) ;
}
static const struct json_command txdiscard_command = {
" txdiscard " ,
" bitcoin " ,
json_txdiscard ,
" Abandon a transaction created by txprepare " ,
false
} ;
AUTODATA ( json_command , & txdiscard_command ) ;
/**
* json_withdraw - Entrypoint for the withdrawal flow
*
* A user has requested a withdrawal over the JSON - RPC , parse the
* request , select coins and a change key . Then send the request to
* the HSM to generate the signatures .
*/
static struct command_result * json_withdraw ( struct command * cmd ,
const char * buffer ,
const jsmntok_t * obj UNNEEDED ,
const jsmntok_t * params )
{
struct unreleased_tx * utx ;
struct command_result * res ;
2019-08-15 19:41:23 +02:00
res = json_prepare_tx ( cmd , buffer , params , & utx , true ) ;
2019-06-05 09:00:05 +02:00
if ( res )
return res ;
2019-05-23 23:01:45 +02:00
/* Store the transaction in the DB and annotate it as a withdrawal */
wallet_transaction_add ( cmd - > ld - > wallet , utx - > tx , 0 , 0 ) ;
2019-08-23 23:45:15 +02:00
wallet_transaction_annotate ( cmd - > ld - > wallet , & utx - > txid ,
2019-05-23 23:01:45 +02:00
TX_WALLET_WITHDRAWAL , 0 ) ;
2019-06-05 09:00:05 +02:00
return broadcast_and_wait ( cmd , utx ) ;
2017-06-20 17:15:25 +02:00
}
static const struct json_command withdraw_command = {
2019-05-22 16:08:16 +02:00
" withdraw " ,
" bitcoin " ,
json_withdraw ,
" Send to {destination} address {satoshi} (or 'all') amount via Bitcoin "
" transaction, at optional {feerate} " ,
false ,
" Send funds from the internal wallet to the specified address. Either "
" specify a number of satoshis to send or 'all' to sweep all funds in the "
" internal wallet to the address. Only use outputs that have at least "
" {minconf} confirmations. "
2017-06-20 17:15:25 +02:00
} ;
AUTODATA ( json_command , & withdraw_command ) ;
2017-06-21 17:18:55 +02:00
2018-04-21 14:24:58 +02:00
/* May return NULL if encoding error occurs. */
static char *
encode_pubkey_to_addr ( const tal_t * ctx ,
const struct lightningd * ld ,
const struct pubkey * pubkey ,
bool is_p2sh_p2wpkh ,
/* Output: redeemscript to use to redeem outputs
* paying to the address .
* May be NULL if redeemscript is do not care . */
u8 * * out_redeemscript )
{
char * out ;
const char * hrp ;
struct sha256 h ;
struct ripemd160 h160 ;
u8 * redeemscript ;
bool ok ;
if ( is_p2sh_p2wpkh ) {
redeemscript = bitcoin_redeem_p2sh_p2wpkh ( ctx , pubkey ) ;
sha256 ( & h , redeemscript , tal_count ( redeemscript ) ) ;
ripemd160 ( & h160 , h . u . u8 , sizeof ( h ) ) ;
out = p2sh_to_base58 ( ctx ,
2019-05-06 23:17:15 +02:00
get_chainparams ( ld ) ,
2018-04-21 14:24:58 +02:00
& h160 ) ;
} else {
hrp = get_chainparams ( ld ) - > bip173_name ;
/* out buffer is 73 + strlen(human readable part),
* see common / bech32 . h */
out = tal_arr ( ctx , char , 73 + strlen ( hrp ) ) ;
pubkey_to_hash160 ( pubkey , & h160 ) ;
/* I am uncertain why this is so for direct SegWit
* outputs , but this is how listaddrs worked prior to
* this code being refactored . */
redeemscript = tal_dup_arr ( ctx , u8 ,
( u8 * ) & h160 , sizeof ( h160 ) ,
0 ) ;
ok = segwit_addr_encode ( out , hrp , 0 , h160 . u . u8 , sizeof ( h160 ) ) ;
if ( ! ok )
out = tal_free ( out ) ;
}
if ( out_redeemscript )
* out_redeemscript = redeemscript ;
else
tal_free ( redeemscript ) ;
return out ;
}
2019-03-04 04:13:20 +01:00
enum addrtype {
ADDR_P2SH_SEGWIT = 1 ,
ADDR_BECH32 = 2 ,
ADDR_ALL = ( ADDR_P2SH_SEGWIT + ADDR_BECH32 )
} ;
/* Extract bool indicating "p2sh-segwit" or "bech32" */
2018-12-16 05:50:06 +01:00
static struct command_result * param_newaddr ( struct command * cmd ,
const char * name ,
const char * buffer ,
const jsmntok_t * tok ,
2019-03-04 04:13:20 +01:00
enum addrtype * * addrtype )
2018-08-14 19:52:42 +02:00
{
2019-03-04 04:13:20 +01:00
* addrtype = tal ( cmd , enum addrtype ) ;
if ( json_tok_streq ( buffer , tok , " p2sh-segwit " ) )
* * addrtype = ADDR_P2SH_SEGWIT ;
else if ( json_tok_streq ( buffer , tok , " bech32 " ) )
* * addrtype = ADDR_BECH32 ;
else if ( json_tok_streq ( buffer , tok , " all " ) )
* * addrtype = ADDR_ALL ;
else
return command_fail ( cmd , JSONRPC2_INVALID_PARAMS ,
" '%s' should be 'bech32', 'p2sh-segwit' or 'all', not '%.*s' " ,
name , tok - > end - tok - > start , buffer + tok - > start ) ;
return NULL ;
2018-08-14 19:52:42 +02:00
}
2018-12-16 05:52:06 +01:00
static struct command_result * json_newaddr ( struct command * cmd ,
const char * buffer ,
const jsmntok_t * obj UNNEEDED ,
const jsmntok_t * params )
2017-06-21 17:18:55 +02:00
{
2018-10-19 03:17:49 +02:00
struct json_stream * response ;
2017-06-21 17:18:55 +02:00
struct pubkey pubkey ;
2019-03-04 04:13:20 +01:00
enum addrtype * addrtype ;
2017-06-25 04:33:13 +02:00
s64 keyidx ;
2019-03-04 04:13:20 +01:00
char * p2sh , * bech32 ;
2019-06-05 07:28:59 +02:00
u8 * b32script ;
2018-01-24 08:01:21 +01:00
2018-07-20 03:14:02 +02:00
if ( ! param ( cmd , buffer , params ,
2019-03-04 04:13:20 +01:00
p_opt_def ( " addresstype " , param_newaddr , & addrtype , ADDR_BECH32 ) ,
2018-07-20 03:14:02 +02:00
NULL ) )
2018-12-16 05:52:06 +01:00
return command_param_failed ( ) ;
2017-06-21 17:18:55 +02:00
2017-08-28 18:09:01 +02:00
keyidx = wallet_get_newindex ( cmd - > ld ) ;
2017-06-25 04:33:13 +02:00
if ( keyidx < 0 ) {
2018-12-16 05:52:06 +01:00
return command_fail ( cmd , LIGHTNINGD , " Keys exhausted " ) ;
2017-06-21 17:18:55 +02:00
}
2019-06-05 07:28:59 +02:00
if ( ! bip32_pubkey ( cmd - > ld - > wallet - > bip32_base , & pubkey , keyidx ) )
2018-12-16 05:52:06 +01:00
return command_fail ( cmd , LIGHTNINGD , " Keys generation failure " ) ;
2017-06-21 17:18:55 +02:00
2019-06-05 07:28:59 +02:00
b32script = scriptpubkey_p2wpkh ( tmpctx , & pubkey ) ;
if ( * addrtype & ADDR_BECH32 )
txfilter_add_scriptpubkey ( cmd - > ld - > owned_txfilter , b32script ) ;
if ( * addrtype & ADDR_P2SH_SEGWIT )
txfilter_add_scriptpubkey ( cmd - > ld - > owned_txfilter ,
scriptpubkey_p2sh ( tmpctx , b32script ) ) ;
2017-11-27 16:20:10 +01:00
2019-03-04 04:13:20 +01:00
p2sh = encode_pubkey_to_addr ( cmd , cmd - > ld , & pubkey , true , NULL ) ;
bech32 = encode_pubkey_to_addr ( cmd , cmd - > ld , & pubkey , false , NULL ) ;
if ( ! p2sh | | ! bech32 ) {
2018-12-16 05:52:06 +01:00
return command_fail ( cmd , LIGHTNINGD ,
" p2wpkh address encoding failure. " ) ;
2018-01-24 08:01:21 +01:00
}
2017-06-21 17:18:55 +02:00
2018-10-19 03:17:48 +02:00
response = json_stream_success ( cmd ) ;
2019-06-05 07:28:45 +02:00
if ( deprecated_apis & & * addrtype ! = ADDR_ALL )
json_add_string ( response , " address " ,
* addrtype & ADDR_BECH32 ? bech32 : p2sh ) ;
2019-03-04 04:13:20 +01:00
if ( * addrtype & ADDR_BECH32 )
json_add_string ( response , " bech32 " , bech32 ) ;
if ( * addrtype & ADDR_P2SH_SEGWIT )
json_add_string ( response , " p2sh-segwit " , p2sh ) ;
2018-12-16 05:52:06 +01:00
return command_success ( cmd , response ) ;
2017-06-21 17:18:55 +02:00
}
static const struct json_command newaddr_command = {
" newaddr " ,
2019-05-22 16:08:16 +02:00
" bitcoin " ,
2017-06-21 17:18:55 +02:00
json_newaddr ,
2019-03-04 04:13:20 +01:00
" Get a new {bech32, p2sh-segwit} (or all) address to fund a channel (default is bech32) " , false ,
" Generates a new address (or both) that belongs to the internal wallet. Funds sent to these addresses will be managed by lightningd. Use `withdraw` to withdraw funds to an external wallet. "
2017-06-21 17:18:55 +02:00
} ;
AUTODATA ( json_command , & newaddr_command ) ;
2017-06-21 17:40:42 +02:00
2018-12-16 05:52:06 +01:00
static struct command_result * json_listaddrs ( struct command * cmd ,
const char * buffer ,
const jsmntok_t * obj UNNEEDED ,
const jsmntok_t * params )
2018-02-18 13:52:46 +01:00
{
2018-10-19 03:17:49 +02:00
struct json_stream * response ;
2018-02-18 13:52:46 +01:00
struct pubkey pubkey ;
2018-08-13 18:16:41 +02:00
u64 * bip32_max_index ;
2018-02-18 13:52:46 +01:00
2018-07-20 03:14:02 +02:00
if ( ! param ( cmd , buffer , params ,
2019-02-04 11:55:42 +01:00
p_opt ( " bip32_max_index " , param_u64 , & bip32_max_index ) ,
2018-07-20 03:14:02 +02:00
NULL ) )
2018-12-16 05:52:06 +01:00
return command_param_failed ( ) ;
2018-02-18 13:52:46 +01:00
2019-02-04 11:55:42 +01:00
if ( ! bip32_max_index ) {
bip32_max_index = tal ( cmd , u64 ) ;
* bip32_max_index = db_get_intvar ( cmd - > ld - > wallet - > db ,
" bip32_max_index " , 0 ) ;
}
2018-10-19 03:17:48 +02:00
response = json_stream_success ( cmd ) ;
2018-02-18 13:52:46 +01:00
json_array_start ( response , " addresses " ) ;
2018-08-13 18:16:41 +02:00
for ( s64 keyidx = 0 ; keyidx < = * bip32_max_index ; keyidx + + ) {
2018-02-18 13:52:46 +01:00
if ( keyidx = = BIP32_INITIAL_HARDENED_CHILD ) {
break ;
}
2019-06-05 07:28:59 +02:00
if ( ! bip32_pubkey ( cmd - > ld - > wallet - > bip32_base , & pubkey , keyidx ) )
2018-10-19 03:17:48 +02:00
abort ( ) ;
2018-02-18 13:52:46 +01:00
// p2sh
2018-04-21 14:24:58 +02:00
u8 * redeemscript_p2sh ;
char * out_p2sh = encode_pubkey_to_addr ( cmd , cmd - > ld ,
& pubkey ,
true ,
& redeemscript_p2sh ) ;
2018-02-18 13:52:46 +01:00
// bech32 : p2wpkh
2018-04-21 14:24:58 +02:00
u8 * redeemscript_p2wpkh ;
char * out_p2wpkh = encode_pubkey_to_addr ( cmd , cmd - > ld ,
& pubkey ,
false ,
& redeemscript_p2wpkh ) ;
if ( ! out_p2wpkh ) {
2018-10-19 03:17:48 +02:00
abort ( ) ;
2018-02-18 13:52:46 +01:00
}
// outputs
json_object_start ( response , NULL ) ;
json_add_u64 ( response , " keyidx " , keyidx ) ;
json_add_pubkey ( response , " pubkey " , & pubkey ) ;
json_add_string ( response , " p2sh " , out_p2sh ) ;
2018-07-28 07:53:33 +02:00
json_add_hex_talarr ( response , " p2sh_redeemscript " ,
redeemscript_p2sh ) ;
2018-02-18 13:52:46 +01:00
json_add_string ( response , " bech32 " , out_p2wpkh ) ;
2018-07-28 07:53:33 +02:00
json_add_hex_talarr ( response , " bech32_redeemscript " ,
redeemscript_p2wpkh ) ;
2018-02-18 13:52:46 +01:00
json_object_end ( response ) ;
}
json_array_end ( response ) ;
2018-12-16 05:52:06 +01:00
return command_success ( cmd , response ) ;
2018-02-18 13:52:46 +01:00
}
static const struct json_command listaddrs_command = {
" dev-listaddrs " ,
2019-05-22 16:08:16 +02:00
" developer " ,
2018-02-18 13:52:46 +01:00
json_listaddrs ,
2018-04-20 10:09:50 +02:00
" Show addresses list up to derivation {index} (default is the last bip32 index) " ,
false ,
2018-02-18 13:52:46 +01:00
" Show addresses of your internal wallet. Use `newaddr` to generate a new address. "
} ;
AUTODATA ( json_command , & listaddrs_command ) ;
2018-12-16 05:52:06 +01:00
static struct command_result * json_listfunds ( struct command * cmd ,
const char * buffer ,
const jsmntok_t * obj UNNEEDED ,
const jsmntok_t * params )
2017-09-05 02:11:53 +02:00
{
2018-10-19 03:17:49 +02:00
struct json_stream * response ;
2018-02-09 14:24:33 +01:00
struct peer * p ;
2018-10-19 03:17:48 +02:00
struct utxo * * utxos ;
2018-03-27 16:00:33 +02:00
char * out ;
struct pubkey funding_pubkey ;
2018-09-14 16:51:04 +02:00
if ( ! param ( cmd , buffer , params , NULL ) )
2018-12-16 05:52:06 +01:00
return command_param_failed ( ) ;
2018-09-14 16:51:04 +02:00
2018-10-19 03:17:48 +02:00
utxos = wallet_get_utxos ( cmd , cmd - > ld - > wallet , output_state_available ) ;
response = json_stream_success ( cmd ) ;
2017-09-05 02:11:53 +02:00
json_array_start ( response , " outputs " ) ;
2018-02-06 14:14:43 +01:00
for ( size_t i = 0 ; i < tal_count ( utxos ) ; i + + ) {
2017-09-05 02:11:53 +02:00
json_object_start ( response , NULL ) ;
2017-12-18 07:20:24 +01:00
json_add_txid ( response , " txid " , & utxos [ i ] - > txid ) ;
2017-09-05 02:11:53 +02:00
json_add_num ( response , " output " , utxos [ i ] - > outnum ) ;
2019-05-20 07:07:40 +02:00
json_add_amount_sat_compat ( response , utxos [ i ] - > amount ,
" value " , " amount_msat " ) ;
2018-02-21 23:48:01 +01:00
2018-04-03 14:08:00 +02:00
/* @close_info is for outputs that are not yet claimable */
2018-03-27 16:00:33 +02:00
if ( utxos [ i ] - > close_info = = NULL ) {
bip32_pubkey ( cmd - > ld - > wallet - > bip32_base , & funding_pubkey ,
utxos [ i ] - > keyindex ) ;
2018-04-21 14:24:58 +02:00
out = encode_pubkey_to_addr ( cmd , cmd - > ld ,
& funding_pubkey ,
utxos [ i ] - > is_p2sh ,
NULL ) ;
if ( ! out ) {
2018-12-16 05:52:06 +01:00
return command_fail ( cmd , LIGHTNINGD ,
" p2wpkh address encoding failure. " ) ;
2018-03-27 16:00:33 +02:00
}
json_add_string ( response , " address " , out ) ;
2019-02-22 17:50:01 +01:00
} else if ( utxos [ i ] - > scriptPubkey ! = NULL ) {
out = encode_scriptpubkey_to_addr (
2019-05-22 23:20:14 +02:00
cmd , get_chainparams ( cmd - > ld ) - > bip173_name ,
utxos [ i ] - > scriptPubkey ) ;
2019-02-22 17:50:01 +01:00
if ( out )
json_add_string ( response , " address " , out ) ;
2018-03-27 16:00:33 +02:00
}
2019-02-22 17:50:01 +01:00
2018-02-21 23:48:01 +01:00
if ( utxos [ i ] - > spendheight )
json_add_string ( response , " status " , " spent " ) ;
2019-08-29 17:54:26 +02:00
else if ( utxos [ i ] - > blockheight ) {
2018-02-21 23:48:01 +01:00
json_add_string ( response , " status " , " confirmed " ) ;
2019-08-29 17:54:26 +02:00
json_add_num ( response , " blockheight " , * utxos [ i ] - > blockheight ) ;
} else
2018-02-21 23:48:01 +01:00
json_add_string ( response , " status " , " unconfirmed " ) ;
2017-09-05 02:11:53 +02:00
json_object_end ( response ) ;
}
json_array_end ( response ) ;
2018-02-09 14:24:33 +01:00
/* Add funds that are allocated to channels */
json_array_start ( response , " channels " ) ;
list_for_each ( & cmd - > ld - > peers , p , list ) {
2018-02-12 11:12:55 +01:00
struct channel * c ;
list_for_each ( & p - > channels , c , list ) {
json_object_start ( response , NULL ) ;
2019-04-08 11:58:32 +02:00
json_add_node_id ( response , " peer_id " , & p - > id ) ;
2018-02-12 11:12:55 +01:00
if ( c - > scid )
json_add_short_channel_id ( response ,
" short_channel_id " ,
c - > scid ) ;
2019-05-20 07:07:40 +02:00
json_add_amount_sat_compat ( response ,
amount_msat_to_sat_round_down ( c - > our_msat ) ,
" channel_sat " ,
" our_amount_msat " ) ;
json_add_amount_sat_compat ( response , c - > funding ,
" channel_total_sat " ,
" amount_msat " ) ;
2018-02-19 02:06:12 +01:00
json_add_txid ( response , " funding_txid " ,
& c - > funding_txid ) ;
2019-07-25 21:48:36 +02:00
json_add_num ( response , " funding_output " ,
c - > funding_outnum ) ;
2018-02-12 11:12:55 +01:00
json_object_end ( response ) ;
}
2018-02-09 14:24:33 +01:00
}
json_array_end ( response ) ;
2018-12-16 05:52:06 +01:00
return command_success ( cmd , response ) ;
2017-09-05 02:11:53 +02:00
}
static const struct json_command listfunds_command = {
2018-01-22 09:55:07 +01:00
" listfunds " ,
2019-05-22 16:08:16 +02:00
" utility " ,
2018-01-22 09:55:07 +01:00
json_listfunds ,
2018-04-20 10:09:50 +02:00
" Show available funds from the internal wallet " ,
false ,
2018-02-06 14:13:57 +01:00
" Returns a list of funds (outputs) that can be used by the internal wallet to open new channels or can be withdrawn, using the `withdraw` command, to another wallet. "
2018-01-22 09:55:07 +01:00
} ;
2017-09-05 02:11:53 +02:00
AUTODATA ( json_command , & listfunds_command ) ;
2018-01-31 23:38:27 +01:00
struct txo_rescan {
struct command * cmd ;
struct utxo * * utxos ;
2018-10-19 03:17:49 +02:00
struct json_stream * response ;
2018-01-31 23:38:27 +01:00
} ;
static void process_utxo_result ( struct bitcoind * bitcoind ,
const struct bitcoin_tx_output * txout ,
void * arg )
{
struct txo_rescan * rescan = arg ;
2018-10-19 03:17:49 +02:00
struct json_stream * response = rescan - > response ;
2018-01-31 23:38:27 +01:00
struct utxo * u = rescan - > utxos [ 0 ] ;
enum output_status newstate =
txout = = NULL ? output_state_spent : output_state_available ;
json_object_start ( rescan - > response , NULL ) ;
json_add_txid ( response , " txid " , & u - > txid ) ;
json_add_num ( response , " output " , u - > outnum ) ;
json_add_num ( response , " oldstate " , u - > status ) ;
json_add_num ( response , " newstate " , newstate ) ;
json_object_end ( rescan - > response ) ;
wallet_update_output_status ( bitcoind - > ld - > wallet , & u - > txid , u - > outnum ,
u - > status , newstate ) ;
/* Remove the utxo we just resolved */
rescan - > utxos [ 0 ] = rescan - > utxos [ tal_count ( rescan - > utxos ) - 1 ] ;
tal_resize ( & rescan - > utxos , tal_count ( rescan - > utxos ) - 1 ) ;
if ( tal_count ( rescan - > utxos ) = = 0 ) {
/* Complete the response */
json_array_end ( rescan - > response ) ;
2018-12-16 05:53:06 +01:00
was_pending ( command_success ( rescan - > cmd , rescan - > response ) ) ;
2018-01-31 23:38:27 +01:00
} else {
bitcoind_gettxout (
bitcoind - > ld - > topology - > bitcoind , & rescan - > utxos [ 0 ] - > txid ,
rescan - > utxos [ 0 ] - > outnum , process_utxo_result , rescan ) ;
}
}
2018-12-16 05:52:06 +01:00
static struct command_result * json_dev_rescan_outputs ( struct command * cmd ,
const char * buffer ,
const jsmntok_t * obj UNNEEDED ,
const jsmntok_t * params )
2018-01-31 23:38:27 +01:00
{
struct txo_rescan * rescan = tal ( cmd , struct txo_rescan ) ;
2018-09-14 16:51:04 +02:00
if ( ! param ( cmd , buffer , params , NULL ) )
2018-12-16 05:52:06 +01:00
return command_param_failed ( ) ;
2018-09-14 16:51:04 +02:00
2018-10-19 03:17:48 +02:00
rescan - > response = json_stream_success ( cmd ) ;
2018-01-31 23:38:27 +01:00
rescan - > cmd = cmd ;
2019-06-12 02:38:54 +02:00
/* Open the outputs structure so we can incrementally add results */
2018-01-31 23:38:27 +01:00
json_array_start ( rescan - > response , " outputs " ) ;
2018-02-08 02:06:52 +01:00
rescan - > utxos = wallet_get_utxos ( rescan , cmd - > ld - > wallet , output_state_any ) ;
if ( tal_count ( rescan - > utxos ) = = 0 ) {
json_array_end ( rescan - > response ) ;
2018-12-16 05:52:06 +01:00
return command_success ( cmd , rescan - > response ) ;
2018-02-08 02:06:52 +01:00
}
2018-01-31 23:38:27 +01:00
bitcoind_gettxout ( cmd - > ld - > topology - > bitcoind , & rescan - > utxos [ 0 ] - > txid ,
rescan - > utxos [ 0 ] - > outnum , process_utxo_result ,
rescan ) ;
2018-12-16 05:52:06 +01:00
return command_still_pending ( cmd ) ;
2018-01-31 23:38:27 +01:00
}
static const struct json_command dev_rescan_output_command = {
2018-04-20 10:09:50 +02:00
" dev-rescan-outputs " ,
2019-05-22 16:08:16 +02:00
" developer " ,
2018-04-20 10:09:50 +02:00
json_dev_rescan_outputs ,
" Synchronize the state of our funds with bitcoind " ,
false ,
" For each output stored in the internal wallet ask `bitcoind` whether we are in sync with its state (spent vs. unspent) "
2018-01-31 23:38:27 +01:00
} ;
AUTODATA ( json_command , & dev_rescan_output_command ) ;
2019-05-28 22:39:48 +02:00
2019-06-23 02:41:19 +02:00
# if EXPERIMENTAL_FEATURES
2019-05-28 22:39:48 +02:00
struct {
enum wallet_tx_type t ;
const char * name ;
} wallet_tx_type_display_names [ ] = {
{ TX_THEIRS , " theirs " } ,
{ TX_WALLET_DEPOSIT , " deposit " } ,
{ TX_WALLET_WITHDRAWAL , " withdraw " } ,
{ TX_CHANNEL_FUNDING , " channel_funding " } ,
{ TX_CHANNEL_CLOSE , " channel_mutual_close " } ,
{ TX_CHANNEL_UNILATERAL , " channel_unilateral_close " } ,
{ TX_CHANNEL_SWEEP , " channel_sweep " } ,
{ TX_CHANNEL_HTLC_SUCCESS , " channel_htlc_success " } ,
{ TX_CHANNEL_HTLC_TIMEOUT , " channel_htlc_timeout " } ,
{ TX_CHANNEL_PENALTY , " channel_penalty " } ,
{ TX_CHANNEL_CHEAT , " channel_unilateral_cheat " } ,
{ 0 , NULL }
} ;
2019-06-07 11:38:20 +02:00
static void json_add_txtypes ( struct json_stream * result , const char * fieldname , enum wallet_tx_type value )
2019-05-28 22:39:48 +02:00
{
json_array_start ( result , fieldname ) ;
for ( size_t i = 0 ; wallet_tx_type_display_names [ i ] . name ! = NULL ; i + + ) {
if ( value & wallet_tx_type_display_names [ i ] . t )
json_add_string ( result , NULL , wallet_tx_type_display_names [ i ] . name ) ;
}
json_array_end ( result ) ;
}
static struct command_result * json_listtransactions ( struct command * cmd ,
const char * buffer ,
const jsmntok_t * obj UNNEEDED ,
const jsmntok_t * params )
{
struct json_stream * response ;
struct wallet_transaction * txs ;
if ( ! param ( cmd , buffer , params , NULL ) )
return command_param_failed ( ) ;
2019-06-22 03:10:39 +02:00
txs = wallet_transactions_get ( cmd - > ld - > wallet , cmd ) ;
2019-05-28 22:39:48 +02:00
2019-06-22 03:10:39 +02:00
response = json_stream_success ( cmd ) ;
2019-05-28 22:39:48 +02:00
json_array_start ( response , " transactions " ) ;
for ( size_t i = 0 ; i < tal_count ( txs ) ; i + + ) {
json_object_start ( response , NULL ) ;
json_add_txid ( response , " hash " , & txs [ i ] . id ) ;
json_add_hex_talarr ( response , " rawtx " , txs [ i ] . rawtx ) ;
json_add_u64 ( response , " blockheight " , txs [ i ] . blockheight ) ;
json_add_num ( response , " txindex " , txs [ i ] . txindex ) ;
json_add_txtypes ( response , " type " , txs [ i ] . type ) ;
if ( txs [ i ] . channel_id ! = 0 ) {
json_add_num ( response , " channel_id " , txs [ i ] . channel_id ) ;
} else {
json_add_null ( response , " channel_id " ) ;
}
json_object_end ( response ) ;
}
json_array_end ( response ) ;
return command_success ( cmd , response ) ;
}
static const struct json_command listtransactions_command = {
" listtransactions " ,
" payment " ,
json_listtransactions ,
" List transactions that we stored in the wallet " ,
false ,
" Returns transactions tracked in the wallet. This includes deposits, "
" withdrawals and transactions related to channels. A transaction may have "
" multiple types, e.g., a transaction may both be a close and a deposit if "
" it closes the channel and returns funds to the wallet. "
} ;
AUTODATA ( json_command , & listtransactions_command ) ;
2019-06-23 02:41:19 +02:00
# endif