diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index cf42785b8..6df1ee286 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -8105,9 +8105,8 @@ bool simple_wallet::return_payment(const std::vector &args_) } } - // We found the one we were looking for - take a copy of the key_image, etc. + // We found the one(s) we were looking for - take a copy of the key_image, etc. transfers_indices.push_back(idx); - break; } // Check we have a valid key_image @@ -8132,21 +8131,32 @@ bool simple_wallet::return_payment(const std::vector &args_) fail_msg_writer() << tr("Multiple transactions are created, which is not supposed to happen"); return true; } - if (ptx_vector[0].selected_transfers.size() != 1) + if (ptx_vector[0].selected_transfers.size() != transfers_indices.size()) { - fail_msg_writer() << tr("The transaction uses multiple or no inputs, which is not supposed to happen"); + fail_msg_writer() << tr("The transaction uses incorrect number of inputs, which is not supposed to happen"); return true; } // give user total and fee, and prompt to confirm uint64_t total_fee = ptx_vector[0].fee; - uint64_t total_sent = m_wallet->get_transfer_details(ptx_vector[0].selected_transfers.front()).amount(); + uint64_t total_sent = 0; + std::string asset_type; + for (auto idx: ptx_vector[0].selected_transfers) { + const tools::wallet2::transfer_details &td = m_wallet->get_transfer_details(idx); + uint64_t sent = td.amount(); + if (total_sent + sent < total_sent) { + fail_msg_writer() << tr("amount overflow detected"); + return true; + } + total_sent += sent; + asset_type = td.asset_type; + } std::ostringstream prompt; if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members())) return true; - prompt << boost::format(tr("Returning %s for a total fee of %s. Is this okay?")) % - print_money(total_sent) % - print_money(total_fee); + prompt << boost::format(tr("Returning %s %s for a total fee of %s %s. Is this okay?")) % + print_money(total_sent) % asset_type % + print_money(total_fee) % asset_type; std::string accepted = input_line(prompt.str(), true); if (std::cin.eof()) return true; @@ -8488,7 +8498,7 @@ bool simple_wallet::yield_info(const std::vector &args) { // EXPERIMENTAL - change to get_yield_summary_info() method uint64_t t_burnt, t_supply, t_locked, t_yield, yps, ybi_size; - std::vector> yield_payouts; + std::vector> yield_payouts; if (!m_wallet->get_yield_summary_info(t_burnt, t_supply, t_locked, t_yield, yps, ybi_size, yield_payouts)) { fail_msg_writer() << "failed to get yield info. Make sure you are connected to a daemon."; return false; @@ -8501,25 +8511,30 @@ bool simple_wallet::yield_info(const std::vector &args) { message_writer(console_color_default, false) << boost::format(tr("\nSTAKED FUNDS:")); for (auto &p: yield_payouts) { uint64_t height, burnt, yield; - std::string txid; - std::tie(height, txid, burnt, yield) = p; + std::string txid, asset_type; + std::tie(height, txid, asset_type, burnt, yield) = p; + epee::console_colors asset_type_color = (asset_type == "SAL") ? console_color_green : (asset_type == "SAL1") ? console_color_blue : console_color_green; if (blockchain_height > ybi_size + height) - message_writer(console_color_green, true) << boost::format(tr("Height %d, txid %s, staked %s SAL, earned %s SAL")) + message_writer(asset_type_color, true) << boost::format(tr("Height %d, txid %s, staked %s %s, earned %s %s")) % height % txid % print_money(burnt) - % print_money(yield); + % asset_type + % print_money(yield) + % asset_type; else - message_writer(console_color_green, false) << boost::format(tr("Height %d (matures %d), txid %s, staked %s SAL, %s SAL accrued so far")) + message_writer(asset_type_color, false) << boost::format(tr("Height %d (matures %d), txid %s, staked %s %s, %s %s accrued so far")) % height % (height + stake_lock_period) % txid % print_money(burnt) - % print_money(yield); - } + % asset_type + % print_money(yield) + % asset_type; + } // Output the necessary information about yield stats - message_writer(console_color_default, false) << boost::format(tr("\nYIELD INFO:\n\tSupply coins burnt over last %s: %d\n\tTotal coins locked: %d\n\tYield accrued over last %s: %d\n\tYield per SAL staked: %d")) + message_writer(console_color_default, false) << boost::format(tr("\nYIELD INFO:\n\tSupply coins burnt over last %s: %d\n\tTotal coins locked: %d\n\tYield accrued over last %s: %d\n\tYield per coin staked: %d")) % get_human_readable_timespan((ybi_size-1) * DIFFICULTY_TARGET_V2) % print_money(t_burnt) % print_money(t_locked) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 486019a2b..5d99fab3e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2402,7 +2402,7 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt, uint64_t &total_yield, uint64_t &yield_per_stake, uint64_t &ybi_data_size, - std::vector> &payouts + std::vector> &payouts ) { // Get the total circulating supply of SALs @@ -2430,17 +2430,17 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt, // Iterate over the transfers in our wallet std::map map_payouts; - std::map>> payouts_active; + std::map> payouts_active; if (m_transfers.size() > 0) { for (size_t idx = m_transfers.size()-1; idx>0; --idx) { const tools::wallet2::transfer_details& td = m_transfers[idx]; //if (td.m_block_height < ybi_data[0].block_height) break; if (td.m_tx.type == cryptonote::transaction_type::STAKE) { if (map_payouts.count(idx)) { - payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, m_transfers[map_payouts[idx]].m_amount - td.m_tx.amount_burnt)); + payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.asset_type, td.m_tx.amount_burnt, m_transfers[map_payouts[idx]].m_amount - td.m_tx.amount_burnt)); } else { //payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, 0)); - payouts_active[epee::string_tools::pod_to_hex(td.m_txid)] = std::make_pair(td.m_block_height, std::make_pair(td.m_tx.amount_burnt, 0)); + payouts_active[epee::string_tools::pod_to_hex(td.m_txid)] = std::make_tuple(td.m_block_height, td.asset_type, td.m_tx.amount_burnt, 0); } } else if (td.m_tx.type == cryptonote::transaction_type::PROTOCOL) { // Store list of reverse-lookup indices to tell YIELD TXs how much they earned @@ -2462,18 +2462,21 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt, // EXPERIMENTAL - add up yield earned for active STAKE TXs for (auto &payout: payouts_active) { - if (ybi_data[idx].block_height < payout.second.first) continue; + + auto&[height,asset_type,total_burnt,total_accrued] = payout.second; + if (ybi_data[idx].block_height < height) continue; boost::multiprecision::uint128_t amount_128 = ybi_data[idx].slippage_total_this_block; - amount_128 *= payout.second.second.first; + amount_128 *= total_burnt; amount_128 /= ybi_data[idx].locked_coins_tally; - payout.second.second.second += amount_128.convert_to(); + total_accrued += amount_128.convert_to(); } } } for (auto &payout: payouts_active) { // Copy to the list of payouts proper - payouts.push_back(std::make_tuple(payout.second.first, payout.first, payout.second.second.first, payout.second.second.second)); + auto&[height,asset_type,total_burnt,total_accrued] = payout.second; + payouts.push_back(std::make_tuple(height, payout.first, asset_type, total_burnt, total_accrued)); } // Get the total currently locked @@ -2905,7 +2908,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote // Additionally, with STAKE and AUDIT TXs, we need to update our "balance staked" subtotal, because otherwise our balance is out by the staked coins until they mature! // SRCG: must remember to deduct the number of staked coins when they mature!! LOG_PRINT_L1("***** STAKED/AUDITED COINS : " << tx.amount_burnt << " *****"); - m_locked_coins.insert({P_change, {0, tx.amount_burnt}}); + m_locked_coins.insert({P_change, {0, tx.amount_burnt, tx.source_asset_type}}); } } else if (tx.type == cryptonote::transaction_type::TRANSFER) { @@ -7026,10 +7029,12 @@ uint64_t wallet2::balance(uint32_t index_major, const std::string& asset_type, b uint64_t amount = 0; for (const auto& i : balance_per_subaddress(index_major, asset_type, strict)) amount += i.second; - if (index_major == 0 && asset_type == "SAL") { - // Iterate over the locked coins, adding them to the _locked_ balance - for (const auto& i : m_locked_coins) + + // Iterate over the locked coins, adding them to the _locked_ balance + for (const auto& i : m_locked_coins) { + if (index_major == 0 && asset_type == i.second.m_asset_type) { amount += i.second.m_amount; + } } return amount; } @@ -11505,7 +11510,7 @@ std::vector wallet2::create_transactions_single(const crypt std::vector wallet2::create_transactions_return(std::vector transfers_indices) { // Get the asset_type and associated information - THROW_WALLET_EXCEPTION_IF(transfers_indices.empty() || transfers_indices.size()>1, error::wallet_internal_error, tr("Incorrect number of transfers_indices on return_payment")); + THROW_WALLET_EXCEPTION_IF(transfers_indices.empty() || transfers_indices.size()>15, error::wallet_internal_error, tr("Incorrect number of transfers_indices on return_payment")); size_t idx = transfers_indices[0]; THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, tr("cannot locate return_payment origin index in m_transfers")); const transfer_details& td_origin = get_transfer_details(idx); @@ -11518,6 +11523,14 @@ std::vector wallet2::create_transactions_return(std::vector uint32_t priority = adjust_priority(0); std::vector extra; // No need for a TX extra beyond that which will be calculated herein + // Verify that all the indices share an origin + for (const auto &td_idx : transfers_indices) { + THROW_WALLET_EXCEPTION_IF(td_idx >= get_num_transfer_details(), error::wallet_internal_error, tr("cannot locate return_payment origin index in m_transfers")); + const transfer_details &td = get_transfer_details(td_idx); + THROW_WALLET_EXCEPTION_IF(td.m_txid != td_origin.m_txid, error::wallet_internal_error, tr("TX hashes do not match for inputs to return_payment")); + THROW_WALLET_EXCEPTION_IF(td.asset_type != td_origin.asset_type, error::wallet_internal_error, tr("TX asset_type values do not match for inputs to return_payment")); + } + // To return a payment, we need to know the y value to process the F value // ...but the y value is calculated differently depending on the original TX ec_scalar y; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 1273d03dc..73905b77d 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -486,11 +486,13 @@ private: { uint32_t m_index_major; uint64_t m_amount; + std::string m_asset_type; BEGIN_SERIALIZE_OBJECT() VERSION_FIELD(0) VARINT_FIELD(m_index_major) VARINT_FIELD(m_amount) + FIELD(m_asset_type) END_SERIALIZE() }; @@ -1755,7 +1757,7 @@ private: uint64_t &total_yield, uint64_t &yield_per_stake, uint64_t &ybi_data_size, - std::vector> &payouts + std::vector> &payouts ); private: @@ -2365,6 +2367,7 @@ namespace boost { a & x.m_index_major; a & x.m_amount; + a & x.m_asset_type; } template