mirror of
https://github.com/wownero/wownero-cpp.git
synced 2026-10-20 16:48:40 +02:00
support subtracting fee from destinations
This commit is contained in:
@@ -619,9 +619,9 @@ namespace monero {
|
||||
return amount;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
template<typename Ts, typename Tu, typename Tk>
|
||||
template<typename Ts, typename Tu, typename Tk, typename Ta>
|
||||
bool fill_response(wallet2* m_w2, std::vector<tools::wallet2::pending_tx> &ptx_vector,
|
||||
bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, Tu &weight, std::string &multisig_txset, std::string &unsigned_txset, bool do_not_relay,
|
||||
bool get_tx_key, Ts& tx_key, Tu &amount, Ta &amounts_by_dest, Tu &fee, Tu &weight, std::string &multisig_txset, std::string &unsigned_txset, bool do_not_relay,
|
||||
Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata, Tk &spent_key_images, epee::json_rpc::error &er)
|
||||
{
|
||||
for (const auto & ptx : ptx_vector)
|
||||
@@ -638,6 +638,12 @@ namespace monero {
|
||||
fill(fee, ptx.fee);
|
||||
fill(weight, cryptonote::get_transaction_weight(ptx.tx));
|
||||
|
||||
// add amounts by destination
|
||||
tools::wallet_rpc::amounts_list abd;
|
||||
for (const auto& dst : ptx.dests)
|
||||
abd.amounts.push_back(dst.amount);
|
||||
fill(amounts_by_dest, abd);
|
||||
|
||||
// add spent key images
|
||||
key_image_list key_image_list;
|
||||
bool all_are_txin_to_key = std::all_of(ptx.tx.vin.begin(), ptx.tx.vin.end(), [&](const cryptonote::txin_v& s_e) -> bool
|
||||
@@ -1569,13 +1575,13 @@ namespace monero {
|
||||
if (!m_is_connected) throw std::runtime_error("Wallet is not connected to daemon");
|
||||
|
||||
// convert string ids to crypto hashes
|
||||
std::vector<crypto::hash> tx_hashes;
|
||||
std::unordered_set<crypto::hash> tx_hashes;
|
||||
std::vector<std::string>::const_iterator i = tx_ids.begin();
|
||||
while (i != tx_ids.end()) {
|
||||
cryptonote::blobdata tx_hash_blob;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(*i++, tx_hash_blob) || tx_hash_blob.size() != sizeof(crypto::hash)) throw std::runtime_error("TX ID has invalid format");
|
||||
crypto::hash tx_hash = *reinterpret_cast<const crypto::hash*>(tx_hash_blob.data());
|
||||
tx_hashes.push_back(tx_hash);
|
||||
tx_hashes.insert(tx_hash);
|
||||
}
|
||||
|
||||
// scan txs
|
||||
@@ -1984,14 +1990,21 @@ namespace monero {
|
||||
uint32_t account_index = config.m_account_index.get();
|
||||
std::set<uint32_t> subaddress_indices;
|
||||
for (const uint32_t& subaddress_idx : config.m_subaddress_indices) subaddress_indices.insert(subaddress_idx);
|
||||
std::set<uint32_t> subtract_fee_from;
|
||||
for (const uint32_t& subtract_fee_from_idx : config.m_subtract_fee_from) subtract_fee_from.insert(subtract_fee_from_idx);
|
||||
|
||||
// prepare transactions
|
||||
std::vector<wallet2::pending_tx> ptx_vector = m_w2->create_transactions_2(dsts, mixin, unlock_height, priority, extra, account_index, subaddress_indices);
|
||||
std::vector<wallet2::pending_tx> ptx_vector = m_w2->create_transactions_2(dsts, mixin, unlock_height, priority, extra, account_index, subaddress_indices, subtract_fee_from);
|
||||
if (ptx_vector.empty()) throw std::runtime_error("No transaction created");
|
||||
|
||||
// check if request cannot be fulfilled due to splitting
|
||||
if (config.m_can_split != boost::none && config.m_can_split.get() == false && ptx_vector.size() != 1) {
|
||||
throw std::runtime_error("Transaction would be too large. Try create_txs()");
|
||||
if (ptx_vector.size() > 1) {
|
||||
if (config.m_can_split != boost::none && !config.m_can_split.get()) {
|
||||
throw std::runtime_error("Transaction would be too large. Try create_txs()");
|
||||
}
|
||||
if (subtract_fee_from.size() > 0 && config.m_can_split != boost::none && config.m_can_split.get()) {
|
||||
throw std::runtime_error("subtractfeefrom transfers cannot be split over multiple transactions yet");
|
||||
}
|
||||
}
|
||||
|
||||
// config for fill_response()
|
||||
@@ -2004,6 +2017,7 @@ namespace monero {
|
||||
// commit txs (if relaying) and get response using wallet rpc's fill_response()
|
||||
std::list<std::string> tx_keys;
|
||||
std::list<uint64_t> tx_amounts;
|
||||
std::list<tools::wallet_rpc::amounts_list> tx_amounts_by_dest;
|
||||
std::list<uint64_t> tx_fees;
|
||||
std::list<uint64_t> tx_weights;
|
||||
std::string multisig_tx_hex;
|
||||
@@ -2012,7 +2026,7 @@ namespace monero {
|
||||
std::list<std::string> tx_blobs;
|
||||
std::list<std::string> tx_metadatas;
|
||||
std::list<key_image_list> input_key_images_list;
|
||||
if (!fill_response(m_w2.get(), ptx_vector, get_tx_keys, tx_keys, tx_amounts, tx_fees, tx_weights, multisig_tx_hex, unsigned_tx_hex, !relay, tx_hashes, get_tx_hex, tx_blobs, get_tx_metadata, tx_metadatas, input_key_images_list, err)) {
|
||||
if (!fill_response(m_w2.get(), ptx_vector, get_tx_keys, tx_keys, tx_amounts, tx_amounts_by_dest, tx_fees, tx_weights, multisig_tx_hex, unsigned_tx_hex, !relay, tx_hashes, get_tx_hex, tx_blobs, get_tx_metadata, tx_metadatas, input_key_images_list, err)) {
|
||||
throw std::runtime_error("need to handle error filling response!"); // TODO
|
||||
}
|
||||
|
||||
@@ -2021,11 +2035,14 @@ namespace monero {
|
||||
auto tx_hashes_iter = tx_hashes.begin();
|
||||
auto tx_keys_iter = tx_keys.begin();
|
||||
auto tx_amounts_iter = tx_amounts.begin();
|
||||
auto tx_amounts_by_dest_iter = tx_amounts_by_dest.begin();
|
||||
auto tx_fees_iter = tx_fees.begin();
|
||||
auto tx_weights_iter = tx_weights.begin();
|
||||
auto tx_blobs_iter = tx_blobs.begin();
|
||||
auto tx_metadatas_iter = tx_metadatas.begin();
|
||||
auto input_key_images_list_iter = input_key_images_list.begin();
|
||||
std::vector<std::shared_ptr<monero_destination>> destinations = config.get_normalized_destinations();
|
||||
auto destinations_iter = destinations.begin();
|
||||
while (tx_fees_iter != tx_fees.end()) {
|
||||
|
||||
// init tx with outgoing transfer from filled values
|
||||
@@ -2051,6 +2068,15 @@ namespace monero {
|
||||
input->m_key_image.get()->m_hex = input_key_image;
|
||||
}
|
||||
|
||||
// init destinations
|
||||
for (const uint64_t tx_amount_by_dest : (*tx_amounts_by_dest_iter).amounts) {
|
||||
std::shared_ptr<monero_destination> destination = std::make_shared<monero_destination>();
|
||||
destination->m_address = (*destinations_iter)->m_address;
|
||||
destination->m_amount = tx_amount_by_dest;
|
||||
tx->m_outgoing_transfer.get()->m_destinations.push_back(destination);
|
||||
destinations_iter++;
|
||||
}
|
||||
|
||||
// init other known fields
|
||||
tx->m_is_outgoing = true;
|
||||
tx->m_payment_id = config.m_payment_id;
|
||||
@@ -2072,6 +2098,7 @@ namespace monero {
|
||||
// iterate to next element
|
||||
tx_keys_iter++;
|
||||
tx_amounts_iter++;
|
||||
tx_amounts_by_dest_iter++;
|
||||
tx_fees_iter++;
|
||||
tx_hashes_iter++;
|
||||
tx_blobs_iter++;
|
||||
@@ -2079,9 +2106,6 @@ namespace monero {
|
||||
input_key_images_list_iter++;
|
||||
}
|
||||
|
||||
// copy destinations if single tx
|
||||
if (txs.size() == 1) txs[0]->m_outgoing_transfer.get()->m_destinations = config.get_normalized_destinations();
|
||||
|
||||
// build tx set
|
||||
std::shared_ptr<monero_tx_set> tx_set = std::make_shared<monero_tx_set>();
|
||||
tx_set->m_txs = txs;
|
||||
@@ -2170,6 +2194,7 @@ namespace monero {
|
||||
if (destinations[0]->m_amount != boost::none) throw std::runtime_error("Cannot specify destination amount to sweep");
|
||||
if (config.m_key_image != boost::none) throw std::runtime_error("Cannot define key image in sweep_account(); use sweep_output() to sweep an output by its key image");
|
||||
if (config.m_sweep_each_subaddress != boost::none && config.m_sweep_each_subaddress.get() == true) throw std::runtime_error("Cannot sweep each subaddress individually with sweep_account");
|
||||
if (config.m_subtract_fee_from.size() > 0) throw std::runtime_error("Sweep transfers do not support subtracting fees from destinations");
|
||||
|
||||
// validate the transfer requested and populate dsts & extra
|
||||
std::list<wallet_rpc::transfer_destination> destination;
|
||||
@@ -2208,6 +2233,7 @@ namespace monero {
|
||||
// commit txs (if relaying) and get response using wallet rpc's fill_response()
|
||||
std::list<std::string> tx_keys;
|
||||
std::list<uint64_t> tx_amounts;
|
||||
std::list<tools::wallet_rpc::amounts_list> tx_amounts_by_dest;
|
||||
std::list<uint64_t> tx_fees;
|
||||
std::list<uint64_t> tx_weights;
|
||||
std::string multisig_tx_hex;
|
||||
@@ -2216,7 +2242,7 @@ namespace monero {
|
||||
std::list<std::string> tx_blobs;
|
||||
std::list<std::string> tx_metadatas;
|
||||
std::list<key_image_list> input_key_images_list;
|
||||
if (!fill_response(m_w2.get(), ptx_vector, get_tx_keys, tx_keys, tx_amounts, tx_fees, tx_weights, multisig_tx_hex, unsigned_tx_hex, !relay, tx_hashes, get_tx_hex, tx_blobs, get_tx_metadata, tx_metadatas, input_key_images_list, err)) {
|
||||
if (!fill_response(m_w2.get(), ptx_vector, get_tx_keys, tx_keys, tx_amounts, tx_amounts_by_dest, tx_fees, tx_weights, multisig_tx_hex, unsigned_tx_hex, !relay, tx_hashes, get_tx_hex, tx_blobs, get_tx_metadata, tx_metadatas, input_key_images_list, err)) {
|
||||
throw std::runtime_error("need to handle error filling response!"); // TODO
|
||||
}
|
||||
|
||||
@@ -2302,6 +2328,7 @@ namespace monero {
|
||||
std::vector<std::shared_ptr<monero_destination>> destinations = config.get_normalized_destinations();
|
||||
if (config.m_key_image == boost::none || config.m_key_image.get().empty()) throw std::runtime_error("Must provide key image of output to sweep");
|
||||
if (destinations.size() != 1 || destinations[0]->m_address == boost::none || destinations[0]->m_address.get().empty()) throw std::runtime_error("Must provide exactly one destination address to sweep output to");
|
||||
if (config.m_subtract_fee_from.size() > 0) throw std::runtime_error("Sweeping output does not support subtracting fees from destinations");
|
||||
|
||||
// validate the transfer queried and populate dsts & extra
|
||||
std::string m_payment_id = config.m_payment_id == boost::none ? std::string("") : config.m_payment_id.get();
|
||||
@@ -2344,6 +2371,7 @@ namespace monero {
|
||||
// commit txs (if relaying) and get response using wallet rpc's fill_response()
|
||||
std::list<std::string> tx_keys;
|
||||
std::list<uint64_t> tx_amounts;
|
||||
std::list<tools::wallet_rpc::amounts_list> tx_amounts_by_dest;
|
||||
std::list<uint64_t> tx_fees;
|
||||
std::list<uint64_t> tx_weights;
|
||||
std::string multisig_tx_hex;
|
||||
@@ -2352,7 +2380,7 @@ namespace monero {
|
||||
std::list<std::string> tx_blobs;
|
||||
std::list<std::string> tx_metadatas;
|
||||
std::list<key_image_list> input_key_images_list;
|
||||
if (!fill_response(m_w2.get(), ptx_vector, get_tx_keys, tx_keys, tx_amounts, tx_fees, tx_weights, multisig_tx_hex, unsigned_tx_hex, !relay, tx_hashes, get_tx_hex, tx_blobs, get_tx_metadata, tx_metadatas, input_key_images_list, err)) {
|
||||
if (!fill_response(m_w2.get(), ptx_vector, get_tx_keys, tx_keys, tx_amounts, tx_amounts_by_dest, tx_fees, tx_weights, multisig_tx_hex, unsigned_tx_hex, !relay, tx_hashes, get_tx_hex, tx_blobs, get_tx_metadata, tx_metadatas, input_key_images_list, err)) {
|
||||
throw std::runtime_error("need to handle error filling response!"); // TODO: return err message
|
||||
}
|
||||
|
||||
@@ -2450,6 +2478,7 @@ namespace monero {
|
||||
// commit txs (if relaying) and get response using wallet rpc's fill_response()
|
||||
std::list<std::string> tx_keys;
|
||||
std::list<uint64_t> tx_amounts;
|
||||
std::list<tools::wallet_rpc::amounts_list> tx_amounts_by_dest;
|
||||
std::list<uint64_t> tx_fees;
|
||||
std::list<uint64_t> tx_weights;
|
||||
std::string multisig_tx_hex;
|
||||
@@ -2459,7 +2488,7 @@ namespace monero {
|
||||
std::list<std::string> tx_metadatas;
|
||||
std::list<key_image_list> input_key_images_list;
|
||||
epee::json_rpc::error er;
|
||||
if (!fill_response(m_w2.get(), ptx_vector, get_tx_keys, tx_keys, tx_amounts, tx_fees, tx_weights, multisig_tx_hex, unsigned_tx_hex, !relay, tx_hashes, get_tx_hex, tx_blobs, get_tx_metadata, tx_metadatas, input_key_images_list, er)) {
|
||||
if (!fill_response(m_w2.get(), ptx_vector, get_tx_keys, tx_keys, tx_amounts, tx_amounts_by_dest, tx_fees, tx_weights, multisig_tx_hex, unsigned_tx_hex, !relay, tx_hashes, get_tx_hex, tx_blobs, get_tx_metadata, tx_metadatas, input_key_images_list, er)) {
|
||||
throw std::runtime_error("need to handle error filling response!"); // TODO: return err message
|
||||
}
|
||||
|
||||
|
||||
@@ -1280,6 +1280,7 @@ namespace monero {
|
||||
m_destinations.push_back(destination->copy(destination, std::make_shared<monero_destination>()));
|
||||
}
|
||||
}
|
||||
m_subtract_fee_from = config.m_subtract_fee_from;
|
||||
m_payment_id = config.m_payment_id;
|
||||
m_priority = config.m_priority;
|
||||
m_ring_size = config.m_ring_size;
|
||||
@@ -1328,6 +1329,7 @@ namespace monero {
|
||||
// set sub-arrays
|
||||
if (!m_destinations.empty()) root.AddMember("destinations", monero_utils::to_rapidjson_val(allocator, m_destinations), allocator);
|
||||
if (!m_subaddress_indices.empty()) root.AddMember("subaddressIndices", monero_utils::to_rapidjson_val(allocator, m_subaddress_indices), allocator);
|
||||
if (!m_subtract_fee_from.empty()) root.AddMember("subtractFeeFrom", monero_utils::to_rapidjson_val(allocator, m_subtract_fee_from), allocator);
|
||||
|
||||
// return root
|
||||
return root;
|
||||
@@ -1352,6 +1354,7 @@ namespace monero {
|
||||
config->m_destinations.push_back(destination);
|
||||
}
|
||||
}
|
||||
else if (key == std::string("subtractFeeFrom")) for (boost::property_tree::ptree::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) config->m_subtract_fee_from.push_back(it2->second.get_value<uint32_t>());
|
||||
else if (key == std::string("paymentId")) config->m_payment_id = it->second.data();
|
||||
else if (key == std::string("priority")) {
|
||||
uint32_t priority_num = it->second.get_value<uint32_t>();
|
||||
|
||||
@@ -375,6 +375,7 @@ namespace monero {
|
||||
boost::optional<std::string> m_address;
|
||||
boost::optional<uint64_t> m_amount;
|
||||
std::vector<std::shared_ptr<monero_destination>> m_destinations;
|
||||
std::vector<uint32_t> m_subtract_fee_from;
|
||||
boost::optional<std::string> m_payment_id;
|
||||
boost::optional<monero_tx_priority> m_priority;
|
||||
boost::optional<uint32_t> m_ring_size;
|
||||
|
||||
Reference in New Issue
Block a user