diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 44b9edf62..088d5e2ac 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -586,6 +586,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("import_key_images", boost::bind(&simple_wallet::import_key_images, this, _1), tr("Import signed key images list and verify their spent status")); m_cmd_binder.set_handler("export_outputs", boost::bind(&simple_wallet::export_outputs, this, _1), tr("Export a set of outputs owned by this wallet")); m_cmd_binder.set_handler("import_outputs", boost::bind(&simple_wallet::import_outputs, this, _1), tr("Import set of outputs owned by this wallet")); + m_cmd_binder.set_handler("show_transfer", boost::bind(&simple_wallet::show_transfer, this, _1), tr("Show information about a transfer to/from this address")); m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), tr("Show this help")); } //---------------------------------------------------------------------------------------------------- @@ -3998,6 +3999,128 @@ bool simple_wallet::import_outputs(const std::vector &args) return true; } //---------------------------------------------------------------------------------------------------- +bool simple_wallet::show_transfer(const std::vector &args) +{ + if (args.size() != 1) + { + fail_msg_writer() << tr("usage: show_transfer "); + return true; + } + + cryptonote::blobdata txid_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(args.front(), txid_data)) + { + fail_msg_writer() << tr("failed to parse txid"); + return false; + } + crypto::hash txid = *reinterpret_cast(txid_data.data()); + + std::list> payments; + m_wallet->get_payments(payments, 0); + for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { + const tools::wallet2::payment_details &pd = i->second; + if (pd.m_tx_hash == txid) { + std::string payment_id = string_tools::pod_to_hex(i->first); + if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) + payment_id = payment_id.substr(0,16); + success_msg_writer() << "Incoming transaction found"; + success_msg_writer() << "txid: " << txid; + success_msg_writer() << "Height: " << pd.m_block_height; + success_msg_writer() << "Timestamp: " << get_human_readable_timestamp(pd.m_timestamp); + success_msg_writer() << "Amount: " << print_money(pd.m_amount); + success_msg_writer() << "Payment ID: " << payment_id; + success_msg_writer() << "Note: " << m_wallet->get_tx_note(txid); + return true; + } + } + + std::list> payments_out; + m_wallet->get_payments_out(payments_out, 0); + for (std::list>::const_iterator i = payments_out.begin(); i != payments_out.end(); ++i) { + if (i->first == txid) + { + const tools::wallet2::confirmed_transfer_details &pd = i->second; + uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known + uint64_t fee = pd.m_amount_in - pd.m_amount_out; + std::string dests; + for (const auto &d: pd.m_dests) { + if (!dests.empty()) + dests += ", "; + dests += get_account_address_as_str(m_wallet->testnet(), d.addr) + ": " + print_money(d.amount); + } + std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id); + if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) + payment_id = payment_id.substr(0,16); + success_msg_writer() << "Outgoing transaction found"; + success_msg_writer() << "txid: " << txid; + success_msg_writer() << "Height: " << pd.m_block_height; + success_msg_writer() << "Timestamp: " << get_human_readable_timestamp(pd.m_timestamp); + success_msg_writer() << "Amount: " << print_money(pd.m_amount_in - change - fee); + success_msg_writer() << "Payment ID: " << payment_id; + success_msg_writer() << "Change: " << print_money(change); + success_msg_writer() << "Fee: " << print_money(fee); + success_msg_writer() << "Destinations: " << dests; + success_msg_writer() << "Note: " << m_wallet->get_tx_note(txid); + return true; + } + } + + try + { + m_wallet->update_pool_state(); + std::list> pool_payments; + m_wallet->get_unconfirmed_payments(pool_payments); + for (std::list>::const_iterator i = pool_payments.begin(); i != pool_payments.end(); ++i) { + const tools::wallet2::payment_details &pd = i->second; + if (pd.m_tx_hash == txid) + { + std::string payment_id = string_tools::pod_to_hex(i->first); + if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) + payment_id = payment_id.substr(0,16); + success_msg_writer() << "Unconfirmed incoming transaction found in the txpool"; + success_msg_writer() << "txid: " << txid; + success_msg_writer() << "Timestamp: " << get_human_readable_timestamp(pd.m_timestamp); + success_msg_writer() << "Amount: " << print_money(pd.m_amount); + success_msg_writer() << "Payment ID: " << payment_id; + success_msg_writer() << "Note: " << m_wallet->get_tx_note(txid); + return true; + } + } + } + catch (...) + { + fail_msg_writer() << "Failed to get pool state"; + } + + std::list> upayments; + m_wallet->get_unconfirmed_payments_out(upayments); + for (std::list>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) { + if (i->first == txid) + { + const tools::wallet2::unconfirmed_transfer_details &pd = i->second; + uint64_t amount = pd.m_amount_in; + uint64_t fee = amount - pd.m_amount_out; + std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id); + if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) + payment_id = payment_id.substr(0,16); + bool is_failed = pd.m_state == tools::wallet2::unconfirmed_transfer_details::failed; + + success_msg_writer() << (is_failed ? "Failed" : "Pending") << " outgoing transaction found"; + success_msg_writer() << "txid: " << txid; + success_msg_writer() << "Timestamp: " << get_human_readable_timestamp(pd.m_timestamp); + success_msg_writer() << "Amount: " << print_money(amount - pd.m_change - fee); + success_msg_writer() << "Payment ID: " << payment_id; + success_msg_writer() << "Change: " << print_money(pd.m_change); + success_msg_writer() << "Fee: " << print_money(fee); + success_msg_writer() << "Note: " << m_wallet->get_tx_note(txid); + return true; + } + } + + fail_msg_writer() << tr("Transaction ID not found"); + return true; +} +//---------------------------------------------------------------------------------------------------- bool simple_wallet::process_command(const std::vector &args) { return m_cmd_binder.process_command_vec(args); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index a807e2cda..753bca74d 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -157,6 +157,7 @@ namespace cryptonote bool import_key_images(const std::vector &args); bool export_outputs(const std::vector &args); bool import_outputs(const std::vector &args); + bool show_transfer(const std::vector &args); uint64_t get_daemon_blockchain_height(std::string& err); bool try_connect_to_daemon(bool silent = false); diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 2a259029d..21965c4c8 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -201,6 +201,73 @@ namespace tools ); } //------------------------------------------------------------------------------------------------------------------------------ + void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd) + { + entry.txid = string_tools::pod_to_hex(pd.m_tx_hash); + entry.payment_id = string_tools::pod_to_hex(payment_id); + if (entry.payment_id.substr(16).find_first_not_of('0') == std::string::npos) + entry.payment_id = entry.payment_id.substr(0,16); + entry.height = pd.m_block_height; + entry.timestamp = pd.m_timestamp; + entry.amount = pd.m_amount; + entry.fee = 0; // TODO + entry.note = m_wallet.get_tx_note(pd.m_tx_hash); + entry.type = "in"; + } + //------------------------------------------------------------------------------------------------------------------------------ + void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::confirmed_transfer_details &pd) + { + entry.txid = string_tools::pod_to_hex(txid); + entry.payment_id = string_tools::pod_to_hex(pd.m_payment_id); + if (entry.payment_id.substr(16).find_first_not_of('0') == std::string::npos) + entry.payment_id = entry.payment_id.substr(0,16); + entry.height = pd.m_block_height; + entry.timestamp = pd.m_timestamp; + entry.fee = pd.m_amount_in - pd.m_amount_out; + uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known + entry.amount = pd.m_amount_in - change - entry.fee; + entry.note = m_wallet.get_tx_note(txid); + + for (const auto &d: pd.m_dests) { + entry.destinations.push_back(wallet_rpc::transfer_destination()); + wallet_rpc::transfer_destination &td = entry.destinations.back(); + td.amount = d.amount; + td.address = get_account_address_as_str(m_wallet.testnet(), d.addr); + } + + entry.type = "out"; + } + //------------------------------------------------------------------------------------------------------------------------------ + void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::unconfirmed_transfer_details &pd) + { + bool is_failed = pd.m_state == tools::wallet2::unconfirmed_transfer_details::failed; + entry.txid = string_tools::pod_to_hex(txid); + entry.payment_id = string_tools::pod_to_hex(pd.m_payment_id); + entry.payment_id = string_tools::pod_to_hex(pd.m_payment_id); + if (entry.payment_id.substr(16).find_first_not_of('0') == std::string::npos) + entry.payment_id = entry.payment_id.substr(0,16); + entry.height = 0; + entry.timestamp = pd.m_timestamp; + entry.fee = pd.m_amount_in - pd.m_amount_out; + entry.amount = pd.m_amount_in - pd.m_change - entry.fee; + entry.note = m_wallet.get_tx_note(txid); + entry.type = is_failed ? "failed" : "pending"; + } + //------------------------------------------------------------------------------------------------------------------------------ + void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd) + { + entry.txid = string_tools::pod_to_hex(pd.m_tx_hash); + entry.payment_id = string_tools::pod_to_hex(payment_id); + if (entry.payment_id.substr(16).find_first_not_of('0') == std::string::npos) + entry.payment_id = entry.payment_id.substr(0,16); + entry.height = 0; + entry.timestamp = pd.m_timestamp; + entry.amount = pd.m_amount; + entry.fee = 0; // TODO + entry.note = m_wallet.get_tx_note(pd.m_tx_hash); + entry.type = "pool"; + } + //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er) { try @@ -1014,19 +1081,8 @@ namespace tools std::list> payments; m_wallet.get_payments(payments, min_height, max_height); for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { - res.in.push_back(wallet_rpc::COMMAND_RPC_GET_TRANSFERS::entry()); - wallet_rpc::COMMAND_RPC_GET_TRANSFERS::entry &entry = res.in.back(); - const tools::wallet2::payment_details &pd = i->second; - - entry.txid = string_tools::pod_to_hex(pd.m_tx_hash); - entry.payment_id = string_tools::pod_to_hex(i->first); - if (entry.payment_id.substr(16).find_first_not_of('0') == std::string::npos) - entry.payment_id = entry.payment_id.substr(0,16); - entry.height = pd.m_block_height; - entry.timestamp = pd.m_timestamp; - entry.amount = pd.m_amount; - entry.fee = 0; // TODO - entry.note = m_wallet.get_tx_note(pd.m_tx_hash); + res.in.push_back(wallet_rpc::transfer_entry()); + fill_transfer_entry(res.in.back(), i->second.m_tx_hash, i->first, i->second); } } @@ -1035,27 +1091,8 @@ namespace tools std::list> payments; m_wallet.get_payments_out(payments, min_height, max_height); for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { - res.out.push_back(wallet_rpc::COMMAND_RPC_GET_TRANSFERS::entry()); - wallet_rpc::COMMAND_RPC_GET_TRANSFERS::entry &entry = res.out.back(); - const tools::wallet2::confirmed_transfer_details &pd = i->second; - - entry.txid = string_tools::pod_to_hex(i->first); - entry.payment_id = string_tools::pod_to_hex(i->second.m_payment_id); - if (entry.payment_id.substr(16).find_first_not_of('0') == std::string::npos) - entry.payment_id = entry.payment_id.substr(0,16); - entry.height = pd.m_block_height; - entry.timestamp = pd.m_timestamp; - entry.fee = pd.m_amount_in - pd.m_amount_out; - uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known - entry.amount = pd.m_amount_in - change - entry.fee; - entry.note = m_wallet.get_tx_note(i->first); - - for (const auto &d: pd.m_dests) { - entry.destinations.push_back(wallet_rpc::transfer_destination()); - wallet_rpc::transfer_destination &td = entry.destinations.back(); - td.amount = d.amount; - td.address = get_account_address_as_str(m_wallet.testnet(), d.addr); - } + res.out.push_back(wallet_rpc::transfer_entry()); + fill_transfer_entry(res.out.back(), i->first, i->second); } } @@ -1067,20 +1104,9 @@ namespace tools bool is_failed = pd.m_state == tools::wallet2::unconfirmed_transfer_details::failed; if (!((req.failed && is_failed) || (!is_failed && req.pending))) continue; - std::list &entries = is_failed ? res.failed : res.pending; - entries.push_back(wallet_rpc::COMMAND_RPC_GET_TRANSFERS::entry()); - wallet_rpc::COMMAND_RPC_GET_TRANSFERS::entry &entry = entries.back(); - - entry.txid = string_tools::pod_to_hex(i->first); - entry.payment_id = string_tools::pod_to_hex(i->second.m_payment_id); - entry.payment_id = string_tools::pod_to_hex(i->second.m_payment_id); - if (entry.payment_id.substr(16).find_first_not_of('0') == std::string::npos) - entry.payment_id = entry.payment_id.substr(0,16); - entry.height = 0; - entry.timestamp = pd.m_timestamp; - entry.fee = pd.m_amount_in - pd.m_amount_out; - entry.amount = pd.m_amount_in - pd.m_change - entry.fee; - entry.note = m_wallet.get_tx_note(i->first); + std::list &entries = is_failed ? res.failed : res.pending; + entries.push_back(wallet_rpc::transfer_entry()); + fill_transfer_entry(entries.back(), i->first, i->second); } } @@ -1091,25 +1117,90 @@ namespace tools std::list> payments; m_wallet.get_unconfirmed_payments(payments); for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { - res.pool.push_back(wallet_rpc::COMMAND_RPC_GET_TRANSFERS::entry()); - wallet_rpc::COMMAND_RPC_GET_TRANSFERS::entry &entry = res.pool.back(); - const tools::wallet2::payment_details &pd = i->second; - - entry.txid = string_tools::pod_to_hex(pd.m_tx_hash); - entry.payment_id = string_tools::pod_to_hex(i->first); - if (entry.payment_id.substr(16).find_first_not_of('0') == std::string::npos) - entry.payment_id = entry.payment_id.substr(0,16); - entry.height = 0; - entry.timestamp = pd.m_timestamp; - entry.amount = pd.m_amount; - entry.fee = 0; // TODO - entry.note = m_wallet.get_tx_note(pd.m_tx_hash); + res.pool.push_back(wallet_rpc::transfer_entry()); + fill_transfer_entry(res.pool.back(), i->first, i->second); } } return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_get_transfer_by_txid(const wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::response& res, epee::json_rpc::error& er) + { + if (m_wallet.restricted()) + { + er.code = WALLET_RPC_ERROR_CODE_DENIED; + er.message = "Command unavailable in restricted mode."; + return false; + } + + crypto::hash txid; + cryptonote::blobdata txid_blob; + if(!epee::string_tools::parse_hexstr_to_binbuff(req.txid, txid_blob)) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_TXID; + er.message = "Transaction ID has invalid format"; + return false; + } + + if(sizeof(txid) == txid_blob.size()) + { + txid = *reinterpret_cast(txid_blob.data()); + } + else + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_TXID; + er.message = "Transaction ID has invalid size: " + req.txid; + return false; + } + + std::list> payments; + m_wallet.get_payments(payments, 0); + for (std::list>::const_iterator i = payments.begin(); i != payments.end(); ++i) { + if (i->first == txid) + { + fill_transfer_entry(res.transfer, i->second.m_tx_hash, i->first, i->second); + return true; + } + } + + std::list> payments_out; + m_wallet.get_payments_out(payments_out, 0); + for (std::list>::const_iterator i = payments_out.begin(); i != payments_out.end(); ++i) { + if (i->first == txid) + { + fill_transfer_entry(res.transfer, i->first, i->second); + return true; + } + } + + std::list> upayments; + m_wallet.get_unconfirmed_payments_out(upayments); + for (std::list>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) { + if (i->first == txid) + { + fill_transfer_entry(res.transfer, i->first, i->second); + return true; + } + } + + m_wallet.update_pool_state(); + + std::list> pool_payments; + m_wallet.get_unconfirmed_payments(pool_payments); + for (std::list>::const_iterator i = pool_payments.begin(); i != pool_payments.end(); ++i) { + if (i->second.m_tx_hash == txid) + { + fill_transfer_entry(res.transfer, i->first, i->second); + return true; + } + } + + er.code = WALLET_RPC_ERROR_CODE_WRONG_TXID; + er.message = "Transaction not found."; + return false; + } + //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_export_key_images(const wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er) { try diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index 92deec043..4ff1b267f 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -78,6 +78,7 @@ namespace tools MAP_JON_RPC_WE("set_tx_notes", on_set_tx_notes, wallet_rpc::COMMAND_RPC_SET_TX_NOTES) MAP_JON_RPC_WE("get_tx_notes", on_get_tx_notes, wallet_rpc::COMMAND_RPC_GET_TX_NOTES) MAP_JON_RPC_WE("get_transfers", on_get_transfers, wallet_rpc::COMMAND_RPC_GET_TRANSFERS) + MAP_JON_RPC_WE("get_transfer_by_txid", on_get_transfer_by_txid, wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID) MAP_JON_RPC_WE("sign", on_sign, wallet_rpc::COMMAND_RPC_SIGN) MAP_JON_RPC_WE("verify", on_verify, wallet_rpc::COMMAND_RPC_VERIFY) MAP_JON_RPC_WE("export_key_images", on_export_key_images, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES) @@ -107,6 +108,7 @@ namespace tools bool on_set_tx_notes(const wallet_rpc::COMMAND_RPC_SET_TX_NOTES::request& req, wallet_rpc::COMMAND_RPC_SET_TX_NOTES::response& res, epee::json_rpc::error& er); bool on_get_tx_notes(const wallet_rpc::COMMAND_RPC_GET_TX_NOTES::request& req, wallet_rpc::COMMAND_RPC_GET_TX_NOTES::response& res, epee::json_rpc::error& er); bool on_get_transfers(const wallet_rpc::COMMAND_RPC_GET_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFERS::response& res, epee::json_rpc::error& er); + bool on_get_transfer_by_txid(const wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::response& res, epee::json_rpc::error& er); bool on_sign(const wallet_rpc::COMMAND_RPC_SIGN::request& req, wallet_rpc::COMMAND_RPC_SIGN::response& res, epee::json_rpc::error& er); bool on_verify(const wallet_rpc::COMMAND_RPC_VERIFY::request& req, wallet_rpc::COMMAND_RPC_VERIFY::response& res, epee::json_rpc::error& er); bool on_export_key_images(const wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er); @@ -117,6 +119,12 @@ namespace tools //json rpc v2 bool on_query_key(const wallet_rpc::COMMAND_RPC_QUERY_KEY::request& req, wallet_rpc::COMMAND_RPC_QUERY_KEY::response& res, epee::json_rpc::error& er); + // helpers + void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd); + void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::confirmed_transfer_details &pd); + void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::unconfirmed_transfer_details &pd); + void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd); + wallet2& m_wallet; std::string rpc_login_filename; std::atomic m_stop; diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 50b1613f9..ea0fc685f 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -525,6 +525,31 @@ namespace wallet_rpc }; }; + struct transfer_entry + { + std::string txid; + std::string payment_id; + uint64_t height; + uint64_t timestamp; + uint64_t amount; + uint64_t fee; + std::string note; + std::list destinations; + std::string type; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(txid); + KV_SERIALIZE(payment_id); + KV_SERIALIZE(height); + KV_SERIALIZE(timestamp); + KV_SERIALIZE(amount); + KV_SERIALIZE(fee); + KV_SERIALIZE(note); + KV_SERIALIZE(destinations); + KV_SERIALIZE(type); + END_KV_SERIALIZE_MAP() + }; + struct COMMAND_RPC_GET_TRANSFERS { struct request @@ -551,36 +576,13 @@ namespace wallet_rpc END_KV_SERIALIZE_MAP() }; - struct entry - { - std::string txid; - std::string payment_id; - uint64_t height; - uint64_t timestamp; - uint64_t amount; - uint64_t fee; - std::string note; - std::list destinations; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(txid); - KV_SERIALIZE(payment_id); - KV_SERIALIZE(height); - KV_SERIALIZE(timestamp); - KV_SERIALIZE(amount); - KV_SERIALIZE(fee); - KV_SERIALIZE(note); - KV_SERIALIZE(destinations); - END_KV_SERIALIZE_MAP() - }; - struct response { - std::list in; - std::list out; - std::list pending; - std::list failed; - std::list pool; + std::list in; + std::list out; + std::list pending; + std::list failed; + std::list pool; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(in); @@ -592,6 +594,27 @@ namespace wallet_rpc }; }; + struct COMMAND_RPC_GET_TRANSFER_BY_TXID + { + struct request + { + std::string txid; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(txid); + END_KV_SERIALIZE_MAP() + }; + + struct response + { + transfer_entry transfer; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(transfer); + END_KV_SERIALIZE_MAP() + }; + }; + struct COMMAND_RPC_SIGN { struct request