//------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_split_integrated_address(const wallet_rpc::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::response& res, epee::json_rpc::error& er) { try { cryptonote::account_public_address address; crypto::hash payment_id; bool has_payment_id; if(!get_account_integrated_address_from_str(address, has_payment_id, payment_id, m_wallet.testnet(), req.integrated_address)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; er.message = "Invalid address"; return false; } if(!has_payment_id) { er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; er.message = "Address is not an integrated address"; return false; } res.standard_address = get_account_address_as_str(m_wallet.testnet(),address); res.payment_id = boost::lexical_cast<std::string>(payment_id); return true; } catch (std::exception &e) { er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; er.message = e.what(); return false; } return true; }
//----------------------------------------------------------------- std::string account_base::get_public_address_str() { //TODO: change this code into base 58 return get_account_address_as_str(m_keys.m_account_address); }
//---------------------------------------------------------------------------------------------------- bool UnsignedTransactionImpl::checkLoadedTx(const std::function<size_t()> get_num_txes, const std::function<const tools::wallet2::tx_construction_data&(size_t)> &get_tx, const std::string &extra_message) { // gather info to ask the user uint64_t amount = 0, amount_to_dests = 0, change = 0; size_t min_ring_size = ~0; std::unordered_map<cryptonote::account_public_address, std::pair<std::string, uint64_t>> dests; int first_known_non_zero_change_index = -1; std::string payment_id_string = ""; for (size_t n = 0; n < get_num_txes(); ++n) { const tools::wallet2::tx_construction_data &cd = get_tx(n); std::vector<cryptonote::tx_extra_field> tx_extra_fields; bool has_encrypted_payment_id = false; crypto::hash8 payment_id8 = crypto::null_hash8; if (cryptonote::parse_tx_extra(cd.extra, tx_extra_fields)) { cryptonote::tx_extra_nonce extra_nonce; if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) { crypto::hash payment_id; if(cryptonote::get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) { if (!payment_id_string.empty()) payment_id_string += ", "; payment_id_string = std::string("encrypted payment ID ") + epee::string_tools::pod_to_hex(payment_id8); has_encrypted_payment_id = true; } else if (cryptonote::get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) { if (!payment_id_string.empty()) payment_id_string += ", "; payment_id_string = std::string("unencrypted payment ID ") + epee::string_tools::pod_to_hex(payment_id); } } } for (size_t s = 0; s < cd.sources.size(); ++s) { amount += cd.sources[s].amount; size_t ring_size = cd.sources[s].outputs.size(); if (ring_size < min_ring_size) min_ring_size = ring_size; } for (size_t d = 0; d < cd.splitted_dsts.size(); ++d) { const cryptonote::tx_destination_entry &entry = cd.splitted_dsts[d]; std::string address, standard_address = get_account_address_as_str(m_wallet.testnet(), entry.is_subaddress, entry.addr); if (has_encrypted_payment_id && !entry.is_subaddress) { address = get_account_integrated_address_as_str(m_wallet.testnet(), entry.addr, payment_id8); address += std::string(" (" + standard_address + " with encrypted payment id " + epee::string_tools::pod_to_hex(payment_id8) + ")"); } else address = standard_address; auto i = dests.find(entry.addr); if (i == dests.end()) dests.insert(std::make_pair(entry.addr, std::make_pair(address, entry.amount))); else i->second.second += entry.amount; amount_to_dests += entry.amount; } if (cd.change_dts.amount > 0) { auto it = dests.find(cd.change_dts.addr); if (it == dests.end()) { m_status = Status_Error; m_errorString = tr("Claimed change does not go to a paid address"); return false; } if (it->second.second < cd.change_dts.amount) { m_status = Status_Error; m_errorString = tr("Claimed change is larger than payment to the change address"); return false; } if (cd.change_dts.amount > 0) { if (first_known_non_zero_change_index == -1) first_known_non_zero_change_index = n; if (memcmp(&cd.change_dts.addr, &get_tx(first_known_non_zero_change_index).change_dts.addr, sizeof(cd.change_dts.addr))) { m_status = Status_Error; m_errorString = tr("Change goes to more than one address"); return false; } } change += cd.change_dts.amount; it->second.second -= cd.change_dts.amount; if (it->second.second == 0) dests.erase(cd.change_dts.addr); } } std::string dest_string; for (auto i = dests.begin(); i != dests.end(); ) { dest_string += (boost::format(tr("sending %s to %s")) % cryptonote::print_money(i->second.second) % i->second.first).str(); ++i; if (i != dests.end()) dest_string += ", "; } if (dest_string.empty()) dest_string = tr("with no destinations"); std::string change_string; if (change > 0) { std::string address = get_account_address_as_str(m_wallet.m_wallet->testnet(), get_tx(0).subaddr_account > 0, get_tx(0).change_dts.addr); change_string += (boost::format(tr("%s change to %s")) % cryptonote::print_money(change) % address).str(); } else change_string += tr("no change"); uint64_t fee = amount - amount_to_dests; m_confirmationMessage = (boost::format(tr("Loaded %lu transactions, for %s, fee %s, %s, %s, with min ring size %lu. %s")) % (unsigned long)get_num_txes() % cryptonote::print_money(amount) % cryptonote::print_money(fee) % dest_string % change_string % (unsigned long)min_ring_size % extra_message).str(); return true; }
bool WalletManagerImpl::checkPayment(const std::string &address_text, const std::string &txid_text, const std::string &txkey_text, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const { error = ""; cryptonote::blobdata txid_data; if(!epee::string_tools::parse_hexstr_to_binbuff(txid_text, txid_data)) { error = tr("failed to parse txid"); return false; } crypto::hash txid = *reinterpret_cast<const crypto::hash*>(txid_data.data()); if (txkey_text.size() < 64 || txkey_text.size() % 64) { error = tr("failed to parse tx key"); return false; } crypto::secret_key tx_key; cryptonote::blobdata tx_key_data; if(!epee::string_tools::parse_hexstr_to_binbuff(txkey_text, tx_key_data)) { error = tr("failed to parse tx key"); return false; } tx_key = *reinterpret_cast<const crypto::secret_key*>(tx_key_data.data()); bool testnet = address_text[0] != '4'; cryptonote::account_public_address address; bool has_payment_id; crypto::hash8 payment_id; if(!cryptonote::get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, address_text)) { error = tr("failed to parse address"); return false; } cryptonote::COMMAND_RPC_GET_TRANSACTIONS::request req; cryptonote::COMMAND_RPC_GET_TRANSACTIONS::response res; req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid)); epee::net_utils::http::http_simple_client http_client; if (!epee::net_utils::invoke_http_json_remote_command2(daemon_address + "/gettransactions", req, res, http_client) || (res.txs.size() != 1 && res.txs_as_hex.size() != 1)) { error = tr("failed to get transaction from daemon"); return false; } cryptonote::blobdata tx_data; bool ok; if (res.txs.size() == 1) ok = epee::string_tools::parse_hexstr_to_binbuff(res.txs.front().as_hex, tx_data); else ok = epee::string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data); if (!ok) { error = tr("failed to parse transaction from daemon"); return false; } crypto::hash tx_hash, tx_prefix_hash; cryptonote::transaction tx; if (!cryptonote::parse_and_validate_tx_from_blob(tx_data, tx, tx_hash, tx_prefix_hash)) { error = tr("failed to validate transaction from daemon"); return false; } if (tx_hash != txid) { error = tr("failed to get the right transaction from daemon"); return false; } crypto::key_derivation derivation; if (!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation)) { error = tr("failed to generate key derivation from supplied parameters"); return false; } received = 0; try { for (size_t n = 0; n < tx.vout.size(); ++n) { if (typeid(cryptonote::txout_to_key) != tx.vout[n].target.type()) continue; const cryptonote::txout_to_key tx_out_to_key = boost::get<cryptonote::txout_to_key>(tx.vout[n].target); crypto::public_key pubkey; derive_public_key(derivation, n, address.m_spend_public_key, pubkey); if (pubkey == tx_out_to_key.key) { uint64_t amount; if (tx.version == 1) { amount = tx.vout[n].amount; } else { try { rct::key Ctmp; //rct::key amount_key = rct::hash_to_scalar(rct::scalarmultKey(rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key))); crypto::key_derivation derivation; bool r = crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation); if (!r) { LOG_ERROR("Failed to generate key derivation to decode rct output " << n); amount = 0; } else { crypto::secret_key scalar1; crypto::derivation_to_scalar(derivation, n, scalar1); rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n]; rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1)); rct::key C = tx.rct_signatures.outPk[n].mask; rct::addKeys2(Ctmp, ecdh_info.mask, ecdh_info.amount, rct::H); if (rct::equalKeys(C, Ctmp)) amount = rct::h2d(ecdh_info.amount); else amount = 0; } } catch (...) { amount = 0; } } received += amount; } } } catch(const std::exception &e) { LOG_ERROR("error: " << e.what()); error = std::string(tr("error: ")) + e.what(); return false; } if (received > 0) { LOG_PRINT_L1(get_account_address_as_str(testnet, address) << " " << tr("received") << " " << cryptonote::print_money(received) << " " << tr("in txid") << " " << txid); } else { LOG_PRINT_L1(get_account_address_as_str(testnet, address) << " " << tr("received nothing in txid") << " " << txid); } if (res.txs.front().in_pool) { height = 0; } else { height = res.txs.front().block_height; } return true; }
/** * Return string representation of monero address */ string print_address(const account_public_address& address) { return get_account_address_as_str(false, address); }
ostream& operator<< (ostream& os, const account_public_address& addr) { os << "<" << get_account_address_as_str(false, addr) << ">"; return os; }
//---------------------------------------------------------------------------------------------------- bool UnsignedTransactionImpl::checkLoadedTx(const std::function<size_t()> get_num_txes, const std::function<const tools::wallet2::tx_construction_data&(size_t)> &get_tx, const std::string &extra_message) { // gather info to ask the user uint64_t amount = 0, amount_to_dests = 0, change = 0; size_t min_ring_size = ~0; std::unordered_map<std::string, uint64_t> dests; const std::string wallet_address = m_wallet.m_wallet->get_account().get_public_address_str(m_wallet.m_wallet->testnet()); int first_known_non_zero_change_index = -1; for (size_t n = 0; n < get_num_txes(); ++n) { const tools::wallet2::tx_construction_data &cd = get_tx(n); for (size_t s = 0; s < cd.sources.size(); ++s) { amount += cd.sources[s].amount; size_t ring_size = cd.sources[s].outputs.size(); if (ring_size < min_ring_size) min_ring_size = ring_size; } for (size_t d = 0; d < cd.splitted_dsts.size(); ++d) { const cryptonote::tx_destination_entry &entry = cd.splitted_dsts[d]; std::string address = get_account_address_as_str(m_wallet.m_wallet->testnet(), entry.addr); std::unordered_map<std::string,uint64_t>::iterator i = dests.find(address); if (i == dests.end()) dests.insert(std::make_pair(address, entry.amount)); else i->second += entry.amount; amount_to_dests += entry.amount; } if (cd.change_dts.amount > 0) { std::unordered_map<std::string, uint64_t>::iterator it = dests.find(get_account_address_as_str(m_wallet.m_wallet->testnet(), cd.change_dts.addr)); if (it == dests.end()) { m_status = Status_Error; m_errorString = tr("Claimed change does not go to a paid address"); return false; } if (it->second < cd.change_dts.amount) { m_status = Status_Error; m_errorString = tr("Claimed change is larger than payment to the change address"); return false; } if (cd.change_dts.amount > 0) { if (first_known_non_zero_change_index == -1) first_known_non_zero_change_index = n; if (memcmp(&cd.change_dts.addr, &get_tx(first_known_non_zero_change_index).change_dts.addr, sizeof(cd.change_dts.addr))) { m_status = Status_Error; m_errorString = tr("Change goes to more than one address"); return false; } } change += cd.change_dts.amount; it->second -= cd.change_dts.amount; if (it->second == 0) dests.erase(get_account_address_as_str(m_wallet.m_wallet->testnet(), cd.change_dts.addr)); } } std::string dest_string; for (std::unordered_map<std::string, uint64_t>::const_iterator i = dests.begin(); i != dests.end(); ) { dest_string += (boost::format(tr("sending %s to %s")) % cryptonote::print_money(i->second) % i->first).str(); ++i; if (i != dests.end()) dest_string += ", "; } if (dest_string.empty()) dest_string = tr("with no destinations"); std::string change_string; if (change > 0) { std::string address = get_account_address_as_str(m_wallet.m_wallet->testnet(), get_tx(0).change_dts.addr); change_string += (boost::format(tr("%s change to %s")) % cryptonote::print_money(change) % address).str(); } else change_string += tr("no change"); uint64_t fee = amount - amount_to_dests; m_confirmationMessage = (boost::format(tr("Loaded %lu transactions, for %s, fee %s, %s, %s, with min ring size %lu. %s")) % (unsigned long)get_num_txes() % cryptonote::print_money(amount) % cryptonote::print_money(fee) % dest_string % change_string % (unsigned long)min_ring_size % extra_message).str(); return true; }