Implemented async monero send routine

pull/11/head
Paul Shapiro 6 years ago
parent 41fbc55521
commit 399d3fadf1

@ -9,32 +9,8 @@ enable_testing()
#Prep ourselves for compiling boost
find_package(Boost COMPONENTS
unit_test_framework REQUIRED
# atomic REQUIRED
# chrono REQUIRED
# context REQUIRED
# date_time REQUIRED
# exception REQUIRED
# filesystem REQUIRED
# graph REQUIRED
# iostreams REQUIRED
# math_c99 REQUIRED
# math_c99f REQUIRED
# math_c99l REQUIRED
# math_tr1 REQUIRED
# math_tr1f REQUIRED
# math_tr1l REQUIRED
# prg_exec_monitor REQUIRED
# program_options REQUIRED
# random REQUIRED
# regex REQUIRED
# serialization REQUIRED
# signals REQUIRED
system REQUIRED
# test_exec_monitor REQUIRED
thread REQUIRED
# timer REQUIRED
# wave REQUIRED
# wserialization REQUIRED
)
set(MONERO_SRC "contrib/monero-core-custom")
@ -73,12 +49,18 @@ set(
src/monero_fee_utils.cpp
src/monero_transfer_utils.hpp
src/monero_transfer_utils.cpp
src/monero_send_routine.hpp
src/monero_send_routine.cpp
src/monero_fork_rules.hpp
src/monero_fork_rules.cpp
src/monero_wallet_utils.hpp
src/monero_wallet_utils.cpp
src/serial_bridge_index.hpp
src/serial_bridge_index.cpp
src/serial_bridge_utils.hpp
src/serial_bridge_utils.cpp
# src/emscr_async_bridge_index.hpp
# src/emscr_async_bridge_index.cpp
src/tools__ret_vals.hpp
src/tools__ret_vals.cpp
#

@ -0,0 +1,525 @@
//
// monero_send_routine.cpp
// Copyright © 2018 MyMonero. All rights reserved.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
//
//
#include <boost/property_tree/json_parser.hpp>
#include "wallet_errors.h"
#include "string_tools.h"
//
#include "monero_send_routine.hpp"
//
#include "monero_transfer_utils.hpp"
#include "monero_fork_rules.hpp"
#include "monero_key_image_utils.hpp"
#include "monero_address_utils.hpp"
//
using namespace std;
using namespace crypto;
using namespace std;
using namespace boost;
using namespace epee;
using namespace cryptonote;
using namespace tools; // for error::
using namespace monero_transfer_utils;
using namespace monero_fork_rules;
using namespace monero_key_image_utils; // for API response parsing
using namespace monero_send_routine;
//
//
optional<uint64_t> _possible_uint64_from_json(
const boost::property_tree::ptree &res,
const string &fieldname
) { // throws
auto optl_str = res.get_optional<string>(fieldname);
// cout << fieldname << ": " << optl_str << endl;
if (optl_str != none) {
return stoull(*optl_str);
}
auto optl_uint32 = res.get_optional<uint32_t>(fieldname); // not uint64 b/c JSON can't store such values
if (optl_uint32 != none) {
return (uint64_t)*optl_uint32; // cast
}
return none;
}
//
LightwalletAPI_Req_GetUnspentOuts monero_send_routine::new__req_params__get_unspent_outs(
const string &from_address_string,
const string &sec_viewKey_string
) {
stringstream dustT_ss;
dustT_ss << dust_threshold();
return {
from_address_string,
sec_viewKey_string,
"0", // amount - always sent as "0"
fixed_mixinsize(),
true, // use dust
dustT_ss.str()
};
}
LightwalletAPI_Req_GetRandomOuts monero_send_routine::new__req_params__get_random_outs(
vector<SpendableOutput> &step1__using_outs
) {
vector<string> decoy_req__amounts;
BOOST_FOREACH(SpendableOutput &using_out, step1__using_outs)
{
if (using_out.rct != none && (*(using_out.rct)).size() > 0) {
decoy_req__amounts.push_back("0");
} else {
stringstream amount_ss;
amount_ss << using_out.amount;
decoy_req__amounts.push_back(amount_ss.str());
}
}
return LightwalletAPI_Req_GetRandomOuts{
decoy_req__amounts,
fixed_mixinsize() + 1 // count; Add one to mixin so we can skip real output key if necessary
};
}
//
LightwalletAPI_Res_GetUnspentOuts monero_send_routine::new__parsed_res__get_unspent_outs(
property_tree::ptree &res,
const secret_key &sec_viewKey,
const secret_key &sec_spendKey,
const public_key &pub_spendKey
) {
uint64_t final__per_byte_fee = 0;
try {
optional<uint64_t> possible__uint64 = _possible_uint64_from_json(res, "per_byte_fee");
if (possible__uint64 != none) {
final__per_byte_fee = *possible__uint64;
}
} catch (const std::exception &e) {
cout << "Unspent outs per-byte-fee parse error: " << e.what() << endl;
string err_msg = "Unspent outs: Unrecognized per-byte fee format";
return {
err_msg,
none, none
};
}
if (final__per_byte_fee == 0) {
try {
optional<uint64_t> possible__uint64 = _possible_uint64_from_json(res, "per_kb_fee");
if (possible__uint64 != none) {
final__per_byte_fee = (*possible__uint64) / 1024; // scale from kib to b
}
} catch (const std::exception &e) {
cout << "Unspent outs per-kb-fee parse error: " << e.what() << endl;
string err_msg = "Unspent outs: Unrecognized per-kb fee format";
return {
err_msg,
none, none
};
}
}
if (final__per_byte_fee == 0) {
string err_msg = "Unable to get a per-byte fee from server response.";
return {
err_msg,
none, none
};
}
vector<SpendableOutput> unspent_outs;
BOOST_FOREACH(boost::property_tree::ptree::value_type &output_desc, res.get_child("outputs"))
{
assert(output_desc.first.empty()); // array elements have no names
//
auto optl__tx_pub_key = output_desc.second.get_optional<string>("tx_pub_key");
if (optl__tx_pub_key == none) { // TODO: do we ever actually expect these not to exist?
cout << "Warn: This unspent out was missing a tx_pub_key. Skipping." << endl;
continue; // skip
}
crypto::public_key tx_pub_key{};
{
bool r = epee::string_tools::hex_to_pod(*optl__tx_pub_key, tx_pub_key);
if (!r) {
string err_msg = "Invalid tx pub key";
return {
err_msg,
none, none
};
}
}
uint64_t output__index;
try {
optional<uint64_t> possible__uint64 = _possible_uint64_from_json(output_desc.second, "index");
if (possible__uint64 != none) {
output__index = *possible__uint64; // expecting this to exist
} else { // bail
string err_msg = "Expected unspent output to have an \"index\"";
return {
err_msg,
none, none
};
}
} catch (const std::exception &e) {
cout << "Unspent outs output index parse error: " << e.what() << endl;
string err_msg = "Unspent outs: Unrecognized output index format";
return {
err_msg,
none, none
};
}
bool isOutputSpent = false; // let's see…
{
BOOST_FOREACH(boost::property_tree::ptree::value_type &spend_key_image_string, output_desc.second.get_child("spend_key_images"))
{
// cout << "spend_key_image_string: " << spend_key_image_string.second.data() << endl;
KeyImageRetVals retVals;
bool r = new__key_image(
pub_spendKey, sec_spendKey, sec_viewKey, tx_pub_key,
output__index,
retVals
);
if (!r) {
string err_msg = "Unable to generate key image";
return {
err_msg,
none, none
};
}
auto calculated_key_image_string = epee::string_tools::pod_to_hex(retVals.calculated_key_image);
// cout << "calculated_key_image_string: " << calculated_key_image_string << endl;
auto areEqual = calculated_key_image_string == spend_key_image_string.second.data();
if (areEqual) {
isOutputSpent = true; // output was spent… exclude
break; // exit spend key img loop to evaluate isOutputSpent
}
}
}
if (isOutputSpent == false) {
SpendableOutput out{};
out.amount = stoull(output_desc.second.get<string>("amount"));
out.public_key = output_desc.second.get<string>("public_key");
out.rct = output_desc.second.get_optional<string>("rct");
out.global_index = stoull(output_desc.second.get<string>("global_index"));
out.index = output__index;
out.tx_pub_key = *optl__tx_pub_key; // just b/c we've already accessed it above
//
unspent_outs.push_back(out);
}
}
return LightwalletAPI_Res_GetUnspentOuts{
none,
final__per_byte_fee, unspent_outs
};
}
LightwalletAPI_Res_GetRandomOuts monero_send_routine::new__parsed_res__get_random_outs(
property_tree::ptree &res
) {
vector<RandomAmountOutputs> mix_outs;
BOOST_FOREACH(boost::property_tree::ptree::value_type &mix_out_desc, res.get_child("amount_outs"))
{
assert(mix_out_desc.first.empty()); // array elements have no names
auto amountAndOuts = RandomAmountOutputs{};
try {
optional<uint64_t> possible__uint64 = _possible_uint64_from_json(mix_out_desc.second, "amount");
if (possible__uint64 != none) {
amountAndOuts.amount = *possible__uint64;
}
} catch (const std::exception &e) {
cout << "Random outs response 'amount' parse error: " << e.what() << endl;
string err_msg = "Random outs: Unrecognized 'amount' format";
return {err_msg, none};
}
BOOST_FOREACH(boost::property_tree::ptree::value_type &mix_out_output_desc, mix_out_desc.second.get_child("outputs"))
{
assert(mix_out_output_desc.first.empty()); // array elements have no names
auto amountOutput = RandomAmountOutput{};
try {
optional<uint64_t> possible__uint64 = _possible_uint64_from_json(mix_out_output_desc.second, "global_index");
if (possible__uint64 != none) {
amountOutput.global_index = *possible__uint64;
}
} catch (const std::exception &e) {
cout << "Random outs response 'global_index' parse error: " << e.what() << endl;
string err_msg = "Random outs: Unrecognized 'global_index' format";
return {err_msg, none};
}
amountOutput.public_key = mix_out_output_desc.second.get<string>("public_key");
amountOutput.rct = mix_out_output_desc.second.get_optional<string>("rct");
//
amountAndOuts.outputs.push_back(amountOutput);
}
mix_outs.push_back(amountAndOuts);
}
return {
none, mix_outs
};
}
//
struct _SendFunds_ConstructAndSendTx_Args
{
const string &from_address_string;
const string &sec_viewKey_string;
const string &sec_spendKey_string;
const string &to_address_string;
optional<string> payment_id_string;
uint64_t sending_amount;
bool is_sweeping;
uint32_t simple_priority;
const send__get_random_outs_fn_type &get_random_outs_fn;
const send__submit_raw_tx_fn_type &submit_raw_tx_fn;
const send__status_update_fn_type &status_update_fn;
const send__error_cb_fn_type &error_cb_fn;
const send__success_cb_fn_type &success_cb_fn;
uint64_t unlock_time;
cryptonote::network_type nettype;
//
const vector<SpendableOutput> &unspent_outs;
uint64_t fee_per_b;
//
// cached
const secret_key &sec_viewKey;
const secret_key &sec_spendKey;
//
optional<uint64_t> passedIn_attemptAt_fee;
size_t constructionAttempt;
};
void _reenterable_construct_and_send_tx(
const _SendFunds_ConstructAndSendTx_Args &args,
//
// re-entry params
optional<uint64_t> passedIn_attemptAt_fee = none,
size_t constructionAttempt = 0
) {
args.status_update_fn(calculatingFee);
//
Send_Step1_RetVals step1_retVals;
monero_transfer_utils::send_step1__prepare_params_for_get_decoys(
step1_retVals,
//
args.payment_id_string,
args.sending_amount,
args.is_sweeping,
args.simple_priority,
[] (uint8_t version, int64_t early_blocks) -> bool
{
return lightwallet_hardcoded__use_fork_rules(version, early_blocks);
},
args.unspent_outs,
args.fee_per_b,
//
passedIn_attemptAt_fee // use this for passing step2 "must-reconstruct" return values back in, i.e. re-entry; when nil, defaults to attempt at network min
);
if (step1_retVals.errCode != noError) {
SendFunds_Error_RetVals error_retVals;
error_retVals.errCode = step1_retVals.errCode;
error_retVals.spendable_balance = step1_retVals.spendable_balance;
error_retVals.required_balance = step1_retVals.required_balance;
args.error_cb_fn(error_retVals);
return;
}
api_fetch_cb_fn get_random_outs_fn__cb_fn = [
args,
step1_retVals,
constructionAttempt
] (
property_tree::ptree res
) -> void {
auto parsed_res = new__parsed_res__get_random_outs(res);
if (parsed_res.err_msg != none) {
SendFunds_Error_RetVals error_retVals;
error_retVals.explicit_errMsg = std::move(*(parsed_res.err_msg));
args.error_cb_fn(error_retVals);
return;
}
Send_Step2_RetVals step2_retVals;
monero_transfer_utils::send_step2__try_create_transaction(
step2_retVals,
//
args.from_address_string,
args.sec_viewKey_string,
args.sec_spendKey_string,
args.to_address_string,
args.payment_id_string,
step1_retVals.final_total_wo_fee,
step1_retVals.change_amount,
step1_retVals.using_fee,
args.simple_priority,
step1_retVals.using_outs,
args.fee_per_b,
*(parsed_res.mix_outs),
[] (uint8_t version, int64_t early_blocks) -> bool
{
return lightwallet_hardcoded__use_fork_rules(version, early_blocks);
},
args.unlock_time,
args.nettype
);
if (step2_retVals.errCode != noError) {
SendFunds_Error_RetVals error_retVals;
error_retVals.errCode = step2_retVals.errCode;
args.error_cb_fn(error_retVals);
return;
}
if (step2_retVals.tx_must_be_reconstructed) {
// this will update status back to .calculatingFee
if (constructionAttempt > 15) { // just going to avoid an infinite loop here or particularly long stack
SendFunds_Error_RetVals error_retVals;
error_retVals.explicit_errMsg = "Unable to construct a transaction with sufficient fee for unknown reason.";
args.error_cb_fn(error_retVals);
return;
}
// cout << "step2_retVals.fee_actually_needed: " << step2_retVals.fee_actually_needed << endl;
_reenterable_construct_and_send_tx(
args,
//
step2_retVals.fee_actually_needed, // -> reconstruction attempt's step1's passedIn_attemptAt_fee
constructionAttempt+1
);
return;
}
args.status_update_fn(submittingTransaction);
//
api_fetch_cb_fn submit_raw_tx_fn__cb_fn = [
args,
step1_retVals,
step2_retVals
] (
property_tree::ptree res
) -> void {
// not actually expecting anything in a success response, so no need to parse
SendFunds_Success_RetVals success_retVals;
success_retVals.used_fee = step1_retVals.using_fee; // NOTE: not the same thing as step2_retVals.fee_actually_needed
success_retVals.total_sent = step1_retVals.final_total_wo_fee + step1_retVals.using_fee;
success_retVals.mixin = step1_retVals.mixin;
{
optional<string> returning__payment_id = args.payment_id_string; // separated from submit_raw_tx_fn so that it can be captured w/o capturing all of args (FIXME: does this matter?)
if (returning__payment_id == none) {
auto decoded = monero::address_utils::decodedAddress(args.to_address_string, args.nettype);
if (decoded.did_error) { // would be very strange...
SendFunds_Error_RetVals error_retVals;
error_retVals.explicit_errMsg = *(decoded.err_string);
args.error_cb_fn(error_retVals);
return;
}
if (decoded.paymentID_string != none) {
returning__payment_id = std::move(*(decoded.paymentID_string)); // just preserving this as an original return value - this can probably eventually be removed
}
}
success_retVals.final_payment_id = returning__payment_id;
}
success_retVals.signed_serialized_tx_string = std::move(*(step2_retVals.signed_serialized_tx_string));
success_retVals.tx_hash_string = std::move(*(step2_retVals.tx_hash_string));
success_retVals.tx_key_string = std::move(*(step2_retVals.tx_key_string));
success_retVals.tx_pub_key_string = std::move(*(step2_retVals.tx_pub_key_string));
//
args.success_cb_fn(success_retVals);
};
args.submit_raw_tx_fn(LightwalletAPI_Req_SubmitRawTx{
args.from_address_string,
args.sec_viewKey_string,
*(step2_retVals.signed_serialized_tx_string)
}, submit_raw_tx_fn__cb_fn);
};
//
args.status_update_fn(fetchingDecoyOutputs);
//
args.get_random_outs_fn(
new__req_params__get_random_outs(step1_retVals.using_outs),
get_random_outs_fn__cb_fn
);
}
//
//
// Entrypoint
void monero_send_routine::async__send_funds(const Async_SendFunds_Args &args)
{
uint64_t usable__sending_amount = args.is_sweeping ? 0 : args.sending_amount;
crypto::secret_key sec_viewKey{};
crypto::secret_key sec_spendKey{};
crypto::public_key pub_spendKey{};
{
bool r = false;
r = epee::string_tools::hex_to_pod(args.sec_viewKey_string, sec_viewKey);
if (!r) {
SendFunds_Error_RetVals error_retVals;
error_retVals.explicit_errMsg = "Invalid secret view key";
args.error_cb_fn(error_retVals);
return;
}
r = epee::string_tools::hex_to_pod(args.sec_spendKey_string, sec_spendKey);
if (!r) {
SendFunds_Error_RetVals error_retVals;
error_retVals.explicit_errMsg = "Invalid sec spend key";
args.error_cb_fn(error_retVals);
return;
}
r = epee::string_tools::hex_to_pod(args.pub_spendKey_string, pub_spendKey);
if (!r) {
SendFunds_Error_RetVals error_retVals;
error_retVals.explicit_errMsg = "Invalid public spend key";
args.error_cb_fn(error_retVals);
return;
}
}
api_fetch_cb_fn get_unspent_outs_fn__cb_fn = [
args,
usable__sending_amount,
sec_viewKey, sec_spendKey, pub_spendKey
] (
property_tree::ptree res
) -> void {
auto parsed_res = new__parsed_res__get_unspent_outs(
res,
sec_viewKey, sec_spendKey, pub_spendKey
);
if (parsed_res.err_msg != none) {
SendFunds_Error_RetVals error_retVals;
error_retVals.explicit_errMsg = std::move(*(parsed_res.err_msg));
args.error_cb_fn(error_retVals);
return;
}
_reenterable_construct_and_send_tx(_SendFunds_ConstructAndSendTx_Args{
args.from_address_string, args.sec_viewKey_string, args.sec_spendKey_string,
args.to_address_string, args.payment_id_string, usable__sending_amount, args.is_sweeping, args.simple_priority,
args.get_random_outs_fn, args.submit_raw_tx_fn, args.status_update_fn, args.error_cb_fn, args.success_cb_fn,
args.unlock_time == none ? 0 : *(args.unlock_time),
args.nettype == none ? MAINNET : *(args.nettype),
//
*(parsed_res.unspent_outs),
*(parsed_res.per_byte_fee),
//
sec_viewKey, sec_spendKey
});
};
args.status_update_fn(fetchingLatestBalance);
//
args.get_unspent_outs_fn(
new__req_params__get_unspent_outs(
args.from_address_string,
args.sec_viewKey_string
),
get_unspent_outs_fn__cb_fn
);
}

@ -0,0 +1,202 @@
//
// monero_send_routine.hpp
// Copyright (c) 2014-2018, MyMonero.com
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
#ifndef monero_send_routine_hpp
#define monero_send_routine_hpp
//
#include <boost/optional.hpp>
#include <boost/property_tree/ptree.hpp>
//
#include "string_tools.h"
#include "crypto.h"
#include "cryptonote_basic.h"
#include "cryptonote_format_utils.h"
//
using namespace tools;
#include "tools__ret_vals.hpp"
//
#include "monero_transfer_utils.hpp"
//
namespace monero_send_routine
{
using namespace std;
using namespace boost;
using namespace cryptonote;
using namespace monero_transfer_utils;
using namespace crypto;
//
// Abstracted Send routine
// - Accessory types - Callbacks - Data fetch hooks
typedef std::function<void(
property_tree::ptree // opted not to send str but already parsed structure - this may not be optimal but makes it so that e.g. emscr_async_bridge doesn't have to send the response as an escaped JSON string nor redundantly parse/stringify
)> api_fetch_cb_fn;
//
struct LightwalletAPI_Req_GetUnspentOuts
{ // strings are NOT references, so they get copied, allowing scope of struct init not to be an issue
const string address;
const string view_key;
const string amount; // "0" uint64_string
size_t mixin;
bool use_dust; // true; send-funds is now coded to filter unmixable and below threshold dust properly when sweeping and not sweeping
const string dust_threshold; // uint64_string; String(MoneroConstants.dustThreshold, radix: 10)
};
LightwalletAPI_Req_GetUnspentOuts new__req_params__get_unspent_outs( // used internally and by emscr async send impl
const string &from_address_string,
const string &sec_viewKey_string
);
typedef std::function<void(
LightwalletAPI_Req_GetUnspentOuts, // req_params - use these for making the request
api_fetch_cb_fn // fn cb … call this after the request responds (successfully)
)> send__get_unspent_outs_fn_type;
//
struct LightwalletAPI_Req_GetRandomOuts
{
const vector<string> amounts;
const size_t count; // =mixin+1
};
LightwalletAPI_Req_GetRandomOuts new__req_params__get_random_outs( // used internally and by emscr async send impl
vector<SpendableOutput> &step1__using_outs
);
typedef std::function<void(
LightwalletAPI_Req_GetRandomOuts, // req_params - use these for making the request
api_fetch_cb_fn // fn cb … call this after the request responds (successfully)
)> send__get_random_outs_fn_type;
//
struct LightwalletAPI_Req_SubmitRawTx
{ // strings are NOT references, so they get copied, allowing scope of struct init not to be an issue
const string address;
const string view_key;
const string tx; // serialized tx
};
typedef std::function<void(
LightwalletAPI_Req_SubmitRawTx, // req_params - use these for making the request
api_fetch_cb_fn // fn cb … call this after the request responds (successfully)
)> send__submit_raw_tx_fn_type;
//
// - Accessory types - Callbacks - Updates
enum SendFunds_ProcessStep
{ // These codes have values for serialization
fetchingLatestBalance = 1,
calculatingFee = 2,
fetchingDecoyOutputs = 3,
constructingTransaction = 4,
submittingTransaction = 5
};
typedef std::function<void(SendFunds_ProcessStep code)> send__status_update_fn_type;
static inline string err_msg_from_err_code__send_funds_step(SendFunds_ProcessStep code)
{
switch (code) {
case fetchingLatestBalance:
return "Fetching latest balance.";
case calculatingFee:
return "Calculating fee.";
case fetchingDecoyOutputs:
return "Fetching decoy outputs.";
case constructingTransaction:
return "Constructing transaction."; // which may go back to .calculatingFee
case submittingTransaction:
return "Submitted transaction.";
}
}
// - Accessory types - Callbacks - Routine completions
struct SendFunds_Error_RetVals
{
optional<string> explicit_errMsg;
optional<CreateTransactionErrorCode> errCode; // if != noError, abort Send process
// for display / information purposes on errCode=needMoreMoneyThanFound during step1:
uint64_t spendable_balance; // (effectively but not the same as spendable_balance)
uint64_t required_balance; // for display / information purposes on errCode=needMoreMoneyThanFound during step1
};
typedef std::function<void(const SendFunds_Error_RetVals &)> send__error_cb_fn_type;
//
struct SendFunds_Success_RetVals
{
uint64_t used_fee;
uint64_t total_sent; // final_total_wo_fee + final_fee
size_t mixin;
optional<string> final_payment_id; // will be filled if a payment id was passed in or an integrated address was used
string signed_serialized_tx_string;
string tx_hash_string;
string tx_key_string; // this includes additional_tx_keys
string tx_pub_key_string; // from get_tx_pub_key_from_extra()
};
typedef std::function<void(const SendFunds_Success_RetVals &)> send__success_cb_fn_type;
//
// Response parsing
struct LightwalletAPI_Res_GetUnspentOuts
{
optional<string> err_msg;
// OR
optional<uint64_t> per_byte_fee;
optional<vector<SpendableOutput>> unspent_outs;
};
struct LightwalletAPI_Res_GetRandomOuts
{
optional<string> err_msg;
// OR
optional<vector<RandomAmountOutputs>> mix_outs;
};
LightwalletAPI_Res_GetUnspentOuts new__parsed_res__get_unspent_outs(
property_tree::ptree &res,
const secret_key &sec_viewKey,
const secret_key &sec_spendKey,
const public_key &pub_spendKey
);
LightwalletAPI_Res_GetRandomOuts new__parsed_res__get_random_outs(
property_tree::ptree &res
);
//
// - Routine entrypoint
struct Async_SendFunds_Args
{ // TODO: add a way to pass native structures if available
const string &from_address_string;
const string &sec_viewKey_string;
const string &sec_spendKey_string;
const string &pub_spendKey_string;
const string &to_address_string;
optional<string> payment_id_string;
uint64_t sending_amount;
bool is_sweeping;
uint32_t simple_priority;
const send__get_unspent_outs_fn_type &get_unspent_outs_fn;
const send__get_random_outs_fn_type &get_random_outs_fn;
const send__submit_raw_tx_fn_type &submit_raw_tx_fn;
const send__status_update_fn_type &status_update_fn;
const send__error_cb_fn_type &error_cb_fn;
const send__success_cb_fn_type &success_cb_fn;
//
optional<uint64_t> unlock_time; // default 0
optional<cryptonote::network_type> nettype;
};
void async__send_funds(const Async_SendFunds_Args &args);
}
#endif /* monero_send_routine_hpp */

@ -35,6 +35,7 @@
#include "wallet_errors.h"
#include "string_tools.h"
#include "monero_paymentID_utils.hpp"
#include "monero_key_image_utils.hpp"
//
using namespace std;
using namespace crypto;
@ -46,6 +47,7 @@ using namespace tools; // for error::
using namespace monero_transfer_utils;
using namespace monero_fork_rules;
using namespace monero_fee_utils;
using namespace monero_key_image_utils; // for API response parsing
//
// Transfer parsing/derived properties
bool monero_transfer_utils::is_transfer_unlocked(
@ -175,8 +177,6 @@ bool _verify_sec_key(const crypto::secret_key &secret_key, const crypto::public_
return r && public_key == calculated_pub;
}
//
//
//----------------------------------------------------------------------------------------------------
namespace
{
template<typename T>
@ -205,6 +205,7 @@ namespace
}
//
//
//
// Decomposed Send procedure
void monero_transfer_utils::send_step1__prepare_params_for_get_decoys(
Send_Step1_RetVals &retVals,
@ -377,18 +378,18 @@ void monero_transfer_utils::send_step1__prepare_params_for_get_decoys(
void monero_transfer_utils::send_step2__try_create_transaction(
Send_Step2_RetVals &retVals,
//
string from_address_string,
string sec_viewKey_string,
string sec_spendKey_string,
string to_address_string,
const string &from_address_string,
const string &sec_viewKey_string,
const string &sec_spendKey_string,
const string &to_address_string,
optional<string> payment_id_string,
uint64_t final_total_wo_fee,
uint64_t change_amount,
uint64_t fee_amount,
uint32_t simple_priority,
vector<SpendableOutput> &using_outs,
const vector<SpendableOutput> &using_outs,
uint64_t fee_per_b, // per v8
vector<RandomAmountOutputs> &mix_outs,
vector<RandomAmountOutputs> &mix_outs, // cannot be const due to convenience__create_transaction's mutability requirement
use_fork_rules_fn_type use_fork_rules_fn,
uint64_t unlock_time, // or 0
cryptonote::network_type nettype
@ -445,9 +446,9 @@ void monero_transfer_utils::create_transaction(
uint64_t sending_amount,
uint64_t change_amount,
uint64_t fee_amount,
vector<SpendableOutput> &outputs,
vector<RandomAmountOutputs> &mix_outs,
std::vector<uint8_t> &extra,
const vector<SpendableOutput> &outputs,
vector<RandomAmountOutputs> &mix_outs,
const std::vector<uint8_t> &extra,
use_fork_rules_fn_type use_fork_rules_fn,
uint64_t unlock_time, // or 0
bool rct,
@ -695,7 +696,7 @@ void monero_transfer_utils::convenience__create_transaction(
uint64_t sending_amount,
uint64_t change_amount,
uint64_t fee_amount,
vector<SpendableOutput> &outputs,
const vector<SpendableOutput> &outputs,
vector<RandomAmountOutputs> &mix_outs,
use_fork_rules_fn_type use_fork_rules_fn,
uint64_t unlock_time,

@ -133,7 +133,7 @@ namespace monero_transfer_utils
case resultFeeNotEqualToGiven:
return "Result fee not equal to given fee";
case needMoreMoneyThanFound:
return "Need more money than found";
return "Spendable balance too low";
case invalidDestinationAddress:
return "Invalid destination address";
case nonZeroPIDWithIntAddress:
@ -161,6 +161,9 @@ namespace monero_transfer_utils
}
}
//
// See monero_send_routine for actual app-lvl interface used by lightwallets
//
//
// Send_Step* functions procedure for integrators:
// 1. call GetUnspentOuts endpoint
// 2. call step1__prepare_params_for_get_decoys to get params for calling RandomOuts; call GetRandomOuts
@ -215,18 +218,18 @@ namespace monero_transfer_utils
void send_step2__try_create_transaction(
Send_Step2_RetVals &retVals,
//
string from_address_string,
string sec_viewKey_string,
string sec_spendKey_string,
string to_address_string,
const string &from_address_string,
const string &sec_viewKey_string,
const string &sec_spendKey_string,
const string &to_address_string,
optional<string> payment_id_string,
uint64_t final_total_wo_fee, // this gets passed to create_transaction's 'sending_amount'
uint64_t change_amount,
uint64_t fee_amount,
uint32_t simple_priority,
vector<SpendableOutput> &using_outs,
const vector<SpendableOutput> &using_outs,
uint64_t fee_per_b, // per v8
vector<RandomAmountOutputs> &mix_outs,
vector<RandomAmountOutputs> &mix_outs, // it gets sorted
use_fork_rules_fn_type use_fork_rules_fn,
uint64_t unlock_time, // or 0
cryptonote::network_type nettype
@ -256,8 +259,8 @@ namespace monero_transfer_utils
uint64_t sending_amount,
uint64_t change_amount,
uint64_t fee_amount,
vector<SpendableOutput> &outputs,
vector<RandomAmountOutputs> &mix_outs,
const vector<SpendableOutput> &outputs,
vector<RandomAmountOutputs> &mix_outs, // get sorted
use_fork_rules_fn_type use_fork_rules_fn,
uint64_t unlock_time = 0, // or 0
network_type nettype = MAINNET
@ -279,9 +282,9 @@ namespace monero_transfer_utils
uint64_t sending_amount,
uint64_t change_amount,
uint64_t fee_amount,
vector<SpendableOutput> &outputs,
const vector<SpendableOutput> &outputs,
vector<RandomAmountOutputs> &mix_outs,
std::vector<uint8_t> &extra, // this is not declared const b/c it may have the output tx pub key appended to it
const std::vector<uint8_t> &extra, // this is not declared const b/c it may have the output tx pub key appended to it
use_fork_rules_fn_type use_fork_rules_fn,
uint64_t unlock_time = 0, // or 0
bool rct = true,

@ -46,7 +46,8 @@
#include "string_tools.h"
#include "ringct/rctSigs.h"
//
//
#include "serial_bridge_utils.hpp"
using namespace std;
using namespace boost;
using namespace cryptonote;
@ -54,98 +55,7 @@ using namespace monero_transfer_utils;
using namespace monero_fork_rules;
//
using namespace serial_bridge;
//
network_type serial_bridge::nettype_from_string(const string &nettype_string)
{ // TODO: possibly move this to network_type declaration
if (nettype_string == "MAINNET") {
return MAINNET;
} else if (nettype_string == "TESTNET") {
return TESTNET;
} else if (nettype_string == "STAGENET") {
return STAGENET;
} else if (nettype_string == "FAKECHAIN") {
return FAKECHAIN;
} else if (nettype_string == "UNDEFINED") {
return UNDEFINED;
}
THROW_WALLET_EXCEPTION_IF(false, error::wallet_internal_error, "Unrecognized nettype_string")
return UNDEFINED;
}
string serial_bridge::string_from_nettype(network_type nettype)
{
switch (nettype) {
case MAINNET:
return "MAINNET";
case TESTNET:
return "TESTNET";
case STAGENET:
return "STAGENET";
case FAKECHAIN:
return "FAKECHAIN";
case UNDEFINED:
return "UNDEFINED";
default:
THROW_WALLET_EXCEPTION_IF(false, error::wallet_internal_error, "Unrecognized nettype for string conversion")
return "UNDEFINED";
}
}
struct RetVals_Transforms
{
static string str_from(uint64_t v)
{
std::ostringstream o;
o << v;
return o.str();
}
static string str_from(uint32_t v)
{
std::ostringstream o;
o << v;
return o.str();
}
};
//
// Shared - Parsing - Args
bool parsed_json_root(const string &args_string, boost::property_tree::ptree &json_root)
{
// cout << "args_string: " << args_string << endl;
std::stringstream ss;
ss << args_string;
try {
boost::property_tree::read_json(ss, json_root);
} catch (std::exception const& e) {
THROW_WALLET_EXCEPTION_IF(false, error::wallet_internal_error, "Invalid JSON");
return false;
}
return true;
}
//
// Shared - Factories - Return values
string ret_json_from_root(const boost::property_tree::ptree &root)
{
stringstream ret_ss;
boost::property_tree::write_json(ret_ss, root, false/*pretty*/);
//
return ret_ss.str();
}
string error_ret_json_from_message(string err_msg)
{
boost::property_tree::ptree root;
root.put(ret_json_key__any__err_msg(), err_msg);
//
return ret_json_from_root(root);
}
string error_ret_json_from_code(int code, optional<string> err_msg)
{
boost::property_tree::ptree root;
root.put(ret_json_key__any__err_code(), code);
if (err_msg != none) {
root.put(ret_json_key__any__err_msg(), *err_msg);
}
//
return ret_json_from_root(root);
}
using namespace serial_bridge_utils;
//
//
// Bridge Function Implementations
@ -455,10 +365,8 @@ string serial_bridge::generate_key_image(const string &args_string)
return ret_json_from_root(root);
}
//
//
// TODO: possibly take tx sec key as a arg so we don't have to worry about randomness there
string serial_bridge::send_step1__prepare_params_for_get_decoys(const string &args_string)
{
{ // TODO: possibly allow this fn to take tx sec key as an arg, although, random bit gen is now handled well by emscripten
boost::property_tree::ptree json_root;
if (!parsed_json_root(args_string, json_root)) {
// it will already have thrown an exception
@ -573,11 +481,6 @@ string serial_bridge::send_step2__try_create_transaction(const string &args_stri
}
mix_outs.push_back(amountAndOuts);
}
optional<string> optl__passedIn_attemptAt_fee_string = json_root.get_optional<string>("passedIn_attemptAt_fee");
optional<uint64_t> optl__passedIn_attemptAt_fee = none;
if (optl__passedIn_attemptAt_fee_string != none) {
optl__passedIn_attemptAt_fee = stoull(*optl__passedIn_attemptAt_fee_string);
}
Send_Step2_RetVals retVals;
monero_transfer_utils::send_step2__try_create_transaction(
retVals,

@ -34,7 +34,9 @@
#define serial_bridge_index_hpp
//
#include <string>
#include "cryptonote_config.h"
#include "cryptonote_config.h"
//
// See serial_bridge_utils.hpp
//
namespace serial_bridge
{
@ -67,52 +69,6 @@ namespace serial_bridge
string derive_public_key(const string &args_string);
string derive_subaddress_public_key(const string &args_string);
string decodeRct(const string &args_string);
//
// JSON values
network_type nettype_from_string(const string &nettype_string);
string string_from_nettype(network_type nettype);
//
// JSON keys - Ret vals
// - - Error
static inline string ret_json_key__any__err_msg() { return "err_msg"; } // optional
static inline string ret_json_key__any__err_code() { return "err_code"; } // optional
//
// - - Shared
static inline string ret_json_key__generic_retVal() { return "retVal"; }
// - - create_transaction / send
static inline string ret_json_key__send__spendable_balance() { return "spendable_balance"; }
static inline string ret_json_key__send__required_balance() { return "required_balance"; }
static inline string ret_json_key__send__mixin() { return "mixin"; }
static inline string ret_json_key__send__using_fee() { return "using_fee"; }
static inline string ret_json_key__send__final_total_wo_fee() { return "final_total_wo_fee"; }
static inline string ret_json_key__send__change_amount() { return "change_amount"; }
static inline string ret_json_key__send__using_outs() { return "using_outs"; } // this list's members' keys should probably be declared (is this the best way to do this?)
//
static inline string ret_json_key__send__tx_must_be_reconstructed() { return "tx_must_be_reconstructed"; }
static inline string ret_json_key__send__fee_actually_needed() { return "fee_actually_needed"; }
static inline string ret_json_key__send__serialized_signed_tx() { return "serialized_signed_tx"; }
static inline string ret_json_key__send__tx_hash() { return "tx_hash"; }
static inline string ret_json_key__send__tx_key() { return "tx_key"; }
static inline string ret_json_key__send__tx_pub_key() { return "tx_pub_key"; }
//
// - - decode_address, etc
static inline string ret_json_key__paymentID_string() { return "paymentID_string"; } // optional
static inline string ret_json_key__isSubaddress() { return "isSubaddress"; }
static inline string ret_json_key__mnemonic_string() { return "mnemonic_string"; }
static inline string ret_json_key__mnemonic_language() { return "mnemonic_language"; }
static inline string ret_json_key__sec_seed_string() { return "sec_seed_string"; }
static inline string ret_json_key__address_string() { return "address_string"; }
static inline string ret_json_key__pub_viewKey_string() { return "pub_viewKey_string"; }
static inline string ret_json_key__pub_spendKey_string() { return "pub_spendKey_string"; }
static inline string ret_json_key__sec_viewKey_string() { return "sec_viewKey_string"; }
static inline string ret_json_key__sec_spendKey_string() { return "sec_spendKey_string"; }
static inline string ret_json_key__isValid() { return "isValid"; }
static inline string ret_json_key__isInViewOnlyMode() { return "isInViewOnlyMode"; }
static inline string ret_json_key__decodeRct_mask() { return "mask"; }
static inline string ret_json_key__decodeRct_amount() { return "amount"; }
// JSON keys - Args
// TODO: (is there a better way of doing this?) structs with auto parse & serialization?
// static inline string args_json_key__
}
#endif /* serial_bridge_index_hpp */

@ -0,0 +1,124 @@
//
// serial_bridge_utils.cpp
// Copyright (c) 2014-2018, MyMonero.com
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
//
#include "serial_bridge_utils.hpp"
//
#include <boost/foreach.hpp>
//
#include "wallet_errors.h"
using namespace tools;
#include "string_tools.h"
//
//
using namespace std;
using namespace boost;
using namespace cryptonote;
//
using namespace serial_bridge_utils;
//
// TODO: factor these into a monero_bridge_utils and share with serial_bridge_utils (incl keys declarations there)
network_type serial_bridge_utils::nettype_from_string(const string &nettype_string)
{ // TODO: possibly move this to network_type declaration
if (nettype_string == "MAINNET") {
return MAINNET;
} else if (nettype_string == "TESTNET") {
return TESTNET;
} else if (nettype_string == "STAGENET") {
return STAGENET;
} else if (nettype_string == "FAKECHAIN") {
return FAKECHAIN;
} else if (nettype_string == "UNDEFINED") {
return UNDEFINED;
}
THROW_WALLET_EXCEPTION_IF(false, error::wallet_internal_error, "Unrecognized nettype_string")
return UNDEFINED;
}
string serial_bridge_utils::string_from_nettype(network_type nettype)
{
switch (nettype) {
case MAINNET:
return "MAINNET";
case TESTNET:
return "TESTNET";
case STAGENET:
return "STAGENET";
case FAKECHAIN:
return "FAKECHAIN";
case UNDEFINED:
return "UNDEFINED";
default:
THROW_WALLET_EXCEPTION_IF(false, error::wallet_internal_error, "Unrecognized nettype for string conversion")
return "UNDEFINED";
}
}
//
// Shared - Parsing - Args
bool serial_bridge_utils::parsed_json_root(const string &args_string, boost::property_tree::ptree &json_root)
{
// cout << "args_string: " << args_string << endl;
std::stringstream ss;
ss << args_string;
try {
boost::property_tree::read_json(ss, json_root);
} catch (std::exception const& e) {
THROW_WALLET_EXCEPTION_IF(false, error::wallet_internal_error, "Invalid JSON");
return false;
}
return true;
}
//
// Shared - Factories - Return values
string serial_bridge_utils::ret_json_from_root(const boost::property_tree::ptree &root)
{
stringstream ret_ss;
boost::property_tree::write_json(ret_ss, root, false/*pretty*/);
//
return ret_ss.str();
}
string serial_bridge_utils::error_ret_json_from_message(const string &err_msg)
{
boost::property_tree::ptree root;
root.put(ret_json_key__any__err_msg(), err_msg);
//
return ret_json_from_root(root);
}
string serial_bridge_utils::error_ret_json_from_code(int code, optional<string> err_msg)
{
boost::property_tree::ptree root;
root.put(ret_json_key__any__err_code(), code);
if (err_msg != none) {
root.put(ret_json_key__any__err_msg(), *err_msg);
}
//
return ret_json_from_root(root);
}

@ -0,0 +1,122 @@
//
// serial_bridge_utils.hpp
// Copyright (c) 2014-2018, MyMonero.com
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
#ifndef serial_bridge_utils_hpp
#define serial_bridge_utils_hpp
//
#include <string>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
//
#include "cryptonote_config.h"
//
namespace serial_bridge_utils
{
using namespace std;
using namespace boost;
using namespace cryptonote;
//
// JSON convenience fns
bool parsed_json_root(const string &args_string, boost::property_tree::ptree &json_root);
//
// JSON values
network_type nettype_from_string(const string &nettype_string);
string string_from_nettype(network_type nettype);
//
struct RetVals_Transforms
{
static string str_from(uint64_t v)
{
std::ostringstream o;
o << v;
return o.str();
}
static string str_from(uint32_t v)
{
std::ostringstream o;
o << v;
return o.str();
}
};
string ret_json_from_root(const boost::property_tree::ptree &root);
string error_ret_json_from_message(const string &err_msg);
string error_ret_json_from_code(int code, optional<string> err_msg);
//
// JSON keys - Ret vals
// - - Error
static inline string ret_json_key__any__err_msg() { return "err_msg"; } // optional
static inline string ret_json_key__any__err_code() { return "err_code"; } // optional
//
// - - Shared
static inline string ret_json_key__generic_retVal() { return "retVal"; }
// - - create_transaction / send
static inline string ret_json_key__send__spendable_balance() { return "spendable_balance"; }
static inline string ret_json_key__send__required_balance() { return "required_balance"; }
static inline string ret_json_key__send__mixin() { return "mixin"; }
static inline string ret_json_key__send__using_fee() { return "using_fee"; }
static inline string ret_json_key__send__final_total_wo_fee() { return "final_total_wo_fee"; }
static inline string ret_json_key__send__change_amount() { return "change_amount"; }
static inline string ret_json_key__send__using_outs() { return "using_outs"; } // this list's members' keys should probably be declared (is this the best way to do this?)
//
static inline string ret_json_key__send__tx_must_be_reconstructed() { return "tx_must_be_reconstructed"; }
static inline string ret_json_key__send__fee_actually_needed() { return "fee_actually_needed"; }
//
static inline string ret_json_key__send__serialized_signed_tx() { return "serialized_signed_tx"; }
static inline string ret_json_key__send__tx_hash() { return "tx_hash"; }
static inline string ret_json_key__send__tx_key() { return "tx_key"; }
static inline string ret_json_key__send__tx_pub_key() { return "tx_pub_key"; }
//
static inline string ret_json_key__send__used_fee() { return "used_fee"; }
static inline string ret_json_key__send__total_sent() { return "total_sent"; }
static inline string ret_json_key__send__final_payment_id() { return "final_payment_id"; }
//
// - - decode_address, etc
static inline string ret_json_key__paymentID_string() { return "paymentID_string"; } // optional
static inline string ret_json_key__isSubaddress() { return "isSubaddress"; }
static inline string ret_json_key__mnemonic_string() { return "mnemonic_string"; }
static inline string ret_json_key__mnemonic_language() { return "mnemonic_language"; }
static inline string ret_json_key__sec_seed_string() { return "sec_seed_string"; }
static inline string ret_json_key__address_string() { return "address_string"; }
static inline string ret_json_key__pub_viewKey_string() { return "pub_viewKey_string"; }
static inline string ret_json_key__pub_spendKey_string() { return "pub_spendKey_string"; }
static inline string ret_json_key__sec_viewKey_string() { return "sec_viewKey_string"; }
static inline string ret_json_key__sec_spendKey_string() { return "sec_spendKey_string"; }
static inline string ret_json_key__isValid() { return "isValid"; }
static inline string ret_json_key__isInViewOnlyMode() { return "isInViewOnlyMode"; }
static inline string ret_json_key__decodeRct_mask() { return "mask"; }
static inline string ret_json_key__decodeRct_amount() { return "amount"; }
// JSON keys - Args
// TODO: (is there a better way of doing this?) structs with auto parse & serialization?
// static inline string args_json_key__
}
#endif /* serial_bridge_utils_hpp */

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save