From 7469d691cb398ad2672bc82444665a1477bcfb14 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Tue, 28 Jan 2025 21:53:49 +0530 Subject: [PATCH 01/50] Multiple url functionality. --- src/simplewallet/simplewallet.cpp | 68 +++++++-- src/wallet/api/wallet.cpp | 14 +- src/wallet/wallet2.cpp | 152 +++++++++++++++---- src/wallet/wallet2.h | 11 +- src/wallet/wallet_rpc_server.cpp | 20 ++- src/wallet/wallet_rpc_server_commands_defs.h | 28 +++- 6 files changed, 241 insertions(+), 52 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 28048590ba1..462d788dcaa 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6532,25 +6532,71 @@ bool simple_wallet::transfer_main(const std::vector &args_, bool ca bool r = true; // check for a URI - std::string address_uri, payment_id_uri, tx_description, recipient_name, error; + std::string payment_id_uri, tx_description, error; std::vector unknown_parameters; - uint64_t amount = 0; - bool has_uri = m_wallet->parse_uri(local_args[i], address_uri, payment_id_uri, amount, tx_description, recipient_name, unknown_parameters, error); + std::vector uri_data; + bool has_uri = m_wallet->parse_uri(local_args[i], uri_data, payment_id_uri, tx_description, unknown_parameters, error); if (has_uri) { - r = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), address_uri, oa_prompter); - if (payment_id_uri.size() == 16) + + for (size_t j = 0; j < uri_data.size(); j++) { - if (!tools::wallet2::parse_short_payment_id(payment_id_uri, info.payment_id)) + r = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), uri_data[j].address, oa_prompter); + if (payment_id_uri.size() == 16) { - fail_msg_writer() << tr("failed to parse short payment ID from URI"); + if (!tools::wallet2::parse_short_payment_id(payment_id_uri, info.payment_id)) + { + fail_msg_writer() << tr("failed to parse short payment ID from URI"); + return false; + } + info.has_payment_id = true; + } + de.amount = uri_data[j].amount; + de.original = uri_data[j].address; + if (!r) + { + fail_msg_writer() << tr("failed to parse address"); return false; } - info.has_payment_id = true; + de.addr = info.address; + de.is_subaddress = info.is_subaddress; + de.is_integrated = info.has_payment_id; + // num_subaddresses += info.is_subaddress; + + if (info.has_payment_id || !payment_id_uri.empty()) + { + if (payment_id_seen) + { + fail_msg_writer() << tr("a single transaction cannot use more than one payment id"); + return false; + } + crypto::hash payment_id; + std::string extra_nonce; + if (info.has_payment_id) + { + set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id); + } + else if (tools::wallet2::parse_payment_id(payment_id_uri, payment_id)) + { + LONG_PAYMENT_ID_SUPPORT_CHECK(); + } + else + { + fail_msg_writer() << tr("failed to parse payment id, though it was detected"); + return false; + } + bool r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + if(!r) + { + fail_msg_writer() << tr("failed to set up payment id, though it was decoded correctly"); + return false; + } + payment_id_seen = true; + } + dsts.push_back(de); } - de.amount = amount; - de.original = local_args[i]; - ++i; + i++; + break; } else if (i + 1 < local_args.size()) { diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 6c50002dd1c..b3c47714eb1 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2550,7 +2550,19 @@ bool WalletImpl::checkBackgroundSync(const std::string &message) const bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) { - return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error); + std::vector data; + if (!m_wallet->parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error)) { + setStatusError(tr("Failed to parse uri")); + return false; + } + if (data.size() > 1) { + setStatusError(tr("Multi-recipient URIs currently unsupported")); + return false; + } + address = data[0].address; + amount = data[0].amount; + recipient_name = data[0].recipient_name; + return true; } std::string WalletImpl::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 04be12c137e..d73580a8deb 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14942,13 +14942,51 @@ std::string wallet2::decrypt_with_view_secret_key(const std::string &ciphertext, return decrypt(ciphertext, get_account().get_keys().m_view_secret_key, authenticated); } //---------------------------------------------------------------------------------------------------- -std::string wallet2::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const +std::string wallet2::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const { - cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, nettype(), address)) + std::string addresses = ""; + std::string amounts = ""; + bool amounts_used = false; + std::string recipients = ""; + bool recipients_used = false; + for (uri_data entry : data) { - error = std::string("wrong address: ") + address; - return std::string(); + cryptonote::address_parse_info info; + if(!get_account_address_from_str(info, nettype(), entry.address)) + { + error = std::string("wrong address: ") + entry.address; + return std::string(); + } + if (!payment_id.empty()) + { + error = "Standalone payment id deprecated, use integrated address instead"; + return std::string(); + } + if (!addresses.empty()) + { + addresses += ";"; + } + addresses += entry.address; + + if (!amounts.empty()) + { + amounts += ";"; + } + if (entry.amount > 0) + { + amounts_used = true; + } + amounts += cryptonote::print_money(entry.amount); + + if (!recipients.empty()) + { + recipients += ";"; + } + if (!entry.recipient_name.empty()) + { + recipients_used = true; + recipients += epee::net_utils::conver_to_url_format(entry.recipient_name); + } } // we want only one payment id @@ -14964,7 +15002,7 @@ std::string wallet2::make_uri(const std::string &address, const std::string &pay return std::string(); } - std::string uri = "monero:" + address; + std::string uri = "monero:" + addresses; unsigned int n_fields = 0; if (!payment_id.empty()) @@ -14972,15 +15010,15 @@ std::string wallet2::make_uri(const std::string &address, const std::string &pay uri += (n_fields++ ? "&" : "?") + std::string("tx_payment_id=") + payment_id; } - if (amount > 0) + if (amounts_used) { // URI encoded amount is in decimal units, not atomic units - uri += (n_fields++ ? "&" : "?") + std::string("tx_amount=") + cryptonote::print_money(amount); + uri += (n_fields++ ? "&" : "?") + std::string("tx_amount=") + amounts; } - if (!recipient_name.empty()) + if (recipients_used) { - uri += (n_fields++ ? "&" : "?") + std::string("recipient_name=") + epee::net_utils::conver_to_url_format(recipient_name); + uri += (n_fields++ ? "&" : "?") + std::string("recipient_name=") + recipients; } if (!tx_description.empty()) @@ -14988,10 +15026,21 @@ std::string wallet2::make_uri(const std::string &address, const std::string &pay uri += (n_fields++ ? "&" : "?") + std::string("tx_description=") + epee::net_utils::conver_to_url_format(tx_description); } + if (!payment_id.empty()) + { + crypto::hash pid32; + if (!wallet2::parse_long_payment_id(payment_id, pid32)) + { + error = "Invalid payment id"; + return std::string(); + } + uri += (n_fields++ ? "&" : "?") + std::string("tx_payment_id=") + payment_id; + } + return uri; } //---------------------------------------------------------------------------------------------------- -bool wallet2::parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) +bool wallet2::parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) { if (uri.substr(0, 7) != "monero:") { @@ -15001,24 +15050,33 @@ bool wallet2::parse_uri(const std::string &uri, std::string &address, std::strin std::string remainder = uri.substr(7); const char *ptr = strchr(remainder.c_str(), '?'); - address = ptr ? remainder.substr(0, ptr-remainder.c_str()) : remainder; + std::string addresses_string = ptr ? remainder.substr(0, ptr-remainder.c_str()) : remainder; + std::vector addresses, recipient_names; + std::vector amounts; + boost::split(addresses, addresses_string, boost::is_any_of(";")); - cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, nettype(), address)) + for (const std::string &address : addresses) { - error = std::string("URI has wrong address: ") + address; - return false; + cryptonote::address_parse_info info; + if(!get_account_address_from_str(info, nettype(), address)) + { + error = std::string("URI constains improper address: ") + address; + return false; + } + uri_data recipient_data; + recipient_data.address = address; + recipient_data.amount = 0; + data.push_back(recipient_data); } - if (!strchr(remainder.c_str(), '?')) + + if (ptr == NULL) return true; + std::string params(ptr+1); std::vector arguments; - std::string body = remainder.substr(address.size() + 1); - if (body.empty()) - return true; - boost::split(arguments, body, boost::is_any_of("&")); + boost::split(arguments, params, boost::is_any_of("&")); std::set have_arg; - for (const auto &arg: arguments) + for (const std::string &arg : arguments) { std::vector kv; boost::split(kv, arg, boost::is_any_of("=")); @@ -15036,20 +15094,21 @@ bool wallet2::parse_uri(const std::string &uri, std::string &address, std::strin if (kv[0] == "tx_amount") { - amount = 0; - if (!cryptonote::parse_amount(amount, kv[1])) + std::vector amounts_split; + boost::split(amounts_split, kv[1], boost::is_any_of(";")); + for (size_t i = 0; i < amounts_split.size(); i++) { - error = std::string("URI has invalid amount: ") + kv[1]; - return false; + uint64_t amount; + if (!cryptonote::parse_amount(amount, amounts_split[i])) + { + error = std::string("URI has invalid amount: ") + amounts_split[i]; + return false; + } + amounts.push_back(amount); } } else if (kv[0] == "tx_payment_id") { - if (info.has_payment_id) - { - error = "Separate payment id given with an integrated address"; - return false; - } crypto::hash hash; if (!wallet2::parse_long_payment_id(kv[1], hash)) { @@ -15060,7 +15119,12 @@ bool wallet2::parse_uri(const std::string &uri, std::string &address, std::strin } else if (kv[0] == "recipient_name") { - recipient_name = epee::net_utils::convert_from_url_format(kv[1]); + std::vector names_split; + boost::split(names_split, kv[1], boost::is_any_of(";")); + for (size_t i = 0; i < names_split.size(); i++) + { + recipient_names.push_back(epee::net_utils::convert_from_url_format(names_split[i])); + } } else if (kv[0] == "tx_description") { @@ -15071,6 +15135,30 @@ bool wallet2::parse_uri(const std::string &uri, std::string &address, std::strin unknown_parameters.push_back(arg); } } + + if (!recipient_names.empty() && recipient_names.size() != addresses.size()) + { + error = "Incorrect recipient name count. If a recipient name is assigned there should be an entry for each recipient."; + return false; + } + if (!amounts.empty() && amounts.size() != addresses.size()) + { + error = "Incorrect amount count. If an amount is assigned there should be an entry for each recipient. zero may be use as a filler"; + return false; + } + + for(size_t i = 0; i < data.size(); i++) + { + if (!amounts.empty()) + { + data[i].amount = amounts[i]; + } + if (!recipient_names.empty()) + { + data[i].recipient_name = recipient_names[i]; + } + } + return true; } //---------------------------------------------------------------------------------------------------- diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 59f279cee0e..a851cb02ca7 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -871,6 +871,13 @@ namespace tools bool empty() const { return tx_extra_fields.empty() && primary.empty() && additional.empty(); } }; + struct uri_data + { + std::string address; + uint64_t amount; + std::string recipient_name; + }; + struct detached_blockchain_data { hashchain detached_blockchain; @@ -1641,8 +1648,8 @@ namespace tools template T decrypt(const std::string &ciphertext, const crypto::secret_key &skey, bool authenticated = true) const; std::string decrypt_with_view_secret_key(const std::string &ciphertext, bool authenticated = true) const; - std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const; - bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error); + std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; + bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); uint64_t get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day); // 1<=month<=12, 1<=day<=31 diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 33437606228..63da74c7d87 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -3109,7 +3109,17 @@ namespace tools { if (!m_wallet) return not_open(er); std::string error; - std::string uri = m_wallet->make_uri(req.address, req.payment_id, req.amount, req.tx_description, req.recipient_name, error); + std::vector data; + for (tools::wallet_rpc::uri_payment entry : req.payments) + { + tools::wallet2::uri_data entry_data; + entry_data.address = entry.address; + entry_data.amount = entry.amount; + entry_data.recipient_name = entry.recipient_name; + data.push_back(entry_data); + } + std::string uri = m_wallet->make_uri(data, req.payment_id, req.tx_description, error); + if (uri.empty()) { er.code = WALLET_RPC_ERROR_CODE_WRONG_URI; @@ -3125,12 +3135,18 @@ namespace tools { if (!m_wallet) return not_open(er); std::string error; - if (!m_wallet->parse_uri(req.uri, res.uri.address, res.uri.payment_id, res.uri.amount, res.uri.tx_description, res.uri.recipient_name, res.unknown_parameters, error)) + std::vector uri_data; + if (!m_wallet->parse_uri(req.uri, uri_data, res.uri.payment_id, res.uri.tx_description, res.unknown_parameters, error)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_URI; er.message = "Error parsing URI: " + error; return false; } + for (const tools::wallet2::uri_data entry : uri_data) + { + tools::wallet_rpc::uri_payment entry_spec = {entry.address, entry.amount, entry.recipient_name}; + res.uri.payments.push_back(entry_spec); + } return true; } //------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index ab7898299e1..3ee97294284 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -1825,12 +1825,10 @@ namespace wallet_rpc typedef epee::misc_utils::struct_init response; }; - struct uri_spec + struct uri_payment { std::string address; - std::string payment_id; uint64_t amount; - std::string tx_description; std::string recipient_name; BEGIN_KV_SERIALIZE_MAP() @@ -1842,10 +1840,32 @@ namespace wallet_rpc END_KV_SERIALIZE_MAP() }; + struct uri_spec + { + std::vector payments; + std::string tx_description; + std::string payment_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(payments); + KV_SERIALIZE(tx_description); + KV_SERIALIZE(payment_id); + END_KV_SERIALIZE_MAP() + }; + + struct COMMAND_RPC_MAKE_URI { - struct request_t: public uri_spec + struct request_t { + std::vector payments; + std::string tx_description; + std::string payment_id; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(payments); + KV_SERIALIZE(tx_description); + KV_SERIALIZE(payment_id); + END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init request; From d1f69b9fa0dce4a69adda8757bb136b60062dbfd Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Tue, 28 Jan 2025 21:55:02 +0530 Subject: [PATCH 02/50] Remove commented line. --- src/simplewallet/simplewallet.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 462d788dcaa..ac1349b83f6 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6561,7 +6561,6 @@ bool simple_wallet::transfer_main(const std::vector &args_, bool ca de.addr = info.address; de.is_subaddress = info.is_subaddress; de.is_integrated = info.has_payment_id; - // num_subaddresses += info.is_subaddress; if (info.has_payment_id || !payment_id_uri.empty()) { From 1b1e93070c46c166c7cc92830b5453e81c73783c Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Tue, 28 Jan 2025 22:15:41 +0530 Subject: [PATCH 03/50] Fix error by removing repeated code block. --- src/wallet/wallet2.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index d73580a8deb..d9cc162937d 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14989,19 +14989,6 @@ std::string wallet2::make_uri(std::vector data, const std::string &pay } } - // we want only one payment id - if (info.has_payment_id && !payment_id.empty()) - { - error = "A single payment id is allowed"; - return std::string(); - } - - if (!payment_id.empty()) - { - error = "Standalone payment id deprecated, use integrated address instead"; - return std::string(); - } - std::string uri = "monero:" + addresses; unsigned int n_fields = 0; From 168668a4019b5bec41b4dffc303d6edcfb252f2e Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Tue, 28 Jan 2025 22:29:46 +0530 Subject: [PATCH 04/50] fix no member named errors --- src/wallet/wallet_rpc_server_commands_defs.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 3ee97294284..bdb72b93b04 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -1833,9 +1833,7 @@ namespace wallet_rpc BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(address) - KV_SERIALIZE(payment_id) KV_SERIALIZE(amount) - KV_SERIALIZE(tx_description) KV_SERIALIZE(recipient_name) END_KV_SERIALIZE_MAP() }; @@ -1853,7 +1851,6 @@ namespace wallet_rpc END_KV_SERIALIZE_MAP() }; - struct COMMAND_RPC_MAKE_URI { struct request_t From ab0c39e3688bea8ceb04b2c73bbce119a3c4c13d Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Tue, 28 Jan 2025 22:57:58 +0530 Subject: [PATCH 05/50] Add function overloads for make_uri to make it compatible with older usages. --- src/wallet/api/wallet.cpp | 58 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index b3c47714eb1..50a9a307d66 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2565,11 +2565,67 @@ bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::st return true; } +std::string WalletImpl::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const +{ + return m_wallet->make_uri(data, payment_id, tx_description, error); +} + std::string WalletImpl::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const { - return m_wallet->make_uri(address, payment_id, amount, tx_description, recipient_name, error); + // from wallet2.h - improve + struct uri_data + { + std::string address; + uint64_t amount; + std::string recipient_name; + } entry; + entry.address = address; + entry.amount = amount; + entry.recipient_name = recipient_name; + + std::vector data; + data.push_back(entry); + + return m_wallet->make_uri(data, payment_id, tx_description, error); } +std::string WalletImpl::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, const std::vector &unknown_parameters, std::string &error) const +{ + struct uri_data + { + std::string address; + uint64_t amount; + std::string recipient_name; + } entry; + entry.address = address; + entry.amount = amount; + entry.recipient_name = recipient_name; + + std::vector data; + data.push_back(entry); + + std::string base_uri = m_wallet->make_uri(data, payment_id, tx_description, error); + if (base_uri.empty()) + { + return std::string(); + } + + std::string extended_uri = base_uri; + for (const auto ¶m : unknown_parameters) + { + if (extended_uri.find('?') == std::string::npos) + { + extended_uri += "?"; + } else { + extended_uri += "&"; + } + extended_uri += param; + } + + return extended_uri; +} + + std::string WalletImpl::getDefaultDataDir() const { return tools::get_default_data_dir(); From 25b3ef25dc7e352954889ccd2f7d4ff3009b8dbf Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 29 Jan 2025 07:28:44 +0530 Subject: [PATCH 06/50] Fix tests --- src/wallet/api/wallet.cpp | 58 +-------------------------------------- src/wallet/wallet2.cpp | 9 +++--- 2 files changed, 5 insertions(+), 62 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 50a9a307d66..b3c47714eb1 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2565,67 +2565,11 @@ bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::st return true; } -std::string WalletImpl::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const -{ - return m_wallet->make_uri(data, payment_id, tx_description, error); -} - std::string WalletImpl::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const { - // from wallet2.h - improve - struct uri_data - { - std::string address; - uint64_t amount; - std::string recipient_name; - } entry; - entry.address = address; - entry.amount = amount; - entry.recipient_name = recipient_name; - - std::vector data; - data.push_back(entry); - - return m_wallet->make_uri(data, payment_id, tx_description, error); + return m_wallet->make_uri(address, payment_id, amount, tx_description, recipient_name, error); } -std::string WalletImpl::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, const std::vector &unknown_parameters, std::string &error) const -{ - struct uri_data - { - std::string address; - uint64_t amount; - std::string recipient_name; - } entry; - entry.address = address; - entry.amount = amount; - entry.recipient_name = recipient_name; - - std::vector data; - data.push_back(entry); - - std::string base_uri = m_wallet->make_uri(data, payment_id, tx_description, error); - if (base_uri.empty()) - { - return std::string(); - } - - std::string extended_uri = base_uri; - for (const auto ¶m : unknown_parameters) - { - if (extended_uri.find('?') == std::string::npos) - { - extended_uri += "?"; - } else { - extended_uri += "&"; - } - extended_uri += param; - } - - return extended_uri; -} - - std::string WalletImpl::getDefaultDataDir() const { return tools::get_default_data_dir(); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index d9cc162937d..1fc313dea56 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14992,11 +14992,6 @@ std::string wallet2::make_uri(std::vector data, const std::string &pay std::string uri = "monero:" + addresses; unsigned int n_fields = 0; - if (!payment_id.empty()) - { - uri += (n_fields++ ? "&" : "?") + std::string("tx_payment_id=") + payment_id; - } - if (amounts_used) { // URI encoded amount is in decimal units, not atomic units @@ -15148,6 +15143,10 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std return true; } +} +bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::unordered_map& unknown_parameters, std::string& error) { + return parse_uri(uri, address, payment_id, amount, description, error); +} //---------------------------------------------------------------------------------------------------- uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day) { From a55f1f190a6ddbb8d0c1ad6d4078628626a4eca1 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 29 Jan 2025 07:46:01 +0530 Subject: [PATCH 07/50] Fix function overloads --- src/wallet/api/wallet.cpp | 16 +++++++++++++--- src/wallet/wallet2.cpp | 21 ++++++++++++++++++--- src/wallet/wallet2.h | 1 + 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index b3c47714eb1..ca279b5802e 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2551,11 +2551,13 @@ bool WalletImpl::checkBackgroundSync(const std::string &message) const bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) { std::vector data; - if (!m_wallet->parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error)) { + if (!m_wallet->parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error)) + { setStatusError(tr("Failed to parse uri")); return false; } - if (data.size() > 1) { + if (data.size() > 1) + { setStatusError(tr("Multi-recipient URIs currently unsupported")); return false; } @@ -2567,7 +2569,15 @@ bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::st std::string WalletImpl::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const { - return m_wallet->make_uri(address, payment_id, amount, tx_description, recipient_name, error); + tools::wallet2::uri_data entry; + entry.address = address; + entry.amount = amount; + entry.recipient_name = recipient_name; + + std::vector data; + data.push_back(entry); + + return make_uri(data, payment_id, tx_description, error); } std::string WalletImpl::getDefaultDataDir() const diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 1fc313dea56..2c100c364f6 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -15143,9 +15143,24 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std return true; } -} -bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::unordered_map& unknown_parameters, std::string& error) { - return parse_uri(uri, address, payment_id, amount, description, error); + +bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::unordered_map& unknown_parameters, std::string& error) +{ + std::vector data; + if (!m_wallet->parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error)) + { + setStatusError(tr("Failed to parse uri")); + return false; + } + if (data.size() > 1) + { + setStatusError(tr("Multi-recipient URIs currently unsupported")); + return false; + } + address = data[0].address; + amount = data[0].amount; + recipient_name = data[0].recipient_name; + return true; } //---------------------------------------------------------------------------------------------------- uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index a851cb02ca7..ed52d77dd57 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1650,6 +1650,7 @@ namespace tools std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); + bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::unordered_map& unknown_parameters, std::string& error); uint64_t get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day); // 1<=month<=12, 1<=day<=31 From 246926a40b1f59f5792f8b7dbdded782d7c1c239 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 29 Jan 2025 07:58:44 +0530 Subject: [PATCH 08/50] Fix errors of parse_uri saying that m_wallet was not found. --- src/wallet/wallet2.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 2c100c364f6..9736c0b1a0b 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -15147,14 +15147,14 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::unordered_map& unknown_parameters, std::string& error) { std::vector data; - if (!m_wallet->parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error)) + if (!parse_uri(uri, data, payment_id, "", unknown_parameters, error)) { - setStatusError(tr("Failed to parse uri")); + throw std::runtime_error("failed to parse URI" + uri) return false; } if (data.size() > 1) { - setStatusError(tr("Multi-recipient URIs currently unsupported")); + throw std::runtime_error("multi-recipient URIs currently unsupported") return false; } address = data[0].address; From bfa2c35bc930ea1bf31c10ef5016dbf50c313028 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 29 Jan 2025 08:10:15 +0530 Subject: [PATCH 09/50] Add semi-colon --- src/wallet/wallet2.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 9736c0b1a0b..4d0dc63e089 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -15147,14 +15147,14 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::unordered_map& unknown_parameters, std::string& error) { std::vector data; - if (!parse_uri(uri, data, payment_id, "", unknown_parameters, error)) + if (!this->parse_uri(uri, data, payment_id, "", unknown_parameters, error)) { - throw std::runtime_error("failed to parse URI" + uri) + throw std::runtime_error("failed to parse URI" + uri); return false; } if (data.size() > 1) { - throw std::runtime_error("multi-recipient URIs currently unsupported") + throw std::runtime_error("multi-recipient URIs currently unsupported"); return false; } address = data[0].address; From cd922c60ab60c22f9ec5ae19e9e8ae774b445e11 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 29 Jan 2025 08:18:55 +0530 Subject: [PATCH 10/50] Update parse_uri to support single tx --- src/wallet/wallet2.cpp | 77 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 14 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 4d0dc63e089..679a1661635 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -15146,20 +15146,69 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::unordered_map& unknown_parameters, std::string& error) { - std::vector data; - if (!this->parse_uri(uri, data, payment_id, "", unknown_parameters, error)) - { - throw std::runtime_error("failed to parse URI" + uri); - return false; - } - if (data.size() > 1) - { - throw std::runtime_error("multi-recipient URIs currently unsupported"); - return false; - } - address = data[0].address; - amount = data[0].amount; - recipient_name = data[0].recipient_name; + if (uri.substr(0, 7) != "monero:") { + error = std::string("URI has wrong scheme (expected \"monero:\"): ") + uri; + return false; + } + + std::string remainder = uri.substr(7); + const char* ptr = strchr(remainder.c_str(), '?'); + std::string address_string = ptr ? remainder.substr(0, ptr - remainder.c_str()) : remainder; + + cryptonote::address_parse_info info; + if (!get_account_address_from_str(info, nettype(), address_string)) { + error = std::string("URI contains improper address: ") + address_string; + return false; + } + + // Assign the parsed address + address = address_string; + + if (ptr == nullptr) { // No parameters to process + return true; + } + + std::string params(ptr + 1); + std::vector arguments; + boost::split(arguments, params, boost::is_any_of("&")); + std::set have_arg; + + amount = 0; // Default amount + for (const std::string& arg : arguments) { + std::vector kv; + boost::split(kv, arg, boost::is_any_of("=")); + if (kv.size() != 2) { + error = std::string("URI has wrong parameter: ") + arg; + return false; + } + + if (have_arg.find(kv[0]) != have_arg.end()) { + error = std::string("URI has more than one instance of ") + kv[0]; + return false; + } + have_arg.insert(kv[0]); + + if (kv[0] == "tx_amount") { + if (!cryptonote::parse_amount(amount, kv[1])) { + error = std::string("URI has invalid amount: ") + kv[1]; + return false; + } + } else if (kv[0] == "tx_payment_id") { + crypto::hash hash; + if (!wallet2::parse_long_payment_id(kv[1], hash)) { + error = "Invalid payment ID: " + kv[1]; + return false; + } + payment_id = kv[1]; + } else if (kv[0] == "recipient_name") { + recipient_name = epee::net_utils::convert_from_url_format(kv[1]); + } else if (kv[0] == "tx_description") { + description = epee::net_utils::convert_from_url_format(kv[1]); + } else { + unknown_parameters[kv[0]] = kv[1]; + } + } + return true; } //---------------------------------------------------------------------------------------------------- From 0fe95f91cf71c3c65df4f62d4898678a168aa104 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 29 Jan 2025 22:43:26 +0530 Subject: [PATCH 11/50] fix parse_uri --- src/wallet/wallet2.cpp | 80 +++++++++--------------------------------- src/wallet/wallet2.h | 2 +- 2 files changed, 17 insertions(+), 65 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 679a1661635..56d299c2aed 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -15144,72 +15144,24 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std return true; } -bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::unordered_map& unknown_parameters, std::string& error) +bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) { - if (uri.substr(0, 7) != "monero:") { - error = std::string("URI has wrong scheme (expected \"monero:\"): ") + uri; - return false; - } - - std::string remainder = uri.substr(7); - const char* ptr = strchr(remainder.c_str(), '?'); - std::string address_string = ptr ? remainder.substr(0, ptr - remainder.c_str()) : remainder; - - cryptonote::address_parse_info info; - if (!get_account_address_from_str(info, nettype(), address_string)) { - error = std::string("URI contains improper address: ") + address_string; - return false; - } - - // Assign the parsed address - address = address_string; - - if (ptr == nullptr) { // No parameters to process - return true; - } - - std::string params(ptr + 1); - std::vector arguments; - boost::split(arguments, params, boost::is_any_of("&")); - std::set have_arg; - - amount = 0; // Default amount - for (const std::string& arg : arguments) { - std::vector kv; - boost::split(kv, arg, boost::is_any_of("=")); - if (kv.size() != 2) { - error = std::string("URI has wrong parameter: ") + arg; - return false; - } - - if (have_arg.find(kv[0]) != have_arg.end()) { - error = std::string("URI has more than one instance of ") + kv[0]; - return false; - } - have_arg.insert(kv[0]); - - if (kv[0] == "tx_amount") { - if (!cryptonote::parse_amount(amount, kv[1])) { - error = std::string("URI has invalid amount: ") + kv[1]; - return false; - } - } else if (kv[0] == "tx_payment_id") { - crypto::hash hash; - if (!wallet2::parse_long_payment_id(kv[1], hash)) { - error = "Invalid payment ID: " + kv[1]; - return false; - } - payment_id = kv[1]; - } else if (kv[0] == "recipient_name") { - recipient_name = epee::net_utils::convert_from_url_format(kv[1]); - } else if (kv[0] == "tx_description") { - description = epee::net_utils::convert_from_url_format(kv[1]); - } else { - unknown_parameters[kv[0]] = kv[1]; - } - } + std::vector data; + if (!parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error)) + { + error = "Failed to parse uri"; + return false; + } + if (data.size() > 1) + { + error = "Multi-recipient URIs currently unsupported"; + return false; + } + address = data[0].address; + amount = data[0].amount; + recipient_name = data[0].recipient_name; - return true; + return true; } //---------------------------------------------------------------------------------------------------- uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index ed52d77dd57..ffd56e76e81 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1650,7 +1650,7 @@ namespace tools std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); - bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::unordered_map& unknown_parameters, std::string& error); + bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error); uint64_t get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day); // 1<=month<=12, 1<=day<=31 From a5750c5626b750a939ec563eb3faffd736d51dd7 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 29 Jan 2025 22:53:31 +0530 Subject: [PATCH 12/50] fix errors --- src/wallet/wallet2.cpp | 2 +- tests/unit_tests/uri.cpp | 75 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 56d299c2aed..6cfbc9f5518 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -15144,7 +15144,7 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std return true; } -bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) +bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) { std::vector data; if (!parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error)) diff --git a/tests/unit_tests/uri.cpp b/tests/unit_tests/uri.cpp index f1c2b694b5b..1992ab7af5f 100644 --- a/tests/unit_tests/uri.cpp +++ b/tests/unit_tests/uri.cpp @@ -213,3 +213,78 @@ TEST(uri, url_encoded_once) ASSERT_EQ(description, "foo 20"); } +TEST(uri, multiple_addresses_no_params) +{ + PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS, true); + ASSERT_EQ(address, TEST_ADDRESS); +} + +TEST(uri, multiple_addresses_with_amounts) +{ + PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000;200000000000", true); + ASSERT_EQ(address, TEST_ADDRESS); + ASSERT_EQ(amount, 500000000000); +} + +TEST(uri, multiple_addresses_with_recipient_names) +{ + PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice;Bob", true); + ASSERT_EQ(address, TEST_ADDRESS); + ASSERT_EQ(recipient_name, "Alice"); +} + +TEST(uri, multiple_addresses_with_mismatched_amounts) +{ + PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000", false); +} + +TEST(uri, multiple_addresses_with_mismatched_recipient_names) +{ + PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice", false); +} + +TEST(uri, multiple_addresses_with_partial_params) +{ + PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000;0&recipient_name=Alice;", true); + ASSERT_EQ(address, TEST_ADDRESS); + ASSERT_EQ(amount, 500000000000); + ASSERT_EQ(recipient_name, "Alice"); +} + +TEST(uri, multiple_addresses_with_unknown_params) +{ + PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?unknown_param=123;456", true); + ASSERT_EQ(unknown_parameters.size(), 1); + ASSERT_EQ(unknown_parameters[0], "unknown_param=123;456"); +} + +TEST(uri, multiple_addresses_with_payment_id) +{ + PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=1234567890123456789012345678901234567890123456789012345678901234", true); + ASSERT_EQ(payment_id, "1234567890123456789012345678901234567890123456789012345678901234"); +} + +TEST(uri, multiple_addresses_with_invalid_payment_id) +{ + PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=123456", false); +} + +TEST(uri, multiple_addresses_with_description) +{ + PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_description=Payment%20for%20services", true); + ASSERT_EQ(description, "Payment for services"); +} + +TEST(uri, multiple_addresses_mismatched_params) +{ + PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000&recipient_name=Alice", false); +} + +TEST(uri, multiple_addresses_all_params_correct) +{ + PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000;200000000000&recipient_name=Alice;Bob&tx_description=Payment%20for%20services", true); + ASSERT_EQ(address, TEST_ADDRESS); + ASSERT_EQ(amount, 500000000000); + ASSERT_EQ(recipient_name, "Alice"); + ASSERT_EQ(description, "Payment for services"); +} From 4a83b22272ecb6e48e12c77c0813c8aab1361b5b Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Thu, 30 Jan 2025 07:20:33 +0530 Subject: [PATCH 13/50] fix make_uri It doesn't properly call make_uri in wallet2.cpp --- src/wallet/api/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index ca279b5802e..63fe95b070d 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2577,7 +2577,7 @@ std::string WalletImpl::make_uri(const std::string &address, const std::string & std::vector data; data.push_back(entry); - return make_uri(data, payment_id, tx_description, error); + return m_wallet->make_uri(data, payment_id, tx_description, error); } std::string WalletImpl::getDefaultDataDir() const From 6ca8ace7c862cb545791df5833776e31ce9f5f91 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Thu, 30 Jan 2025 18:14:56 +0530 Subject: [PATCH 14/50] Slight imporvements and fix always failing test code. --- src/wallet/wallet2.cpp | 20 ++++++++--- src/wallet/wallet2.h | 2 +- tests/unit_tests/uri.cpp | 73 +++++++++++++++++++++++++++------------- 3 files changed, 65 insertions(+), 30 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 6cfbc9f5518..23277aec3bb 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14944,12 +14944,17 @@ std::string wallet2::decrypt_with_view_secret_key(const std::string &ciphertext, //---------------------------------------------------------------------------------------------------- std::string wallet2::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const { + if (data.empty()) + { + error = "No recipient data provided."; + return std::string(); + } std::string addresses = ""; std::string amounts = ""; bool amounts_used = false; std::string recipients = ""; bool recipients_used = false; - for (uri_data entry : data) + for (const uri_data& entry : data) { cryptonote::address_parse_info info; if(!get_account_address_from_str(info, nettype(), entry.address)) @@ -15036,8 +15041,15 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std std::vector addresses, recipient_names; std::vector amounts; boost::split(addresses, addresses_string, boost::is_any_of(";")); + addresses.erase(std::remove(addresses.begin(), addresses.end(), ""), addresses.end()); - for (const std::string &address : addresses) + if (addresses.empty()) + { + error = "No addresses specified in URI."; + return false; + } + + for (const std::string& address : addresses) { cryptonote::address_parse_info info; if(!get_account_address_from_str(info, nettype(), address)) @@ -15128,7 +15140,6 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std error = "Incorrect amount count. If an amount is assigned there should be an entry for each recipient. zero may be use as a filler"; return false; } - for(size_t i = 0; i < data.size(); i++) { if (!amounts.empty()) @@ -15140,10 +15151,9 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std data[i].recipient_name = recipient_names[i]; } } - return true; } - +//---------------------------------------------------------------------------------------------------- bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) { std::vector data; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index ffd56e76e81..60b48814d8a 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -874,7 +874,7 @@ namespace tools struct uri_data { std::string address; - uint64_t amount; + uint64_t amount = 0; std::string recipient_name; }; diff --git a/tests/unit_tests/uri.cpp b/tests/unit_tests/uri.cpp index 1992ab7af5f..4c801586c3b 100644 --- a/tests/unit_tests/uri.cpp +++ b/tests/unit_tests/uri.cpp @@ -41,6 +41,14 @@ bool ret = w.parse_uri(uri, address, payment_id, amount, description, recipient_name, unknown_parameters, error); \ ASSERT_EQ(ret, expected); +#define PARSE_URI_MULTI(uri, expected) \ + std::vector data; \ + std::string payment_id, description, error; \ + std::vector unknown_parameters; \ + tools::wallet2 w(cryptonote::TESTNET); \ + bool ret = w.parse_uri(uri, data, payment_id, description, unknown_parameters, error); \ + ASSERT_EQ(ret, expected); + TEST(uri, empty_string) { PARSE_URI("", false); @@ -213,78 +221,95 @@ TEST(uri, url_encoded_once) ASSERT_EQ(description, "foo 20"); } + TEST(uri, multiple_addresses_no_params) { - PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS, true); - ASSERT_EQ(address, TEST_ADDRESS); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS, true); + ASSERT_EQ(data.size(), 2); + ASSERT_EQ(data[0].address, TEST_ADDRESS); + ASSERT_EQ(data[1].address, TEST_ADDRESS); } TEST(uri, multiple_addresses_with_amounts) { - PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000;200000000000", true); - ASSERT_EQ(address, TEST_ADDRESS); - ASSERT_EQ(amount, 500000000000); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000;200000000000", true); + ASSERT_EQ(data.size(), 2); + ASSERT_EQ(data[0].address, TEST_ADDRESS); + ASSERT_EQ(data[0].amount, 500000000000); + ASSERT_EQ(data[1].address, TEST_ADDRESS); + ASSERT_EQ(data[1].amount, 200000000000); } TEST(uri, multiple_addresses_with_recipient_names) { - PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice;Bob", true); - ASSERT_EQ(address, TEST_ADDRESS); - ASSERT_EQ(recipient_name, "Alice"); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice;Bob", true); + ASSERT_EQ(data.size(), 2); + ASSERT_EQ(data[0].address, TEST_ADDRESS); + ASSERT_EQ(data[0].recipient_name, "Alice"); + ASSERT_EQ(data[1].address, TEST_ADDRESS); + ASSERT_EQ(data[1].recipient_name, "Bob"); } TEST(uri, multiple_addresses_with_mismatched_amounts) { - PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000", false); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000", false); } TEST(uri, multiple_addresses_with_mismatched_recipient_names) { - PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice", false); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice", false); } TEST(uri, multiple_addresses_with_partial_params) { - PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000;0&recipient_name=Alice;", true); - ASSERT_EQ(address, TEST_ADDRESS); - ASSERT_EQ(amount, 500000000000); - ASSERT_EQ(recipient_name, "Alice"); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000;0&recipient_name=Alice;", true); + ASSERT_EQ(data.size(), 2); + ASSERT_EQ(data[0].address, TEST_ADDRESS); + ASSERT_EQ(data[0].amount, 500000000000); + ASSERT_EQ(data[0].recipient_name, "Alice"); + ASSERT_EQ(data[1].address, TEST_ADDRESS); + ASSERT_EQ(data[1].amount, 0); + ASSERT_EQ(data[1].recipient_name, ""); } TEST(uri, multiple_addresses_with_unknown_params) { - PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?unknown_param=123;456", true); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?unknown_param=123;456", true); ASSERT_EQ(unknown_parameters.size(), 1); ASSERT_EQ(unknown_parameters[0], "unknown_param=123;456"); } TEST(uri, multiple_addresses_with_payment_id) { - PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=1234567890123456789012345678901234567890123456789012345678901234", true); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=1234567890123456789012345678901234567890123456789012345678901234", true); ASSERT_EQ(payment_id, "1234567890123456789012345678901234567890123456789012345678901234"); } TEST(uri, multiple_addresses_with_invalid_payment_id) { - PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=123456", false); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=123456", false); } TEST(uri, multiple_addresses_with_description) { - PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_description=Payment%20for%20services", true); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_description=Payment%20for%20services", true); ASSERT_EQ(description, "Payment for services"); } TEST(uri, multiple_addresses_mismatched_params) { - PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000&recipient_name=Alice", false); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000&recipient_name=Alice", false); } TEST(uri, multiple_addresses_all_params_correct) { - PARSE_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000;200000000000&recipient_name=Alice;Bob&tx_description=Payment%20for%20services", true); - ASSERT_EQ(address, TEST_ADDRESS); - ASSERT_EQ(amount, 500000000000); - ASSERT_EQ(recipient_name, "Alice"); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000;200000000000&recipient_name=Alice;Bob&tx_description=Payment%20for%20services", true); + ASSERT_EQ(data.size(), 2); + ASSERT_EQ(data[0].address, TEST_ADDRESS); + ASSERT_EQ(data[0].amount, 500000000000); + ASSERT_EQ(data[0].recipient_name, "Alice"); + ASSERT_EQ(data[1].address, TEST_ADDRESS); + ASSERT_EQ(data[1].amount, 200000000000); + ASSERT_EQ(data[1].recipient_name, "Bob"); ASSERT_EQ(description, "Payment for services"); -} +} \ No newline at end of file From dab6fe2c7e67ffe0796de5fc69d6d0ff50b39739 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Thu, 30 Jan 2025 20:52:44 +0530 Subject: [PATCH 15/50] Fix tests that were using atomic units in URL. Add parameter consistency checks and improve error messages. --- src/wallet/wallet2.cpp | 25 ++++++++++++++++++++++--- tests/unit_tests/uri.cpp | 10 +++++----- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 23277aec3bb..401b8c76be0 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14972,7 +14972,7 @@ std::string wallet2::make_uri(std::vector data, const std::string &pay addresses += ";"; } addresses += entry.address; - + if (!amounts.empty()) { amounts += ";"; @@ -15090,6 +15090,16 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std { std::vector amounts_split; boost::split(amounts_split, kv[1], boost::is_any_of(";")); + size_t expected_size = addresses.size(); + + // enforce parameter consistency + if (amounts_split.size() != expected_size) + { + error = "Incorrect tx_amount count"; + return false; + } + + for (size_t i = 0; i < amounts_split.size(); i++) { uint64_t amount; @@ -15115,6 +15125,15 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std { std::vector names_split; boost::split(names_split, kv[1], boost::is_any_of(";")); + size_t expected_size = addresses.size(); + + // enforce parameter consistency + if (names_split.size() != expected_size) + { + error = "Incorrect recipient_name count"; + return false; + } + for (size_t i = 0; i < names_split.size(); i++) { recipient_names.push_back(epee::net_utils::convert_from_url_format(names_split[i])); @@ -15132,12 +15151,12 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std if (!recipient_names.empty() && recipient_names.size() != addresses.size()) { - error = "Incorrect recipient name count. If a recipient name is assigned there should be an entry for each recipient."; + error = "Incorrect recipient name count. Recipient name count must match address count"; return false; } if (!amounts.empty() && amounts.size() != addresses.size()) { - error = "Incorrect amount count. If an amount is assigned there should be an entry for each recipient. zero may be use as a filler"; + error = "Incorrect amount count. Amount count must match address count. Zero may be use as a filler"; return false; } for(size_t i = 0; i < data.size(); i++) diff --git a/tests/unit_tests/uri.cpp b/tests/unit_tests/uri.cpp index 4c801586c3b..2322464b6c3 100644 --- a/tests/unit_tests/uri.cpp +++ b/tests/unit_tests/uri.cpp @@ -232,7 +232,7 @@ TEST(uri, multiple_addresses_no_params) TEST(uri, multiple_addresses_with_amounts) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000;200000000000", true); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0.2", true); ASSERT_EQ(data.size(), 2); ASSERT_EQ(data[0].address, TEST_ADDRESS); ASSERT_EQ(data[0].amount, 500000000000); @@ -252,7 +252,7 @@ TEST(uri, multiple_addresses_with_recipient_names) TEST(uri, multiple_addresses_with_mismatched_amounts) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000", false); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5", false); } TEST(uri, multiple_addresses_with_mismatched_recipient_names) @@ -262,7 +262,7 @@ TEST(uri, multiple_addresses_with_mismatched_recipient_names) TEST(uri, multiple_addresses_with_partial_params) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000;0&recipient_name=Alice;", true); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0&recipient_name=Alice;", true); ASSERT_EQ(data.size(), 2); ASSERT_EQ(data[0].address, TEST_ADDRESS); ASSERT_EQ(data[0].amount, 500000000000); @@ -298,12 +298,12 @@ TEST(uri, multiple_addresses_with_description) TEST(uri, multiple_addresses_mismatched_params) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000&recipient_name=Alice", false); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5&recipient_name=Alice", false); } TEST(uri, multiple_addresses_all_params_correct) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=500000000000;200000000000&recipient_name=Alice;Bob&tx_description=Payment%20for%20services", true); + PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0.2&recipient_name=Alice;Bob&tx_description=Payment%20for%20services", true); ASSERT_EQ(data.size(), 2); ASSERT_EQ(data[0].address, TEST_ADDRESS); ASSERT_EQ(data[0].amount, 500000000000); From 20e6095ad01dce1c3e8c0a5608a639385b1129cb Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Fri, 31 Jan 2025 21:30:35 +0530 Subject: [PATCH 16/50] Fix failing python functional tests --- tests/functional_tests/uri.py | 275 +++++++++++++++++---------- utils/python-rpc/framework/wallet.py | 20 +- 2 files changed, 186 insertions(+), 109 deletions(-) diff --git a/tests/functional_tests/uri.py b/tests/functional_tests/uri.py index fb981b3fdc7..ca5df862e4e 100755 --- a/tests/functional_tests/uri.py +++ b/tests/functional_tests/uri.py @@ -43,7 +43,8 @@ class URITest(): def run_test(self): self.create() self.test_monero_uri() - + self.test_multi_uri() + def create(self): print('Creating wallet') wallet = Wallet() @@ -63,111 +64,95 @@ def test_monero_uri(self): quoted_utf8string = [urllib_quote(x.encode('utf8')) for x in utf8string] ok = False - try: res = wallet.make_uri() + try: res = wallet.make_uri(payments=[{}]) # no address except: ok = True assert ok + ok = False - try: res = wallet.make_uri(address = '') - except: ok = True - assert ok - ok = False - try: res = wallet.make_uri(address = 'kjshdkj') + try: res = wallet.make_uri(payments=[{'address': 'kjshdkj'}]) # invalid address except: ok = True assert ok + # single payment tests for address in [ '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', '4BxSHvcgTwu25WooY4BVmgdcKwZu5EksVZSZkDd6ooxSVVqQ4ubxXkhLF6hEqtw96i9cf3cVfLw8UWe95bdDKfRQeYtPwLm1Jiw7AKt2LY', '8AsN91rznfkBGTY8psSNkJBg9SZgxxGGRUhGwRptBhgr5XSQ1XzmA9m8QAnoxydecSh5aLJXdrgXwTDMMZ1AuXsN1EX5Mtm' ]: - res = wallet.make_uri(address = address) + # basic address + res = wallet.make_uri(payments=[{'address': address}]) assert res.uri == 'monero:' + address - res = wallet.parse_uri(res.uri) - assert res.uri.address == address - assert res.uri.payment_id == '' - assert res.uri.amount == 0 - assert res.uri.tx_description == '' - assert res.uri.recipient_name == '' - assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 - res = wallet.make_uri(address = address, amount = 11000000000) - assert res.uri == 'monero:' + address + '?tx_amount=0.011' or res.uri == 'monero:' + address + '?tx_amount=0.011000000000' - res = wallet.parse_uri(res.uri) - assert res.uri.address == address - assert res.uri.payment_id == '' - assert res.uri.amount == 11000000000 - assert res.uri.tx_description == '' - assert res.uri.recipient_name == '' - assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 + parsed = wallet.parse_uri(res.uri) + assert len(parsed.uri['payments']) == 1 + assert parsed.uri['payments'][0]['address'] == address + assert parsed.uri['payments'][0]['amount'] == 0 + assert parsed.uri['payment_id'] == '' + assert parsed.uri['tx_description'] == '' + # with amount + res = wallet.make_uri(payments=[{ + 'address': address, + 'amount': 11000000000 + }]) + assert 'tx_amount=0.011' in res.uri or 'tx_amount=0.011000000000' in res.uri + parsed = wallet.parse_uri(res.uri) + assert parsed.uri['payments'][0]['amount'] == 11000000000 + address = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' - res = wallet.make_uri(address = address, tx_description = utf8string[0]) - assert res.uri == 'monero:' + address + '?tx_description=' + quoted_utf8string[0] - res = wallet.parse_uri(res.uri) - assert res.uri.address == address - assert res.uri.payment_id == '' - assert res.uri.amount == 0 - assert res.uri.tx_description == utf8string[0] - assert res.uri.recipient_name == '' - assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 - - res = wallet.make_uri(address = address, recipient_name = utf8string[0]) - assert res.uri == 'monero:' + address + '?recipient_name=' + quoted_utf8string[0] - res = wallet.parse_uri(res.uri) - assert res.uri.address == address - assert res.uri.payment_id == '' - assert res.uri.amount == 0 - assert res.uri.tx_description == '' - assert res.uri.recipient_name == utf8string[0] - assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 - - res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1]) - assert res.uri == 'monero:' + address + '?recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1] - res = wallet.parse_uri(res.uri) - assert res.uri.address == address - assert res.uri.payment_id == '' - assert res.uri.amount == 0 - assert res.uri.tx_description == utf8string[1] - assert res.uri.recipient_name == utf8string[0] - assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 - - res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1], amount = 1000000000000) - assert res.uri == 'monero:' + address + '?tx_amount=1.000000000000&recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1] - res = wallet.parse_uri(res.uri) - assert res.uri.address == address - assert res.uri.payment_id == '' - assert res.uri.amount == 1000000000000 - assert res.uri.tx_description == utf8string[1] - assert res.uri.recipient_name == utf8string[0] - assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 + # test desc + res = wallet.make_uri( + payments=[{'address': address}], + tx_description=utf8string[0] + ) + assert 'tx_description=' + quoted_utf8string[0] in res.uri + parsed = wallet.parse_uri(res.uri) + assert parsed.uri['tx_description'] == utf8string[0] - # external payment ids are not supported anymore + # test recipient name in payment entry + res = wallet.make_uri(payments=[{ + 'address': address, + 'recipient_name': utf8string[0] + }]) + assert 'recipient_name=' + quoted_utf8string[0] in res.uri + parsed = wallet.parse_uri(res.uri) + assert parsed.uri['payments'][0]['recipient_name'] == utf8string[0] + + # combined parameters + res = wallet.make_uri( + payments=[{ + 'address': address, + 'amount': 1000000000000, + 'recipient_name': utf8string[0] + }], + tx_description=utf8string[1] + ) + parsed = wallet.parse_uri(res.uri) + assert parsed.uri['payments'][0]['amount'] == 1000000000000 + assert parsed.uri['payments'][0]['recipient_name'] == utf8string[0] + assert parsed.uri['tx_description'] == utf8string[1] + + # test payment ID rejection ok = False - try: res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1], amount = 1000000000000, payment_id = '1' * 64) + try: + wallet.make_uri( + payments=[{'address': address}], + payment_id='1' * 64 + ) except: ok = True assert ok - # spaces must be encoded as %20 - res = wallet.make_uri(address = address, tx_description = ' ' + utf8string[1] + ' ' + utf8string[0] + ' ', amount = 1000000000000) - assert res.uri == 'monero:' + address + '?tx_amount=1.000000000000&tx_description=%20' + quoted_utf8string[1] + '%20' + quoted_utf8string[0] + '%20' - res = wallet.parse_uri(res.uri) - assert res.uri.address == address - assert res.uri.payment_id == '' - assert res.uri.amount == 1000000000000 - assert res.uri.tx_description == ' ' + utf8string[1] + ' ' + utf8string[0] + ' ' - assert res.uri.recipient_name == '' - assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 - - # the example from the docs + # notes: spaces must be encoded as %20 + # external payment ids are not supported anymore + # test URI parsing from docs res = wallet.parse_uri('monero:46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em?tx_amount=239.39014&tx_description=donation') - assert res.uri.address == '46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em' - assert res.uri.amount == 239390140000000 - assert res.uri.tx_description == 'donation' - assert res.uri.recipient_name == '' - assert res.uri.payment_id == '' - assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 - - # malformed/invalid + assert len(res.uri['payments']) == 1 + assert res.uri['payments'][0]['address'] == '46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em' + assert res.uri['payments'][0]['amount'] == 239390140000000 + assert res.uri['tx_description'] == 'donation' + + + # test malformed/invalid URIs for uri in [ '', ':', @@ -203,26 +188,108 @@ def test_monero_uri(self): ok = False try: res = wallet.parse_uri(uri) except: ok = True - assert ok, res - - # unknown parameters but otherwise valid - res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&foo=bar') - assert res.uri.address == address - assert res.uri.amount == 239390140000000 - assert res.unknown_parameters == ['foo=bar'], res - res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&foo=bar&baz=quux') - assert res.uri.address == address - assert res.uri.amount == 239390140000000 - assert res.unknown_parameters == ['foo=bar', 'baz=quux'], res - res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&%20=%20') - assert res.uri.address == address - assert res.uri.amount == 239390140000000 - assert res.unknown_parameters == ['%20=%20'], res - res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&unknown=' + quoted_utf8string[0]) - assert res.uri.address == address - assert res.uri.amount == 239390140000000 - assert res.unknown_parameters == [u'unknown=' + quoted_utf8string[0]], res + assert ok, f"Failed to reject invalid URI: {uri}" + + # unknown parameter tests for single URI: unknown parameters but otherwise valid + print('Testing unknown parameters in single-URI') + test_cases = [ + ('monero:' + address + '?tx_amount=239.39014&foo=bar', ['foo=bar']), + ('monero:' + address + '?tx_amount=239.39014&foo=bar&baz=quux', ['foo=bar', 'baz=quux']), + ('monero:' + address + '?tx_amount=239.39014&%20=%20', ['%20=%20']), + ('monero:' + address + '?tx_amount=239.39014&unknown=' + quoted_utf8string[0], + [u'unknown=' + quoted_utf8string[0]]) + ] + + for uri, expected_unknown in test_cases: + res = wallet.parse_uri(uri) + assert len(res.uri['payments']) == 1, "Should have single payment" + assert res.uri['payments'][0]['address'] == address + assert res.uri['payments'][0]['amount'] == 239390140000000 + assert res.unknown_parameters == expected_unknown, \ + f"Unexpected unknown params: {res.unknown_parameters}" + +def test_multi_uri(self): + print('Testing multi-recipient URIs') + wallet = Wallet() + address1 = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' + address2 = '4BxSHvcgTwu25WooY4BVmgdcKwZu5EksVZSZkDd6ooxSVVqQ4ubxXkhLF6hEqtw96i9cf3cVfLw8UWe95bdDKfRQeYtPwLm1Jiw7AKt2LY' + utf8string = [u'えんしゅう', u'あまやかす'] + quoted_utf8string = [urllib_quote(x.encode('utf8')) for x in utf8string] + + # multi-URI unknown parameter tests + print('Testing unknown parameters in multi-URI') + multi_uri_cases = [ + ( + f'monero:{address1};{address2}?tx_amount=0.5;0.2&foo=bar', + {'addresses': [address1, address2], 'amounts': [500000000000, 200000000000]}, + ['foo=bar'] + ), + ( + f'monero:{address1};{address2}?tx_amount=1.0;0&recipient_name=Alice;&unknown_param=123', + {'addresses': [address1, address2], 'amounts': [1000000000000, 0], 'names': ['Alice', '']}, + ['unknown_param=123'] + ), + ( + f'monero:{address1};{address2}?tx_description=Test&unknown1=val1&unknown2=val2', + {'addresses': [address1, address2], 'description': 'Test'}, + ['unknown1=val1', 'unknown2=val2'] + ), + ( + f'monero:{address1};{address2}?recipient_name=Name1;Name2&tx_amount=0.1;0.2&special=%40%24%5E', + {'addresses': [address1, address2], 'amounts': [100000000000, 200000000000], 'names': ['Name1', 'Name2']}, + ['special=%40%24%5E'] + ) + ] + + for uri, expected, expected_unknown in multi_uri_cases: + res = wallet.parse_uri(uri) + + # verify payment count + assert len(res.uri['payments']) == len(expected['addresses']), \ + f"Expected {len(expected['addresses'])} payments, got {len(res.uri['payments'])}" + + # check addresses and amounts + for i, payment in enumerate(res.uri['payments']): + assert payment['address'] == expected['addresses'][i], \ + f"Address mismatch at position {i}" + + if 'amounts' in expected: + assert payment['amount'] == expected['amounts'][i], \ + f"Amount mismatch at position {i}" + + if 'names' in expected: + assert payment['recipient_name'] == expected['names'][i], \ + f"Name mismatch at position {i}" + + # check desc + if 'description' in expected: + assert res.uri['tx_description'] == expected['description'], \ + "Description mismatch" + + # verify unknown parameters + assert res.unknown_parameters == expected_unknown, \ + f"Unknown params mismatch. Expected {expected_unknown}, got {res.unknown_parameters}" + + # test mixed parameter positions + res = wallet.parse_uri( + f'monero:{address1};{address2}?unknown_first=123&tx_amount=0.1;0.2&unknown_last=456' + ) + assert res.unknown_parameters == ['unknown_first=123', 'unknown_last=456'] + assert len(res.uri['payments']) == 2 + assert res.uri['payments'][0]['amount'] == 100000000000 + assert res.uri['payments'][1]['amount'] == 200000000000 + + # test special characters in unknown params + special_uri = f'monero:{address1};{address2}?weird_param={quoted_utf8string[0]}&tx_amount=1;2' + res = wallet.parse_uri(special_uri) + assert res.unknown_parameters == [u'weird_param=' + quoted_utf8string[0]] + assert res.uri['payments'][0]['amount'] == 1000000000000 + assert res.uri['payments'][1]['amount'] == 2000000000000 + # test multiple unknown params with same key + res = wallet.parse_uri(f'monero:{address1}?tx_amount=1&flag=1&flag=2') + assert res.unknown_parameters == ['flag=1', 'flag=2'] + assert res.uri['payments'][0]['amount'] == 1000000000000 if __name__ == '__main__': diff --git a/utils/python-rpc/framework/wallet.py b/utils/python-rpc/framework/wallet.py index 0753b4fd4ad..f6ef758ec53 100644 --- a/utils/python-rpc/framework/wallet.py +++ b/utils/python-rpc/framework/wallet.py @@ -987,21 +987,31 @@ def get_attribute(self, key): } return self.rpc.send_json_rpc_request(get_attribute) - def make_uri(self, address = '', payment_id = '', amount = 0, tx_description = '', recipient_name = ''): + def make_uri(self, payments, payment_id='', tx_description=''): make_uri = { 'method': 'make_uri', 'jsonrpc': '2.0', 'params': { - 'address': address, + 'payments': payments, 'payment_id': payment_id, - 'amount': amount, 'tx_description': tx_description, - 'recipient_name': recipient_name, }, 'id': '0' } return self.rpc.send_json_rpc_request(make_uri) - + + def legacy_make_uri(self, address='', payment_id='', amount=0, tx_description='', recipient_name=''): + """For backward compatibility with single-payment URIs""" + return self.make_uri( + payments=[{ + 'address': address, + 'amount': amount, + 'recipient_name': recipient_name + }], + payment_id=payment_id, + tx_description=tx_description + ) + def parse_uri(self, uri): parse_uri = { 'method': 'parse_uri', From 546fb29286732afc99ac3c6705abed341d1f6a87 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Fri, 31 Jan 2025 23:45:01 +0530 Subject: [PATCH 17/50] fix improper size calc --- src/wallet/wallet2.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 401b8c76be0..dd6c7489cd6 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -6236,6 +6236,9 @@ std::string wallet2::make_background_keys_file_name(const std::string &wallet_fi //---------------------------------------------------------------------------------------------------- bool wallet2::parse_long_payment_id(const std::string& payment_id_str, crypto::hash& payment_id) { + if (payment_id_str.size() != 64) + return false; + cryptonote::blobdata payment_id_data; if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data)) return false; @@ -15113,6 +15116,7 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std } else if (kv[0] == "tx_payment_id") { + // standalone payment ids are deprecated. use integrated address crypto::hash hash; if (!wallet2::parse_long_payment_id(kv[1], hash)) { From 993ebfc3d7975a04ef96947cc2499cadd11599b6 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Sat, 1 Feb 2025 23:24:46 +0530 Subject: [PATCH 18/50] Move overloads to wallet2.cpp. Introduce backwards compatibility in wallet.py for handling both new and old formats plus rewrite uri.py to handle tests properly. Rewrite was necessary to remove all broken tests written previously, restore the file and modify the way it accesses data (the structure is different). --- src/wallet/api/wallet.cpp | 34 +-- src/wallet/wallet2.cpp | 22 +- tests/functional_tests/uri.py | 356 +++++++++++++++------------ utils/python-rpc/framework/wallet.py | 42 +++- 4 files changed, 255 insertions(+), 199 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 63fe95b070d..cb44fd3bae8 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2548,35 +2548,23 @@ bool WalletImpl::checkBackgroundSync(const std::string &message) const return false; } -bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) +bool WalletImpl::parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) { - std::vector data; - if (!m_wallet->parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error)) - { - setStatusError(tr("Failed to parse uri")); - return false; - } - if (data.size() > 1) - { - setStatusError(tr("Multi-recipient URIs currently unsupported")); - return false; - } - address = data[0].address; - amount = data[0].amount; - recipient_name = data[0].recipient_name; - return true; + return m_wallet->parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error) } -std::string WalletImpl::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const +bool WalletImpl::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) { - tools::wallet2::uri_data entry; - entry.address = address; - entry.amount = amount; - entry.recipient_name = recipient_name; + return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error); +} - std::vector data; - data.push_back(entry); +std::string WalletImpl::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const +{ + return m_wallet->make_uri(address, payment_id, amount, tx_description, recipient_name, error); +} +std::string WalletImpl::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const +{ return m_wallet->make_uri(data, payment_id, tx_description, error); } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index dd6c7489cd6..4deb67e5061 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -6236,9 +6236,6 @@ std::string wallet2::make_background_keys_file_name(const std::string &wallet_fi //---------------------------------------------------------------------------------------------------- bool wallet2::parse_long_payment_id(const std::string& payment_id_str, crypto::hash& payment_id) { - if (payment_id_str.size() != 64) - return false; - cryptonote::blobdata payment_id_data; if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data)) return false; @@ -15030,6 +15027,19 @@ std::string wallet2::make_uri(std::vector data, const std::string &pay return uri; } //---------------------------------------------------------------------------------------------------- +std::string wallet2::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const +{ + tools::wallet2::uri_data entry; + entry.address = address; + entry.amount = amount; + entry.recipient_name = recipient_name; + + std::vector data; + data.push_back(entry); + + return make_uri(data, payment_id, tx_description, error); +} +//---------------------------------------------------------------------------------------------------- bool wallet2::parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) { if (uri.substr(0, 7) != "monero:") @@ -15117,6 +15127,11 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std else if (kv[0] == "tx_payment_id") { // standalone payment ids are deprecated. use integrated address + error = "Standalone payment id deprecated, use integrated address instead"; + return false; + + /* + // Commenting this code to save for any unforeseen future use. crypto::hash hash; if (!wallet2::parse_long_payment_id(kv[1], hash)) { @@ -15124,6 +15139,7 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std return false; } payment_id = kv[1]; + */ } else if (kv[0] == "recipient_name") { diff --git a/tests/functional_tests/uri.py b/tests/functional_tests/uri.py index ca5df862e4e..14fe217a60c 100755 --- a/tests/functional_tests/uri.py +++ b/tests/functional_tests/uri.py @@ -43,8 +43,7 @@ class URITest(): def run_test(self): self.create() self.test_monero_uri() - self.test_multi_uri() - + def create(self): print('Creating wallet') wallet = Wallet() @@ -64,95 +63,113 @@ def test_monero_uri(self): quoted_utf8string = [urllib_quote(x.encode('utf8')) for x in utf8string] ok = False - try: res = wallet.make_uri(payments=[{}]) # no address + try: res = wallet.make_uri() except: ok = True assert ok - ok = False - try: res = wallet.make_uri(payments=[{'address': 'kjshdkj'}]) # invalid address + try: res = wallet.make_uri(address = '') + except: ok = True + assert ok + ok = False + try: res = wallet.make_uri(address = 'kjshdkj') except: ok = True assert ok - # single payment tests for address in [ '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', '4BxSHvcgTwu25WooY4BVmgdcKwZu5EksVZSZkDd6ooxSVVqQ4ubxXkhLF6hEqtw96i9cf3cVfLw8UWe95bdDKfRQeYtPwLm1Jiw7AKt2LY', '8AsN91rznfkBGTY8psSNkJBg9SZgxxGGRUhGwRptBhgr5XSQ1XzmA9m8QAnoxydecSh5aLJXdrgXwTDMMZ1AuXsN1EX5Mtm' ]: - # basic address - res = wallet.make_uri(payments=[{'address': address}]) + res = wallet.make_uri(address = address) assert res.uri == 'monero:' + address - parsed = wallet.parse_uri(res.uri) - assert len(parsed.uri['payments']) == 1 - assert parsed.uri['payments'][0]['address'] == address - assert parsed.uri['payments'][0]['amount'] == 0 - assert parsed.uri['payment_id'] == '' - assert parsed.uri['tx_description'] == '' + res = wallet.parse_uri(res.uri) + assert res.uri.payments[0].address == address + assert res.uri.payments[0].amount == 0 + assert res.uri.payments[0].recipient_name == '' + assert res.uri.payment_id == '' + assert res.uri.tx_description == '' + + assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 + res = wallet.make_uri(address = address, amount = 11000000000) + assert res.uri == 'monero:' + address + '?tx_amount=0.011' or res.uri == 'monero:' + address + '?tx_amount=0.011000000000' + res = wallet.parse_uri(res.uri) + assert res.uri.payments[0].address == address + assert res.uri.payments[0].amount == 11000000000 + assert res.uri.payments[0].recipient_name == '' + assert res.uri.payment_id == '' + assert res.uri.tx_description == '' + assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 - # with amount - res = wallet.make_uri(payments=[{ - 'address': address, - 'amount': 11000000000 - }]) - assert 'tx_amount=0.011' in res.uri or 'tx_amount=0.011000000000' in res.uri - parsed = wallet.parse_uri(res.uri) - assert parsed.uri['payments'][0]['amount'] == 11000000000 - address = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' - # test desc - res = wallet.make_uri( - payments=[{'address': address}], - tx_description=utf8string[0] - ) - assert 'tx_description=' + quoted_utf8string[0] in res.uri - parsed = wallet.parse_uri(res.uri) - assert parsed.uri['tx_description'] == utf8string[0] + res = wallet.make_uri(address = address, tx_description = utf8string[0]) + assert res.uri == 'monero:' + address + '?tx_description=' + quoted_utf8string[0] + res = wallet.parse_uri(res.uri) + assert res.uri.payments[0].address == address + assert res.uri.payments[0].amount == 0 + assert res.uri.payments[0].recipient_name == '' + assert res.uri.payment_id == '' + assert res.uri.tx_description == utf8string[0] + assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 + + res = wallet.make_uri(address = address, recipient_name = utf8string[0]) + assert res.uri == 'monero:' + address + '?recipient_name=' + quoted_utf8string[0] + res = wallet.parse_uri(res.uri) + assert res.uri.payments[0].address == address + assert res.uri.payments[0].amount == 0 + assert res.uri.payments[0].recipient_name == utf8string[0] + assert res.uri.payment_id == '' + assert res.uri.tx_description == '' + assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 - # test recipient name in payment entry - res = wallet.make_uri(payments=[{ - 'address': address, - 'recipient_name': utf8string[0] - }]) - assert 'recipient_name=' + quoted_utf8string[0] in res.uri - parsed = wallet.parse_uri(res.uri) - assert parsed.uri['payments'][0]['recipient_name'] == utf8string[0] + res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1]) + assert res.uri == 'monero:' + address + '?recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1] + res = wallet.parse_uri(res.uri) + assert res.uri.payments[0].address == address + assert res.uri.payments[0].amount == 0 + assert res.uri.payments[0].recipient_name == utf8string[0] + assert res.uri.payment_id == '' + assert res.uri.tx_description == utf8string[1] + assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 - # combined parameters - res = wallet.make_uri( - payments=[{ - 'address': address, - 'amount': 1000000000000, - 'recipient_name': utf8string[0] - }], - tx_description=utf8string[1] - ) - parsed = wallet.parse_uri(res.uri) - assert parsed.uri['payments'][0]['amount'] == 1000000000000 - assert parsed.uri['payments'][0]['recipient_name'] == utf8string[0] - assert parsed.uri['tx_description'] == utf8string[1] + res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1], amount = 1000000000000) + assert res.uri == 'monero:' + address + '?tx_amount=1.000000000000&recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1] + res = wallet.parse_uri(res.uri) + assert res.uri.payments[0].address == address + assert res.uri.payments[0].amount == 1000000000000 + assert res.uri.payments[0].recipient_name == utf8string[0] + assert res.uri.payment_id == '' + assert res.uri.tx_description == utf8string[1] + assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 - # test payment ID rejection + # external payment ids are not supported anymore ok = False - try: - wallet.make_uri( - payments=[{'address': address}], - payment_id='1' * 64 - ) + try: res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1], amount = 1000000000000, payment_id = '1' * 64) except: ok = True assert ok - # notes: spaces must be encoded as %20 - # external payment ids are not supported anymore - # test URI parsing from docs - res = wallet.parse_uri('monero:46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em?tx_amount=239.39014&tx_description=donation') - assert len(res.uri['payments']) == 1 - assert res.uri['payments'][0]['address'] == '46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em' - assert res.uri['payments'][0]['amount'] == 239390140000000 - assert res.uri['tx_description'] == 'donation' + # spaces must be encoded as %20 + res = wallet.make_uri(address = address, tx_description = ' ' + utf8string[1] + ' ' + utf8string[0] + ' ', amount = 1000000000000) + assert res.uri == 'monero:' + address + '?tx_amount=1.000000000000&tx_description=%20' + quoted_utf8string[1] + '%20' + quoted_utf8string[0] + '%20' + res = wallet.parse_uri(res.uri) + assert res.uri.payments[0].address == address + assert res.uri.payments[0].amount == 1000000000000 + assert res.uri.payments[0].recipient_name == '' + assert res.uri.payment_id == '' + assert res.uri.tx_description == ' ' + utf8string[1] + ' ' + utf8string[0] + ' ' + assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 + # the example from the docs + res = wallet.parse_uri('monero:46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em?tx_amount=239.39014&tx_description=donation') + assert res.uri.payments[0].address == '46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em' + assert res.uri.payments[0].amount == 239390140000000 + assert res.uri.payments[0].recipient_name == '' + assert res.uri.tx_description == 'donation' + + assert res.uri.payment_id == '' + assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 - # test malformed/invalid URIs + # malformed/invalid for uri in [ '', ':', @@ -188,109 +205,128 @@ def test_monero_uri(self): ok = False try: res = wallet.parse_uri(uri) except: ok = True - assert ok, f"Failed to reject invalid URI: {uri}" + assert ok, res - # unknown parameter tests for single URI: unknown parameters but otherwise valid - print('Testing unknown parameters in single-URI') - test_cases = [ - ('monero:' + address + '?tx_amount=239.39014&foo=bar', ['foo=bar']), - ('monero:' + address + '?tx_amount=239.39014&foo=bar&baz=quux', ['foo=bar', 'baz=quux']), - ('monero:' + address + '?tx_amount=239.39014&%20=%20', ['%20=%20']), - ('monero:' + address + '?tx_amount=239.39014&unknown=' + quoted_utf8string[0], - [u'unknown=' + quoted_utf8string[0]]) - ] + # unknown parameters but otherwise valid + res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&foo=bar') + assert res.uri.payments[0].address == address + assert res.uri.payments[0].amount == 239390140000000 + assert res.unknown_parameters == ['foo=bar'], res + res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&foo=bar&baz=quux') + assert res.uri.payments[0].address == address + assert res.uri.payments[0].amount == 239390140000000 + assert res.unknown_parameters == ['foo=bar', 'baz=quux'], res + res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&%20=%20') + assert res.uri.payments[0].address == address + assert res.uri.payments[0].amount == 239390140000000 + assert res.unknown_parameters == ['%20=%20'], res + res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&unknown=' + quoted_utf8string[0]) + assert res.uri.payments[0].address == address + assert res.uri.payments[0].amount == 239390140000000 + assert res.unknown_parameters == [u'unknown=' + quoted_utf8string[0]], res - for uri, expected_unknown in test_cases: - res = wallet.parse_uri(uri) - assert len(res.uri['payments']) == 1, "Should have single payment" - assert res.uri['payments'][0]['address'] == address - assert res.uri['payments'][0]['amount'] == 239390140000000 - assert res.unknown_parameters == expected_unknown, \ - f"Unexpected unknown params: {res.unknown_parameters}" - -def test_multi_uri(self): - print('Testing multi-recipient URIs') - wallet = Wallet() - address1 = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' - address2 = '4BxSHvcgTwu25WooY4BVmgdcKwZu5EksVZSZkDd6ooxSVVqQ4ubxXkhLF6hEqtw96i9cf3cVfLw8UWe95bdDKfRQeYtPwLm1Jiw7AKt2LY' + + def test_multi_uri(self): + print('Testing multi-recipient monero: URI') + addr1 = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' + addr2 = '4BxSHvcgTwu25WooY4BVmgdcKwZu5EksVZSZkDd6ooxSVVqQ4ubxXkhLF6hEqtw96i9cf3cVfLw8UWe95bdDKfRQeYtPwLm1Jiw7AKt2LY' + addr3 = '8AsN91rznfkBGTY8psSNkJBg9SZgxxGGRUhGwRptBhgr5XSQ1XzmA9m8QAnoxydecSh5aLJXdrgXwTDMMZ1AuXsN1EX5Mtm' utf8string = [u'えんしゅう', u'あまやかす'] quoted_utf8string = [urllib_quote(x.encode('utf8')) for x in utf8string] - # multi-URI unknown parameter tests - print('Testing unknown parameters in multi-URI') - multi_uri_cases = [ - ( - f'monero:{address1};{address2}?tx_amount=0.5;0.2&foo=bar', - {'addresses': [address1, address2], 'amounts': [500000000000, 200000000000]}, - ['foo=bar'] - ), - ( - f'monero:{address1};{address2}?tx_amount=1.0;0&recipient_name=Alice;&unknown_param=123', - {'addresses': [address1, address2], 'amounts': [1000000000000, 0], 'names': ['Alice', '']}, - ['unknown_param=123'] - ), - ( - f'monero:{address1};{address2}?tx_description=Test&unknown1=val1&unknown2=val2', - {'addresses': [address1, address2], 'description': 'Test'}, - ['unknown1=val1', 'unknown2=val2'] - ), - ( - f'monero:{address1};{address2}?recipient_name=Name1;Name2&tx_amount=0.1;0.2&special=%40%24%5E', - {'addresses': [address1, address2], 'amounts': [100000000000, 200000000000], 'names': ['Name1', 'Name2']}, - ['special=%40%24%5E'] - ) + # build multi-recipient URI with two payments. + payments = [ + {'address': addr1, 'amount': 500000000000, 'recipient_name': utf8string[0]}, + {'address': addr2, 'amount': 200000000000, 'recipient_name': utf8string[1]} ] + res = self.make_uri(payments=payments, payment_id='', tx_description='multi test') + # expect URI like: + # monero:addr1;addr2?tx_amount=0.5;0.2&recipient_name=;&tx_description=multi%20test + parsed = self.parse_uri(res.uri) + # verify that both payments are present. + assert len(parsed.uri.payments) == 2, "Expected 2 payments in multi-recipient URI" + assert parsed.uri.payments[0].address == addr1 + assert parsed.uri.payments[0].amount == 500000000000 + assert parsed.uri.payments[0].recipient_name == utf8string[0] + assert parsed.uri.payments[1].address == addr2 + assert parsed.uri.payments[1].amount == 200000000000 + assert parsed.uri.payments[1].recipient_name == utf8string[1] + # check tx_description at the top level. + assert parsed.uri.tx_description == 'multi test' + assert parsed.uri.payment_id == '' + + # build multi-recipient URI with three payments. + payments = [ + {'address': addr1, 'amount': 1000000000000, 'recipient_name': utf8string[0]}, + {'address': addr2, 'amount': 500000000000, 'recipient_name': utf8string[1]}, + {'address': addr3, 'amount': 250000000000, 'recipient_name': ''} + ] + res = self.make_uri(payments=payments, payment_id='', tx_description='three pay') + parsed = self.parse_uri(res.uri) + assert len(parsed.uri.payments) == 3, "Expected 3 payments in multi-recipient URI" + assert parsed.uri.payments[0].address == addr1 + assert parsed.uri.payments[0].amount == 1000000000000 + assert parsed.uri.payments[0].recipient_name == utf8string[0] + assert parsed.uri.payments[1].address == addr2 + assert parsed.uri.payments[1].amount == 500000000000 + assert parsed.uri.payments[1].recipient_name == utf8string[1] + assert parsed.uri.payments[2].address == addr3 + assert parsed.uri.payments[2].amount == 250000000000 + assert parsed.uri.payments[2].recipient_name == '' + assert parsed.uri.tx_description == 'three pay' + + payments = [ + {'address': addr1, 'amount': 500000000000, 'recipient_name': 'Alice'}, + {'address': addr2, 'amount': 0, 'recipient_name': 'Bob'} + ] + # manually build a URI with mismatched amounts (remove Bob's amount). + # we simulate this by concatenating amounts incorrectly. + # (this step assumes you have control over the output URI; in practice, the server would reject it. For testing, we assume the RPC returns an error.) + uri_bad = 'monero:' + addr1 + ';' + addr2 + '?tx_amount=0.5&recipient_name=Alice;Bob' + ok = False + try: + self.parse_uri(uri_bad) + except Exception: + ok = True + assert ok, "Expected rejection for mismatched payment counts" + + # case: trailing semicolon in addresses or parameters should be handled gracefully + uri_trailing = 'monero:' + addr1 + ';' + addr2 + ';' + '?tx_amount=0.5;0.2&recipient_name=Alice;Bob' + # depending on the implementation, a trailing empty value might be dropped. + parsed = self.parse_uri(uri_trailing) + assert len(parsed.uri.payments) == 2, "Trailing delimiter should not add empty payment" + + # case: special characters in recipient names and descriptions + special_name = "A&B=Test?" + special_desc = "Desc with spaces & symbols!" + payments = [ + {'address': addr1, 'amount': 750000000000, 'recipient_name': special_name}, + {'address': addr2, 'amount': 250000000000, 'recipient_name': special_name} + ] + + # the RPC should URL-encode these parameters. + res = self.make_uri(payments=payments, tx_description=special_desc) + parsed = self.parse_uri(res.uri) + # check that the decoded values match the original. + for pay in parsed.uri.payments: + assert pay.recipient_name == special_name, "Special characters in recipient name mismatch" + assert parsed.uri.tx_description == special_desc, "Special characters in description mismatch" + + # build a well-formed multi-recipient URI and tack on unknown parameters. + payments = [ + {'address': addr1, 'amount': 239390140000000, 'recipient_name': ''} + ] + uri_with_unknown = 'monero:' + addr1 + '?tx_amount=239.39014&foo=bar&baz=quux' + parsed = self.parse_uri(uri_with_unknown) + assert parsed.uri.payments[0].address == addr1 + assert parsed.uri.payments[0].amount == 239390140000000 + # unknown parameters should be collected in the unknown_parameters list. + assert parsed.unknown_parameters == ['foo=bar', 'baz=quux'], "Unknown parameters mismatch" - for uri, expected, expected_unknown in multi_uri_cases: - res = wallet.parse_uri(uri) - - # verify payment count - assert len(res.uri['payments']) == len(expected['addresses']), \ - f"Expected {len(expected['addresses'])} payments, got {len(res.uri['payments'])}" - - # check addresses and amounts - for i, payment in enumerate(res.uri['payments']): - assert payment['address'] == expected['addresses'][i], \ - f"Address mismatch at position {i}" - - if 'amounts' in expected: - assert payment['amount'] == expected['amounts'][i], \ - f"Amount mismatch at position {i}" - - if 'names' in expected: - assert payment['recipient_name'] == expected['names'][i], \ - f"Name mismatch at position {i}" - - # check desc - if 'description' in expected: - assert res.uri['tx_description'] == expected['description'], \ - "Description mismatch" - - # verify unknown parameters - assert res.unknown_parameters == expected_unknown, \ - f"Unknown params mismatch. Expected {expected_unknown}, got {res.unknown_parameters}" - # test mixed parameter positions - res = wallet.parse_uri( - f'monero:{address1};{address2}?unknown_first=123&tx_amount=0.1;0.2&unknown_last=456' - ) - assert res.unknown_parameters == ['unknown_first=123', 'unknown_last=456'] - assert len(res.uri['payments']) == 2 - assert res.uri['payments'][0]['amount'] == 100000000000 - assert res.uri['payments'][1]['amount'] == 200000000000 - # test special characters in unknown params - special_uri = f'monero:{address1};{address2}?weird_param={quoted_utf8string[0]}&tx_amount=1;2' - res = wallet.parse_uri(special_uri) - assert res.unknown_parameters == [u'weird_param=' + quoted_utf8string[0]] - assert res.uri['payments'][0]['amount'] == 1000000000000 - assert res.uri['payments'][1]['amount'] == 2000000000000 - # test multiple unknown params with same key - res = wallet.parse_uri(f'monero:{address1}?tx_amount=1&flag=1&flag=2') - assert res.unknown_parameters == ['flag=1', 'flag=2'] - assert res.uri['payments'][0]['amount'] == 1000000000000 if __name__ == '__main__': - URITest().run_test() + URITest().run_test() \ No newline at end of file diff --git a/utils/python-rpc/framework/wallet.py b/utils/python-rpc/framework/wallet.py index f6ef758ec53..7a6f808504a 100644 --- a/utils/python-rpc/framework/wallet.py +++ b/utils/python-rpc/framework/wallet.py @@ -987,7 +987,35 @@ def get_attribute(self, key): } return self.rpc.send_json_rpc_request(get_attribute) - def make_uri(self, payments, payment_id='', tx_description=''): + + def make_uri(self, payments=None, address='', payment_id='', amount=0, tx_description='', recipient_name=''): + """ + Unified make_uri method. + + If 'payments' is provided (a list), the new multi-recipient format is used (old format, but multi data is separated by semi-colon). + Otherwise, if no payments list is provided, the legacy format is assumed and + a single payment is created from the legacy parameters (address, amount, recipient_name). + + Existing parameter names remain unchanged for backwards compatibility. + The underlying C++ implementation provides overloads: + - make_uri(vector, payment_id, tx_description, error) + - make_uri(address, payment_id, amount, tx_description, recipient_name, error) + + Either provide: + #1 payments{address,amount,recipient_name}, payment_id, tx_description (supports multi-uri) + #2: address, payment_id, amount, tx_description, recipient_name (obsolete, legacy, kept for backwards-compatibility) + Standalone payment IDs are not supported and will result into errors. + """ + # if payments is None or an empty list, assume legacy mode: + if not payments: + # in legacy mode, the address must be nonempty. + if not address: + raise Exception("No address provided") + payments = [{ + 'address': address, + 'amount': amount, + 'recipient_name': recipient_name + }] make_uri = { 'method': 'make_uri', 'jsonrpc': '2.0', @@ -1000,18 +1028,6 @@ def make_uri(self, payments, payment_id='', tx_description=''): } return self.rpc.send_json_rpc_request(make_uri) - def legacy_make_uri(self, address='', payment_id='', amount=0, tx_description='', recipient_name=''): - """For backward compatibility with single-payment URIs""" - return self.make_uri( - payments=[{ - 'address': address, - 'amount': amount, - 'recipient_name': recipient_name - }], - payment_id=payment_id, - tx_description=tx_description - ) - def parse_uri(self, uri): parse_uri = { 'method': 'parse_uri', From 577b7eeade3161ff2cce324a418278bae7c9281d Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Sat, 1 Feb 2025 23:35:12 +0530 Subject: [PATCH 19/50] Fix function declarations --- src/wallet/api/wallet.h | 4 +++- src/wallet/wallet2.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index d48d7f130e3..e825a0565bb 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -213,8 +213,10 @@ class WalletImpl : public Wallet virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const override; virtual void startRefresh() override; virtual void pauseRefresh() override; - virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) override; + virtual bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) override; + virtual bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) override; virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const override; + virtual std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; virtual std::string getDefaultDataDir() const override; virtual bool blackballOutputs(const std::vector &outputs, bool add) override; virtual bool blackballOutput(const std::string &amount, const std::string &offset) override; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 60b48814d8a..4846d076490 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1649,6 +1649,7 @@ namespace tools std::string decrypt_with_view_secret_key(const std::string &ciphertext, bool authenticated = true) const; std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; + std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const; bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error); From faf7306a6b79b06c3e4c26091d0e656976b8ffbc Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Sat, 1 Feb 2025 23:40:50 +0530 Subject: [PATCH 20/50] fix uri_data not found by replacing it with tools::wallet2::uri_data since it's in wallet2.h --- src/wallet/api/wallet.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index e825a0565bb..0d2a3864be2 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -213,10 +213,10 @@ class WalletImpl : public Wallet virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const override; virtual void startRefresh() override; virtual void pauseRefresh() override; - virtual bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) override; + virtual bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) override; virtual bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) override; virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const override; - virtual std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; + virtual std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; virtual std::string getDefaultDataDir() const override; virtual bool blackballOutputs(const std::vector &outputs, bool add) override; virtual bool blackballOutput(const std::string &amount, const std::string &offset) override; From 48fe7eb343122c8b5e9c3025ec7c6afa2b80cfc2 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Sat, 1 Feb 2025 23:44:32 +0530 Subject: [PATCH 21/50] remove override keyword from wallet.h: make_uri and parse_uri --- src/wallet/api/wallet.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 0d2a3864be2..cfd50ca75c2 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -213,9 +213,9 @@ class WalletImpl : public Wallet virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const override; virtual void startRefresh() override; virtual void pauseRefresh() override; - virtual bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) override; - virtual bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) override; - virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const override; + virtual bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); + virtual bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error); + virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const; virtual std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; virtual std::string getDefaultDataDir() const override; virtual bool blackballOutputs(const std::vector &outputs, bool add) override; From 9383f36b19109f473c2d857a80b5a78cfc0eb3e5 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Sun, 2 Feb 2025 00:02:34 +0530 Subject: [PATCH 22/50] fix override issue --- src/wallet/api/wallet.cpp | 4 ++-- src/wallet/api/wallet.h | 5 +++-- src/wallet/api/wallet2_api.h | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index cb44fd3bae8..ea3d7fe3821 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2548,7 +2548,7 @@ bool WalletImpl::checkBackgroundSync(const std::string &message) const return false; } -bool WalletImpl::parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) +bool WalletImpl::parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) { return m_wallet->parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error) } @@ -2563,7 +2563,7 @@ std::string WalletImpl::make_uri(const std::string &address, const std::string & return m_wallet->make_uri(address, payment_id, amount, tx_description, recipient_name, error); } -std::string WalletImpl::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const +std::string WalletImpl::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const { return m_wallet->make_uri(data, payment_id, tx_description, error); } diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index cfd50ca75c2..88dc025fa13 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -213,10 +213,11 @@ class WalletImpl : public Wallet virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const override; virtual void startRefresh() override; virtual void pauseRefresh() override; + virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) override; virtual bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); - virtual bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error); - virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const; + virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const override; virtual std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; + virtual std::string getDefaultDataDir() const override; virtual bool blackballOutputs(const std::vector &outputs, bool add) override; virtual bool blackballOutput(const std::string &amount, const std::string &offset) override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 2bedcc7d280..46dcf1f9b75 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1066,8 +1066,10 @@ struct Wallet virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const = 0; virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) = 0; + virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const = 0; + virtual std::string getDefaultDataDir() const = 0; /* From ca7b72e1129dfcc14935d31e68914f6b18a9495d Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Sun, 2 Feb 2025 08:29:02 +0530 Subject: [PATCH 23/50] add semi-colon. --- src/wallet/api/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index ea3d7fe3821..e116cf67130 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2550,7 +2550,7 @@ bool WalletImpl::checkBackgroundSync(const std::string &message) const bool WalletImpl::parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) { - return m_wallet->parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error) + return m_wallet->parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error); } bool WalletImpl::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) From a7fbf60263297831a4047e645fc1df1f58156440 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Sun, 2 Feb 2025 08:57:06 +0530 Subject: [PATCH 24/50] warning fix: loop variable 'entry' creates a copy. --- src/wallet/wallet2.cpp | 4 ++-- src/wallet/wallet_rpc_server.cpp | 4 ++-- tests/functional_tests/uri.py | 5 ----- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 4deb67e5061..49e91aee6d9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14962,9 +14962,9 @@ std::string wallet2::make_uri(std::vector data, const std::string &pay error = std::string("wrong address: ") + entry.address; return std::string(); } - if (!payment_id.empty()) + if (info.has_payment_id && !payment_id.empty()) { - error = "Standalone payment id deprecated, use integrated address instead"; + error = "Separate payment id given with an integrated address"; return std::string(); } if (!addresses.empty()) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 63da74c7d87..18d6cb8be4a 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -3110,7 +3110,7 @@ namespace tools if (!m_wallet) return not_open(er); std::string error; std::vector data; - for (tools::wallet_rpc::uri_payment entry : req.payments) + for (tools::wallet_rpc::uri_payment &entry : req.payments) { tools::wallet2::uri_data entry_data; entry_data.address = entry.address; @@ -3142,7 +3142,7 @@ namespace tools er.message = "Error parsing URI: " + error; return false; } - for (const tools::wallet2::uri_data entry : uri_data) + for (const tools::wallet2::uri_data &entry : uri_data) { tools::wallet_rpc::uri_payment entry_spec = {entry.address, entry.amount, entry.recipient_name}; res.uri.payments.push_back(entry_spec); diff --git a/tests/functional_tests/uri.py b/tests/functional_tests/uri.py index 14fe217a60c..576b78a8800 100755 --- a/tests/functional_tests/uri.py +++ b/tests/functional_tests/uri.py @@ -323,10 +323,5 @@ def test_multi_uri(self): # unknown parameters should be collected in the unknown_parameters list. assert parsed.unknown_parameters == ['foo=bar', 'baz=quux'], "Unknown parameters mismatch" - - - - - if __name__ == '__main__': URITest().run_test() \ No newline at end of file From 400d812a33fb484704aea93ff61e8dece4ba5dfc Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Sun, 2 Feb 2025 09:11:17 +0530 Subject: [PATCH 25/50] add const keyword --- src/wallet/wallet_rpc_server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 18d6cb8be4a..83f716ba574 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -3110,7 +3110,7 @@ namespace tools if (!m_wallet) return not_open(er); std::string error; std::vector data; - for (tools::wallet_rpc::uri_payment &entry : req.payments) + for (const tools::wallet_rpc::uri_payment &entry : req.payments) { tools::wallet2::uri_data entry_data; entry_data.address = entry.address; From d678eeeea97c0f09459553184dd906396422508b Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Sun, 2 Feb 2025 11:52:52 +0530 Subject: [PATCH 26/50] allow standalone payment ids (yet not recommended; fallback) --- src/wallet/wallet2.cpp | 15 +++++++++------ tests/functional_tests/uri.py | 22 +++++++++++++++------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 49e91aee6d9..7411462aae5 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -6236,6 +6236,9 @@ std::string wallet2::make_background_keys_file_name(const std::string &wallet_fi //---------------------------------------------------------------------------------------------------- bool wallet2::parse_long_payment_id(const std::string& payment_id_str, crypto::hash& payment_id) { + if (payment_id_str.size() != 64) + return false; + cryptonote::blobdata payment_id_data; if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data)) return false; @@ -15127,11 +15130,6 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std else if (kv[0] == "tx_payment_id") { // standalone payment ids are deprecated. use integrated address - error = "Standalone payment id deprecated, use integrated address instead"; - return false; - - /* - // Commenting this code to save for any unforeseen future use. crypto::hash hash; if (!wallet2::parse_long_payment_id(kv[1], hash)) { @@ -15139,7 +15137,12 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std return false; } payment_id = kv[1]; - */ + + if (payment_id.length() != 16 && payment_id.length() != 64) + { + error = "Invalid payment ID length"; + return false; + } } else if (kv[0] == "recipient_name") { diff --git a/tests/functional_tests/uri.py b/tests/functional_tests/uri.py index 576b78a8800..9c9ac4be681 100755 --- a/tests/functional_tests/uri.py +++ b/tests/functional_tests/uri.py @@ -43,6 +43,7 @@ class URITest(): def run_test(self): self.create() self.test_monero_uri() + self.test_multi_uri() def create(self): print('Creating wallet') @@ -142,11 +143,17 @@ def test_monero_uri(self): assert res.uri.tx_description == utf8string[1] assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 - # external payment ids are not supported anymore - ok = False - try: res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1], amount = 1000000000000, payment_id = '1' * 64) - except: ok = True - assert ok + # standalone payment ids are supported but not recommended + res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1], amount = 1000000000000, payment_id = '1' * 64) + assert res.uri == 'monero:' + address + '?tx_amount=1.000000000000&recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1] + '&tx_payment_id=' + '1' * 64 + + # in case of standalone payment id removal + # ok = False + # try: + # res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1], amount = 1000000000000, payment_id = '1' * 64) + # except: + # ok = True + # assert ok # spaces must be encoded as %20 res = wallet.make_uri(address = address, tx_description = ' ' + utf8string[1] + ' ' + utf8string[0] + ' ', amount = 1000000000000) @@ -196,8 +203,9 @@ def test_monero_uri(self): 'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm&tx_amount=10=&', 'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm&tx_amount=10=&foo=bar', 'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm?tx_amount=10&tx_amount=20', - 'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm?tx_payment_id=1111111111111111', - 'monero:4BxSHvcgTwu25WooY4BVmgdcKwZu5EksVZSZkDd6ooxSVVqQ4ubxXkhLF6hEqtw96i9cf3cVfLw8UWe95bdDKfRQeYtPwLm1Jiw7AKt2LY?tx_payment_id=' + '1' * 64, + # Standalone payment ids are still supported, in case of complete functionality removal: uncomment this. + # 'monero:42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm?tx_payment_id=1111111111111111', + # 'monero:4BxSHvcgTwu25WooY4BVmgdcKwZu5EksVZSZkDd6ooxSVVqQ4ubxXkhLF6hEqtw96i9cf3cVfLw8UWe95bdDKfRQeYtPwLm1Jiw7AKt2LY?tx_payment_id=' + '1' * 64, 'monero:9ujeXrjzf7bfeK3KZdCqnYaMwZVFuXemPU8Ubw335rj2FN1CdMiWNyFV3ksEfMFvRp9L9qum5UxkP5rN9aLcPxbH1au4WAB', 'monero:5K8mwfjumVseCcQEjNbf59Um6R9NfVUNkHTLhhPCmNvgDLVS88YW5tScnm83rw9mfgYtchtDDTW5jEfMhygi27j1QYphX38hg6m4VMtN29', 'monero:7A1Hr63MfgUa8pkWxueD5xBqhQczkusYiCMYMnJGcGmuQxa7aDBxN1G7iCuLCNB3VPeb2TW7U9FdxB27xKkWKfJ8VhUZthF', From bd357c56bd0a584bf748835e82976e5df4618c73 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Sun, 2 Feb 2025 12:20:48 +0530 Subject: [PATCH 27/50] Exclude core_tests --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2e95fb15aab..031ede27955 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -224,6 +224,7 @@ jobs: ${{env.CCACHE_SETTINGS}} ${{env.BUILD_DEFAULT_LINUX}} --parallel ${{env.MAKE_JOB_COUNT}} cmake --build build --target test + ctest -E core_tests --output-on-failure # ARCH="default" (not "native") ensures, that a different execution host can execute binaries compiled elsewhere. # BUILD_SHARED_LIBS=ON speeds up the linkage part a bit, reduces size, and is the only place where the dynamic linkage is tested. From f0de5c821023233825297ff3226280d3a9ac22fc Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Sun, 2 Feb 2025 14:05:15 +0530 Subject: [PATCH 28/50] fix failing uri.py by properly calling make_uri and parse_uri. restore build.yml --- .github/workflows/build.yml | 1 - tests/functional_tests/uri.py | 21 +++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 031ede27955..2e95fb15aab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -224,7 +224,6 @@ jobs: ${{env.CCACHE_SETTINGS}} ${{env.BUILD_DEFAULT_LINUX}} --parallel ${{env.MAKE_JOB_COUNT}} cmake --build build --target test - ctest -E core_tests --output-on-failure # ARCH="default" (not "native") ensures, that a different execution host can execute binaries compiled elsewhere. # BUILD_SHARED_LIBS=ON speeds up the linkage part a bit, reduces size, and is the only place where the dynamic linkage is tested. diff --git a/tests/functional_tests/uri.py b/tests/functional_tests/uri.py index 9c9ac4be681..f4b51b3e9b6 100755 --- a/tests/functional_tests/uri.py +++ b/tests/functional_tests/uri.py @@ -57,7 +57,7 @@ def create(self): assert res.seed == seed def test_monero_uri(self): - print('Testing monero: URI') + print('Testing monero: URI - single') wallet = Wallet() utf8string = [u'えんしゅう', u'あまやかす'] @@ -236,6 +236,7 @@ def test_monero_uri(self): def test_multi_uri(self): print('Testing multi-recipient monero: URI') + wallet = Wallet() addr1 = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' addr2 = '4BxSHvcgTwu25WooY4BVmgdcKwZu5EksVZSZkDd6ooxSVVqQ4ubxXkhLF6hEqtw96i9cf3cVfLw8UWe95bdDKfRQeYtPwLm1Jiw7AKt2LY' addr3 = '8AsN91rznfkBGTY8psSNkJBg9SZgxxGGRUhGwRptBhgr5XSQ1XzmA9m8QAnoxydecSh5aLJXdrgXwTDMMZ1AuXsN1EX5Mtm' @@ -247,10 +248,10 @@ def test_multi_uri(self): {'address': addr1, 'amount': 500000000000, 'recipient_name': utf8string[0]}, {'address': addr2, 'amount': 200000000000, 'recipient_name': utf8string[1]} ] - res = self.make_uri(payments=payments, payment_id='', tx_description='multi test') + res = wallet.make_uri(payments=payments, payment_id='', tx_description='multi test') # expect URI like: # monero:addr1;addr2?tx_amount=0.5;0.2&recipient_name=;&tx_description=multi%20test - parsed = self.parse_uri(res.uri) + parsed = wallet.parse_uri(res.uri) # verify that both payments are present. assert len(parsed.uri.payments) == 2, "Expected 2 payments in multi-recipient URI" assert parsed.uri.payments[0].address == addr1 @@ -269,8 +270,8 @@ def test_multi_uri(self): {'address': addr2, 'amount': 500000000000, 'recipient_name': utf8string[1]}, {'address': addr3, 'amount': 250000000000, 'recipient_name': ''} ] - res = self.make_uri(payments=payments, payment_id='', tx_description='three pay') - parsed = self.parse_uri(res.uri) + res = wallet.make_uri(payments=payments, payment_id='', tx_description='three pay') + parsed = wallet.parse_uri(res.uri) assert len(parsed.uri.payments) == 3, "Expected 3 payments in multi-recipient URI" assert parsed.uri.payments[0].address == addr1 assert parsed.uri.payments[0].amount == 1000000000000 @@ -293,7 +294,7 @@ def test_multi_uri(self): uri_bad = 'monero:' + addr1 + ';' + addr2 + '?tx_amount=0.5&recipient_name=Alice;Bob' ok = False try: - self.parse_uri(uri_bad) + wallet.parse_uri(uri_bad) except Exception: ok = True assert ok, "Expected rejection for mismatched payment counts" @@ -301,7 +302,7 @@ def test_multi_uri(self): # case: trailing semicolon in addresses or parameters should be handled gracefully uri_trailing = 'monero:' + addr1 + ';' + addr2 + ';' + '?tx_amount=0.5;0.2&recipient_name=Alice;Bob' # depending on the implementation, a trailing empty value might be dropped. - parsed = self.parse_uri(uri_trailing) + parsed = wallet.parse_uri(uri_trailing) assert len(parsed.uri.payments) == 2, "Trailing delimiter should not add empty payment" # case: special characters in recipient names and descriptions @@ -313,8 +314,8 @@ def test_multi_uri(self): ] # the RPC should URL-encode these parameters. - res = self.make_uri(payments=payments, tx_description=special_desc) - parsed = self.parse_uri(res.uri) + res = wallet.make_uri(payments=payments, tx_description=special_desc) + parsed = wallet.parse_uri(res.uri) # check that the decoded values match the original. for pay in parsed.uri.payments: assert pay.recipient_name == special_name, "Special characters in recipient name mismatch" @@ -325,7 +326,7 @@ def test_multi_uri(self): {'address': addr1, 'amount': 239390140000000, 'recipient_name': ''} ] uri_with_unknown = 'monero:' + addr1 + '?tx_amount=239.39014&foo=bar&baz=quux' - parsed = self.parse_uri(uri_with_unknown) + parsed = wallet.parse_uri(uri_with_unknown) assert parsed.uri.payments[0].address == addr1 assert parsed.uri.payments[0].amount == 239390140000000 # unknown parameters should be collected in the unknown_parameters list. From c489d7d57fa87272f3ea145db0ae481aa5a04138 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Sun, 2 Feb 2025 16:12:14 +0530 Subject: [PATCH 29/50] introduce a custom convert to url func instead of modifying existing func to handle `=` and `?` properly in desc and recipient name. --- src/wallet/wallet2.cpp | 32 ++++++++++++++++++++++++++++++-- src/wallet/wallet2.h | 3 ++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 7411462aae5..ecb36f1f886 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14945,6 +14945,34 @@ std::string wallet2::decrypt_with_view_secret_key(const std::string &ciphertext, return decrypt(ciphertext, get_account().get_keys().m_view_secret_key, authenticated); } //---------------------------------------------------------------------------------------------------- +std::string wallet2::custom_conver_to_url_format(const std::string &uri) const +{ + std::string s = conver_to_url_format(uri); + + // replace '=' with "%3D" and '?' with "%3F". + std::string result; + result.reserve(s.size()); + + for (char c : s) + { + if (c == '=') + { + result.append("%3D"); + } + else if (c == '?') + { + result.append("%3F"); + } + + else + { + result.push_back(c); + } + } + + return result; +} +//---------------------------------------------------------------------------------------------------- std::string wallet2::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const { if (data.empty()) @@ -14993,7 +15021,7 @@ std::string wallet2::make_uri(std::vector data, const std::string &pay if (!entry.recipient_name.empty()) { recipients_used = true; - recipients += epee::net_utils::conver_to_url_format(entry.recipient_name); + recipients += custom_conver_to_url_format(entry.recipient_name); } } @@ -15013,7 +15041,7 @@ std::string wallet2::make_uri(std::vector data, const std::string &pay if (!tx_description.empty()) { - uri += (n_fields++ ? "&" : "?") + std::string("tx_description=") + epee::net_utils::conver_to_url_format(tx_description); + uri += (n_fields++ ? "&" : "?") + std::string("tx_description=") + custom_conver_to_url_format(tx_description); } if (!payment_id.empty()) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 4846d076490..0f0d02a8b2e 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1647,7 +1647,8 @@ namespace tools std::string encrypt_with_view_secret_key(const std::string &plaintext, bool authenticated = true) const; template T decrypt(const std::string &ciphertext, const crypto::secret_key &skey, bool authenticated = true) const; std::string decrypt_with_view_secret_key(const std::string &ciphertext, bool authenticated = true) const; - + + std::string custom_conver_to_url_format(const std::string &uri) const; std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const; bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); From 5911114a0abd7c03acedeb88cfbc1c2fea3ce39b Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Sun, 2 Feb 2025 16:18:18 +0530 Subject: [PATCH 30/50] fix conver_to_url_format not declared by changing call to epee::net_utils::conver_to_url_format --- src/wallet/wallet2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index ecb36f1f886..f267c37e75a 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14947,7 +14947,7 @@ std::string wallet2::decrypt_with_view_secret_key(const std::string &ciphertext, //---------------------------------------------------------------------------------------------------- std::string wallet2::custom_conver_to_url_format(const std::string &uri) const { - std::string s = conver_to_url_format(uri); + std::string s = epee::net_utils::conver_to_url_format(uri); // replace '=' with "%3D" and '?' with "%3F". std::string result; From d9a56b84d989a0c912ac4a49b85edeacf8d46328 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Mon, 10 Feb 2025 20:49:53 +0530 Subject: [PATCH 31/50] Remove out of scope payment id check --- src/wallet/wallet2.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f267c37e75a..48084026721 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -6236,9 +6236,6 @@ std::string wallet2::make_background_keys_file_name(const std::string &wallet_fi //---------------------------------------------------------------------------------------------------- bool wallet2::parse_long_payment_id(const std::string& payment_id_str, crypto::hash& payment_id) { - if (payment_id_str.size() != 64) - return false; - cryptonote::blobdata payment_id_data; if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data)) return false; From cd59dfa25bf0d32a723151be9ad5db0f168792db Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Tue, 11 Feb 2025 07:10:28 +0530 Subject: [PATCH 32/50] Introduce v2 versions of make_uri and parse_uri to ensure proper backwards compatibility --- src/wallet/api/wallet.cpp | 12 +-- src/wallet/api/wallet.h | 5 +- src/wallet/wallet2.cpp | 10 +-- src/wallet/wallet2.h | 4 +- src/wallet/wallet_rpc_server.cpp | 39 +++++++-- src/wallet/wallet_rpc_server.h | 4 + src/wallet/wallet_rpc_server_commands_defs.h | 68 +++++++++++++++- tests/functional_tests/uri.py | 86 ++++++++++---------- tests/unit_tests/uri.cpp | 28 +++---- utils/python-rpc/framework/wallet.py | 58 +++++++------ 10 files changed, 201 insertions(+), 113 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index e116cf67130..17238e02814 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2548,14 +2548,14 @@ bool WalletImpl::checkBackgroundSync(const std::string &message) const return false; } -bool WalletImpl::parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) +bool WalletImpl::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) { - return m_wallet->parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error); + return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error); } -bool WalletImpl::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) +bool WalletImpl::parse_uri_v2(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) { - return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error); + return m_wallet->parse_uri_v2(uri, data, payment_id, tx_description, unknown_parameters, error); } std::string WalletImpl::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const @@ -2563,9 +2563,9 @@ std::string WalletImpl::make_uri(const std::string &address, const std::string & return m_wallet->make_uri(address, payment_id, amount, tx_description, recipient_name, error); } -std::string WalletImpl::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const +std::string WalletImpl::make_uri_v2(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const { - return m_wallet->make_uri(data, payment_id, tx_description, error); + return m_wallet->make_uri_v2(data, payment_id, tx_description, error); } std::string WalletImpl::getDefaultDataDir() const diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 88dc025fa13..b6d26de05fa 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -214,10 +214,9 @@ class WalletImpl : public Wallet virtual void startRefresh() override; virtual void pauseRefresh() override; virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) override; - virtual bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); + virtual bool parse_uri_v2(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const override; - virtual std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; - + virtual std::string make_uri_v2(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; virtual std::string getDefaultDataDir() const override; virtual bool blackballOutputs(const std::vector &outputs, bool add) override; virtual bool blackballOutput(const std::string &amount, const std::string &offset) override; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 48084026721..2c76e5d2c0e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14970,7 +14970,7 @@ std::string wallet2::custom_conver_to_url_format(const std::string &uri) const return result; } //---------------------------------------------------------------------------------------------------- -std::string wallet2::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const +std::string wallet2::make_uri_v2(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const { if (data.empty()) { @@ -15065,10 +15065,10 @@ std::string wallet2::make_uri(const std::string &address, const std::string &pay std::vector data; data.push_back(entry); - return make_uri(data, payment_id, tx_description, error); + return make_uri_v2(data, payment_id, tx_description, error); } //---------------------------------------------------------------------------------------------------- -bool wallet2::parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) +bool wallet2::parse_uri_v2(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) { if (uri.substr(0, 7) != "monero:") { @@ -15224,14 +15224,14 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) { std::vector data; - if (!parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error)) + if (!parse_uri_v2(uri, data, payment_id, tx_description, unknown_parameters, error)) { error = "Failed to parse uri"; return false; } if (data.size() > 1) { - error = "Multi-recipient URIs currently unsupported"; + error = "Multi-recipient URIs currently unsupported; please use parse_uri_v2"; return false; } address = data[0].address; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 0f0d02a8b2e..1da025c666f 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1649,9 +1649,9 @@ namespace tools std::string decrypt_with_view_secret_key(const std::string &ciphertext, bool authenticated = true) const; std::string custom_conver_to_url_format(const std::string &uri) const; - std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; + std::string make_uri_v2(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const; - bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); + bool parse_uri_v2(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error); uint64_t get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day); // 1<=month<=12, 1<=day<=31 diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 83f716ba574..d5c96cc7cfc 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -3106,6 +3106,22 @@ namespace tools } //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_make_uri(const wallet_rpc::COMMAND_RPC_MAKE_URI::request& req, wallet_rpc::COMMAND_RPC_MAKE_URI::response& res, epee::json_rpc::error& er, const connection_context *ctx) + { + if (!m_wallet) return not_open(er); + std::string error; + std::string uri = m_wallet->make_uri(req.address, req.payment_id, req.amount, req.tx_description, req.recipient_name, error); + if (uri.empty()) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_URI; + er.message = std::string("Cannot make URI from supplied parameters: ") + error; + return false; + } + + res.uri = uri; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_make_uri_v2(const wallet_rpc::COMMAND_RPC_MAKE_URI_V2::request& req, wallet_rpc::COMMAND_RPC_MAKE_URI_V2::response& res, epee::json_rpc::error& er, const connection_context *ctx) { if (!m_wallet) return not_open(er); std::string error; @@ -3119,19 +3135,32 @@ namespace tools data.push_back(entry_data); } std::string uri = m_wallet->make_uri(data, req.payment_id, req.tx_description, error); - + if (uri.empty()) { - er.code = WALLET_RPC_ERROR_CODE_WRONG_URI; - er.message = std::string("Cannot make URI from supplied parameters: ") + error; - return false; + er.code = WALLET_RPC_ERROR_CODE_WRONG_URI; + er.message = std::string("Cannot make URI from supplied parameters: ") + error; + return false; } - + res.uri = uri; return true; } //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_parse_uri(const wallet_rpc::COMMAND_RPC_PARSE_URI::request& req, wallet_rpc::COMMAND_RPC_PARSE_URI::response& res, epee::json_rpc::error& er, const connection_context *ctx) + { + if (!m_wallet) return not_open(er); + std::string error; + if (!m_wallet->parse_uri(req.uri, res.uri.address, res.uri.payment_id, res.uri.amount, res.uri.tx_description, res.uri.recipient_name, res.unknown_parameters, error)) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_URI; + er.message = "Error parsing URI: " + error; + return false; + } + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_parse_uri_v2(const wallet_rpc::COMMAND_RPC_PARSE_URI_V2::request& req, wallet_rpc::COMMAND_RPC_PARSE_URI_V2::response& res, epee::json_rpc::error& er, const connection_context *ctx) { if (!m_wallet) return not_open(er); std::string error; diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index f118f581a61..16e29e31501 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -126,7 +126,9 @@ namespace tools MAP_JON_RPC_WE("export_key_images", on_export_key_images, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES) MAP_JON_RPC_WE("import_key_images", on_import_key_images, wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES) MAP_JON_RPC_WE("make_uri", on_make_uri, wallet_rpc::COMMAND_RPC_MAKE_URI) + MAP_JON_RPC_WE("make_uri_v2", on_make_uri_v2, wallet_rpc::COMMAND_RPC_MAKE_URI_V2) MAP_JON_RPC_WE("parse_uri", on_parse_uri, wallet_rpc::COMMAND_RPC_PARSE_URI) + MAP_JON_RPC_WE("parse_uri_v2", on_parse_uri_v2, wallet_rpc::COMMAND_RPC_PARSE_URI_V2) MAP_JON_RPC_WE("get_address_book", on_get_address_book, wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY) MAP_JON_RPC_WE("add_address_book", on_add_address_book, wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY) MAP_JON_RPC_WE("edit_address_book", on_edit_address_book, wallet_rpc::COMMAND_RPC_EDIT_ADDRESS_BOOK_ENTRY) @@ -221,7 +223,9 @@ namespace tools 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, const connection_context *ctx = NULL); bool on_import_key_images(const wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); bool on_make_uri(const wallet_rpc::COMMAND_RPC_MAKE_URI::request& req, wallet_rpc::COMMAND_RPC_MAKE_URI::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); + bool on_make_uri_v2(const wallet_rpc::COMMAND_RPC_MAKE_URI_V2::request& req, wallet_rpc::COMMAND_RPC_MAKE_URI_V2::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); bool on_parse_uri(const wallet_rpc::COMMAND_RPC_PARSE_URI::request& req, wallet_rpc::COMMAND_RPC_PARSE_URI::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); + bool on_parse_uri_v2(const wallet_rpc::COMMAND_RPC_PARSE_URI_V2::request& req, wallet_rpc::COMMAND_RPC_PARSE_URI_V2::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); bool on_get_address_book(const wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); bool on_add_address_book(const wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_ADD_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); bool on_edit_address_book(const wallet_rpc::COMMAND_RPC_EDIT_ADDRESS_BOOK_ENTRY::request& req, wallet_rpc::COMMAND_RPC_EDIT_ADDRESS_BOOK_ENTRY::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index bdb72b93b04..f687e6faec1 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -1825,6 +1825,66 @@ namespace wallet_rpc typedef epee::misc_utils::struct_init response; }; + struct uri_spec + { + std::string address; + std::string payment_id; + uint64_t amount; + std::string tx_description; + std::string recipient_name; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(address) + KV_SERIALIZE(payment_id) + KV_SERIALIZE(amount) + KV_SERIALIZE(tx_description) + KV_SERIALIZE(recipient_name) + END_KV_SERIALIZE_MAP() + }; + + struct COMMAND_RPC_MAKE_URI + { + struct request_t: public uri_spec + { + }; + typedef epee::misc_utils::struct_init request; + + struct response_t + { + std::string uri; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(uri) + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init response; + }; + + struct COMMAND_RPC_PARSE_URI + { + struct request_t + { + std::string uri; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(uri) + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init request; + + struct response_t + { + uri_spec uri; + std::vector unknown_parameters; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(uri) + KV_SERIALIZE(unknown_parameters) + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init response; + }; + struct uri_payment { std::string address; @@ -1838,7 +1898,7 @@ namespace wallet_rpc END_KV_SERIALIZE_MAP() }; - struct uri_spec + struct uri_spec_v2 { std::vector payments; std::string tx_description; @@ -1851,7 +1911,7 @@ namespace wallet_rpc END_KV_SERIALIZE_MAP() }; - struct COMMAND_RPC_MAKE_URI + struct COMMAND_RPC_MAKE_URI_V2 { struct request_t { @@ -1877,7 +1937,7 @@ namespace wallet_rpc typedef epee::misc_utils::struct_init response; }; - struct COMMAND_RPC_PARSE_URI + struct COMMAND_RPC_PARSE_URI_V2 { struct request_t { @@ -1891,7 +1951,7 @@ namespace wallet_rpc struct response_t { - uri_spec uri; + uri_spec_v2 uri; std::vector unknown_parameters; BEGIN_KV_SERIALIZE_MAP() diff --git a/tests/functional_tests/uri.py b/tests/functional_tests/uri.py index f4b51b3e9b6..b0bb7f1e4de 100755 --- a/tests/functional_tests/uri.py +++ b/tests/functional_tests/uri.py @@ -84,9 +84,9 @@ def test_monero_uri(self): res = wallet.make_uri(address = address) assert res.uri == 'monero:' + address res = wallet.parse_uri(res.uri) - assert res.uri.payments[0].address == address - assert res.uri.payments[0].amount == 0 - assert res.uri.payments[0].recipient_name == '' + assert res.uri.address == address + assert res.uri.amount == 0 + assert res.uri.recipient_name == '' assert res.uri.payment_id == '' assert res.uri.tx_description == '' @@ -94,9 +94,9 @@ def test_monero_uri(self): res = wallet.make_uri(address = address, amount = 11000000000) assert res.uri == 'monero:' + address + '?tx_amount=0.011' or res.uri == 'monero:' + address + '?tx_amount=0.011000000000' res = wallet.parse_uri(res.uri) - assert res.uri.payments[0].address == address - assert res.uri.payments[0].amount == 11000000000 - assert res.uri.payments[0].recipient_name == '' + assert res.uri.address == address + assert res.uri.amount == 11000000000 + assert res.uri.recipient_name == '' assert res.uri.payment_id == '' assert res.uri.tx_description == '' assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 @@ -106,9 +106,9 @@ def test_monero_uri(self): res = wallet.make_uri(address = address, tx_description = utf8string[0]) assert res.uri == 'monero:' + address + '?tx_description=' + quoted_utf8string[0] res = wallet.parse_uri(res.uri) - assert res.uri.payments[0].address == address - assert res.uri.payments[0].amount == 0 - assert res.uri.payments[0].recipient_name == '' + assert res.uri.address == address + assert res.uri.amount == 0 + assert res.uri.recipient_name == '' assert res.uri.payment_id == '' assert res.uri.tx_description == utf8string[0] assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 @@ -116,9 +116,9 @@ def test_monero_uri(self): res = wallet.make_uri(address = address, recipient_name = utf8string[0]) assert res.uri == 'monero:' + address + '?recipient_name=' + quoted_utf8string[0] res = wallet.parse_uri(res.uri) - assert res.uri.payments[0].address == address - assert res.uri.payments[0].amount == 0 - assert res.uri.payments[0].recipient_name == utf8string[0] + assert res.uri.address == address + assert res.uri.amount == 0 + assert res.uri.recipient_name == utf8string[0] assert res.uri.payment_id == '' assert res.uri.tx_description == '' assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 @@ -126,9 +126,9 @@ def test_monero_uri(self): res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1]) assert res.uri == 'monero:' + address + '?recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1] res = wallet.parse_uri(res.uri) - assert res.uri.payments[0].address == address - assert res.uri.payments[0].amount == 0 - assert res.uri.payments[0].recipient_name == utf8string[0] + assert res.uri.address == address + assert res.uri.amount == 0 + assert res.uri.recipient_name == utf8string[0] assert res.uri.payment_id == '' assert res.uri.tx_description == utf8string[1] assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 @@ -136,9 +136,9 @@ def test_monero_uri(self): res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1], amount = 1000000000000) assert res.uri == 'monero:' + address + '?tx_amount=1.000000000000&recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1] res = wallet.parse_uri(res.uri) - assert res.uri.payments[0].address == address - assert res.uri.payments[0].amount == 1000000000000 - assert res.uri.payments[0].recipient_name == utf8string[0] + assert res.uri.address == address + assert res.uri.amount == 1000000000000 + assert res.uri.recipient_name == utf8string[0] assert res.uri.payment_id == '' assert res.uri.tx_description == utf8string[1] assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 @@ -159,18 +159,18 @@ def test_monero_uri(self): res = wallet.make_uri(address = address, tx_description = ' ' + utf8string[1] + ' ' + utf8string[0] + ' ', amount = 1000000000000) assert res.uri == 'monero:' + address + '?tx_amount=1.000000000000&tx_description=%20' + quoted_utf8string[1] + '%20' + quoted_utf8string[0] + '%20' res = wallet.parse_uri(res.uri) - assert res.uri.payments[0].address == address - assert res.uri.payments[0].amount == 1000000000000 - assert res.uri.payments[0].recipient_name == '' + assert res.uri.address == address + assert res.uri.amount == 1000000000000 + assert res.uri.recipient_name == '' assert res.uri.payment_id == '' assert res.uri.tx_description == ' ' + utf8string[1] + ' ' + utf8string[0] + ' ' assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 # the example from the docs res = wallet.parse_uri('monero:46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em?tx_amount=239.39014&tx_description=donation') - assert res.uri.payments[0].address == '46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em' - assert res.uri.payments[0].amount == 239390140000000 - assert res.uri.payments[0].recipient_name == '' + assert res.uri.address == '46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em' + assert res.uri.amount == 239390140000000 + assert res.uri.recipient_name == '' assert res.uri.tx_description == 'donation' assert res.uri.payment_id == '' @@ -217,23 +217,22 @@ def test_monero_uri(self): # unknown parameters but otherwise valid res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&foo=bar') - assert res.uri.payments[0].address == address - assert res.uri.payments[0].amount == 239390140000000 + assert res.uri.address == address + assert res.uri.amount == 239390140000000 assert res.unknown_parameters == ['foo=bar'], res res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&foo=bar&baz=quux') - assert res.uri.payments[0].address == address - assert res.uri.payments[0].amount == 239390140000000 + assert res.uri.address == address + assert res.uri.amount == 239390140000000 assert res.unknown_parameters == ['foo=bar', 'baz=quux'], res res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&%20=%20') - assert res.uri.payments[0].address == address - assert res.uri.payments[0].amount == 239390140000000 + assert res.uri.address == address + assert res.uri.amount == 239390140000000 assert res.unknown_parameters == ['%20=%20'], res res = wallet.parse_uri('monero:' + address + '?tx_amount=239.39014&unknown=' + quoted_utf8string[0]) - assert res.uri.payments[0].address == address - assert res.uri.payments[0].amount == 239390140000000 + assert res.uri.address == address + assert res.uri.amount == 239390140000000 assert res.unknown_parameters == [u'unknown=' + quoted_utf8string[0]], res - def test_multi_uri(self): print('Testing multi-recipient monero: URI') wallet = Wallet() @@ -241,17 +240,16 @@ def test_multi_uri(self): addr2 = '4BxSHvcgTwu25WooY4BVmgdcKwZu5EksVZSZkDd6ooxSVVqQ4ubxXkhLF6hEqtw96i9cf3cVfLw8UWe95bdDKfRQeYtPwLm1Jiw7AKt2LY' addr3 = '8AsN91rznfkBGTY8psSNkJBg9SZgxxGGRUhGwRptBhgr5XSQ1XzmA9m8QAnoxydecSh5aLJXdrgXwTDMMZ1AuXsN1EX5Mtm' utf8string = [u'えんしゅう', u'あまやかす'] - quoted_utf8string = [urllib_quote(x.encode('utf8')) for x in utf8string] # build multi-recipient URI with two payments. payments = [ {'address': addr1, 'amount': 500000000000, 'recipient_name': utf8string[0]}, {'address': addr2, 'amount': 200000000000, 'recipient_name': utf8string[1]} ] - res = wallet.make_uri(payments=payments, payment_id='', tx_description='multi test') + res = wallet.make_uri_v2(payments=payments, payment_id='', tx_description='multi test') # expect URI like: # monero:addr1;addr2?tx_amount=0.5;0.2&recipient_name=;&tx_description=multi%20test - parsed = wallet.parse_uri(res.uri) + parsed = wallet.parse_uri_v2(res.uri) # verify that both payments are present. assert len(parsed.uri.payments) == 2, "Expected 2 payments in multi-recipient URI" assert parsed.uri.payments[0].address == addr1 @@ -270,8 +268,8 @@ def test_multi_uri(self): {'address': addr2, 'amount': 500000000000, 'recipient_name': utf8string[1]}, {'address': addr3, 'amount': 250000000000, 'recipient_name': ''} ] - res = wallet.make_uri(payments=payments, payment_id='', tx_description='three pay') - parsed = wallet.parse_uri(res.uri) + res = wallet.make_uri_v2(payments=payments, payment_id='', tx_description='three pay') + parsed = wallet.parse_uri_v2(res.uri) assert len(parsed.uri.payments) == 3, "Expected 3 payments in multi-recipient URI" assert parsed.uri.payments[0].address == addr1 assert parsed.uri.payments[0].amount == 1000000000000 @@ -289,12 +287,12 @@ def test_multi_uri(self): {'address': addr2, 'amount': 0, 'recipient_name': 'Bob'} ] # manually build a URI with mismatched amounts (remove Bob's amount). - # we simulate this by concatenating amounts incorrectly. + # simulate this by concatenating amounts incorrectly. # (this step assumes you have control over the output URI; in practice, the server would reject it. For testing, we assume the RPC returns an error.) uri_bad = 'monero:' + addr1 + ';' + addr2 + '?tx_amount=0.5&recipient_name=Alice;Bob' ok = False try: - wallet.parse_uri(uri_bad) + wallet.parse_uri_v2(uri_bad) except Exception: ok = True assert ok, "Expected rejection for mismatched payment counts" @@ -302,7 +300,7 @@ def test_multi_uri(self): # case: trailing semicolon in addresses or parameters should be handled gracefully uri_trailing = 'monero:' + addr1 + ';' + addr2 + ';' + '?tx_amount=0.5;0.2&recipient_name=Alice;Bob' # depending on the implementation, a trailing empty value might be dropped. - parsed = wallet.parse_uri(uri_trailing) + parsed = wallet.parse_uri_v2(uri_trailing) assert len(parsed.uri.payments) == 2, "Trailing delimiter should not add empty payment" # case: special characters in recipient names and descriptions @@ -314,8 +312,8 @@ def test_multi_uri(self): ] # the RPC should URL-encode these parameters. - res = wallet.make_uri(payments=payments, tx_description=special_desc) - parsed = wallet.parse_uri(res.uri) + res = wallet.make_uri_v2(payments=payments, tx_description=special_desc) + parsed = wallet.parse_uri_v2(res.uri) # check that the decoded values match the original. for pay in parsed.uri.payments: assert pay.recipient_name == special_name, "Special characters in recipient name mismatch" @@ -326,7 +324,7 @@ def test_multi_uri(self): {'address': addr1, 'amount': 239390140000000, 'recipient_name': ''} ] uri_with_unknown = 'monero:' + addr1 + '?tx_amount=239.39014&foo=bar&baz=quux' - parsed = wallet.parse_uri(uri_with_unknown) + parsed = wallet.parse_uri_v2(uri_with_unknown) assert parsed.uri.payments[0].address == addr1 assert parsed.uri.payments[0].amount == 239390140000000 # unknown parameters should be collected in the unknown_parameters list. diff --git a/tests/unit_tests/uri.cpp b/tests/unit_tests/uri.cpp index 2322464b6c3..7ddfb938be7 100644 --- a/tests/unit_tests/uri.cpp +++ b/tests/unit_tests/uri.cpp @@ -41,12 +41,12 @@ bool ret = w.parse_uri(uri, address, payment_id, amount, description, recipient_name, unknown_parameters, error); \ ASSERT_EQ(ret, expected); -#define PARSE_URI_MULTI(uri, expected) \ +#define PARSE_URI_V2(uri, expected) \ std::vector data; \ std::string payment_id, description, error; \ std::vector unknown_parameters; \ tools::wallet2 w(cryptonote::TESTNET); \ - bool ret = w.parse_uri(uri, data, payment_id, description, unknown_parameters, error); \ + bool ret = w.parse_uri_v2(uri, data, payment_id, description, unknown_parameters, error); \ ASSERT_EQ(ret, expected); TEST(uri, empty_string) @@ -224,7 +224,7 @@ TEST(uri, url_encoded_once) TEST(uri, multiple_addresses_no_params) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS, true); + PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS, true); ASSERT_EQ(data.size(), 2); ASSERT_EQ(data[0].address, TEST_ADDRESS); ASSERT_EQ(data[1].address, TEST_ADDRESS); @@ -232,7 +232,7 @@ TEST(uri, multiple_addresses_no_params) TEST(uri, multiple_addresses_with_amounts) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0.2", true); + PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0.2", true); ASSERT_EQ(data.size(), 2); ASSERT_EQ(data[0].address, TEST_ADDRESS); ASSERT_EQ(data[0].amount, 500000000000); @@ -242,7 +242,7 @@ TEST(uri, multiple_addresses_with_amounts) TEST(uri, multiple_addresses_with_recipient_names) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice;Bob", true); + PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice;Bob", true); ASSERT_EQ(data.size(), 2); ASSERT_EQ(data[0].address, TEST_ADDRESS); ASSERT_EQ(data[0].recipient_name, "Alice"); @@ -252,17 +252,17 @@ TEST(uri, multiple_addresses_with_recipient_names) TEST(uri, multiple_addresses_with_mismatched_amounts) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5", false); + PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5", false); } TEST(uri, multiple_addresses_with_mismatched_recipient_names) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice", false); + PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice", false); } TEST(uri, multiple_addresses_with_partial_params) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0&recipient_name=Alice;", true); + PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0&recipient_name=Alice;", true); ASSERT_EQ(data.size(), 2); ASSERT_EQ(data[0].address, TEST_ADDRESS); ASSERT_EQ(data[0].amount, 500000000000); @@ -274,36 +274,36 @@ TEST(uri, multiple_addresses_with_partial_params) TEST(uri, multiple_addresses_with_unknown_params) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?unknown_param=123;456", true); + PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?unknown_param=123;456", true); ASSERT_EQ(unknown_parameters.size(), 1); ASSERT_EQ(unknown_parameters[0], "unknown_param=123;456"); } TEST(uri, multiple_addresses_with_payment_id) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=1234567890123456789012345678901234567890123456789012345678901234", true); + PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=1234567890123456789012345678901234567890123456789012345678901234", true); ASSERT_EQ(payment_id, "1234567890123456789012345678901234567890123456789012345678901234"); } TEST(uri, multiple_addresses_with_invalid_payment_id) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=123456", false); + PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=123456", false); } TEST(uri, multiple_addresses_with_description) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_description=Payment%20for%20services", true); + PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_description=Payment%20for%20services", true); ASSERT_EQ(description, "Payment for services"); } TEST(uri, multiple_addresses_mismatched_params) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5&recipient_name=Alice", false); + PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5&recipient_name=Alice", false); } TEST(uri, multiple_addresses_all_params_correct) { - PARSE_URI_MULTI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0.2&recipient_name=Alice;Bob&tx_description=Payment%20for%20services", true); + PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0.2&recipient_name=Alice;Bob&tx_description=Payment%20for%20services", true); ASSERT_EQ(data.size(), 2); ASSERT_EQ(data[0].address, TEST_ADDRESS); ASSERT_EQ(data[0].amount, 500000000000); diff --git a/utils/python-rpc/framework/wallet.py b/utils/python-rpc/framework/wallet.py index 7a6f808504a..d4303c31ade 100644 --- a/utils/python-rpc/framework/wallet.py +++ b/utils/python-rpc/framework/wallet.py @@ -987,36 +987,34 @@ def get_attribute(self, key): } return self.rpc.send_json_rpc_request(get_attribute) - - def make_uri(self, payments=None, address='', payment_id='', amount=0, tx_description='', recipient_name=''): - """ - Unified make_uri method. - - If 'payments' is provided (a list), the new multi-recipient format is used (old format, but multi data is separated by semi-colon). - Otherwise, if no payments list is provided, the legacy format is assumed and - a single payment is created from the legacy parameters (address, amount, recipient_name). - - Existing parameter names remain unchanged for backwards compatibility. - The underlying C++ implementation provides overloads: - - make_uri(vector, payment_id, tx_description, error) - - make_uri(address, payment_id, amount, tx_description, recipient_name, error) - - Either provide: - #1 payments{address,amount,recipient_name}, payment_id, tx_description (supports multi-uri) - #2: address, payment_id, amount, tx_description, recipient_name (obsolete, legacy, kept for backwards-compatibility) - Standalone payment IDs are not supported and will result into errors. - """ - # if payments is None or an empty list, assume legacy mode: - if not payments: - # in legacy mode, the address must be nonempty. - if not address: - raise Exception("No address provided") - payments = [{ + def make_uri(self, address = '', payment_id = '', amount = 0, tx_description = '', recipient_name = ''): + make_uri = { + 'method': 'make_uri', + 'jsonrpc': '2.0', + 'params': { 'address': address, + 'payment_id': payment_id, 'amount': amount, - 'recipient_name': recipient_name - }] - make_uri = { + 'tx_description': tx_description, + 'recipient_name': recipient_name, + }, + 'id': '0' + } + return self.rpc.send_json_rpc_request(make_uri) + + def parse_uri(self, uri): + parse_uri = { + 'method': 'parse_uri', + 'jsonrpc': '2.0', + 'params': { + 'uri': uri, + }, + 'id': '0' + } + return self.rpc.send_json_rpc_request(parse_uri) + + def make_uri_v2(self, payments, payment_id, tx_description): + make_uri_v2 = { 'method': 'make_uri', 'jsonrpc': '2.0', 'params': { @@ -1026,9 +1024,9 @@ def make_uri(self, payments=None, address='', payment_id='', amount=0, tx_descri }, 'id': '0' } - return self.rpc.send_json_rpc_request(make_uri) + return self.rpc.send_json_rpc_request(make_uri_v2) - def parse_uri(self, uri): + def parse_uri_v2(self, uri): parse_uri = { 'method': 'parse_uri', 'jsonrpc': '2.0', From 6f27307bcc6e74a2e883849c4e9d3c7dc12e00ba Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Tue, 11 Feb 2025 07:12:28 +0530 Subject: [PATCH 33/50] add new-lines --- tests/functional_tests/uri.py | 2 +- tests/unit_tests/uri.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/functional_tests/uri.py b/tests/functional_tests/uri.py index b0bb7f1e4de..bfae981d8e5 100755 --- a/tests/functional_tests/uri.py +++ b/tests/functional_tests/uri.py @@ -331,4 +331,4 @@ def test_multi_uri(self): assert parsed.unknown_parameters == ['foo=bar', 'baz=quux'], "Unknown parameters mismatch" if __name__ == '__main__': - URITest().run_test() \ No newline at end of file + URITest().run_test() diff --git a/tests/unit_tests/uri.cpp b/tests/unit_tests/uri.cpp index 7ddfb938be7..5ba1d4e7e4d 100644 --- a/tests/unit_tests/uri.cpp +++ b/tests/unit_tests/uri.cpp @@ -312,4 +312,4 @@ TEST(uri, multiple_addresses_all_params_correct) ASSERT_EQ(data[1].amount, 200000000000); ASSERT_EQ(data[1].recipient_name, "Bob"); ASSERT_EQ(description, "Payment for services"); -} \ No newline at end of file +} From 01d3a9402102b5f85f2a5a81763e629da33f7572 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Tue, 11 Feb 2025 07:26:10 +0530 Subject: [PATCH 34/50] fix occurrences of uri funcs --- src/simplewallet/simplewallet.cpp | 2 +- src/wallet/wallet_rpc_server.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index ac1349b83f6..178ee647869 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6535,7 +6535,7 @@ bool simple_wallet::transfer_main(const std::vector &args_, bool ca std::string payment_id_uri, tx_description, error; std::vector unknown_parameters; std::vector uri_data; - bool has_uri = m_wallet->parse_uri(local_args[i], uri_data, payment_id_uri, tx_description, unknown_parameters, error); + bool has_uri = m_wallet->parse_uri_v2(local_args[i], uri_data, payment_id_uri, tx_description, unknown_parameters, error); if (has_uri) { diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index d5c96cc7cfc..3f4450e7f5a 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -3134,7 +3134,7 @@ namespace tools entry_data.recipient_name = entry.recipient_name; data.push_back(entry_data); } - std::string uri = m_wallet->make_uri(data, req.payment_id, req.tx_description, error); + std::string uri = m_wallet->make_uri_v2(data, req.payment_id, req.tx_description, error); if (uri.empty()) { @@ -3165,7 +3165,7 @@ namespace tools if (!m_wallet) return not_open(er); std::string error; std::vector uri_data; - if (!m_wallet->parse_uri(req.uri, uri_data, res.uri.payment_id, res.uri.tx_description, res.unknown_parameters, error)) + if (!m_wallet->parse_uri_v2(req.uri, uri_data, res.uri.payment_id, res.uri.tx_description, res.unknown_parameters, error)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_URI; er.message = "Error parsing URI: " + error; From 5b1f082b94b5e66f36f1cd5192357f7842cca43b Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Tue, 11 Feb 2025 07:48:44 +0530 Subject: [PATCH 35/50] remove v2 uri funcs as C++ differs them through function overloading anyways --- src/simplewallet/simplewallet.cpp | 2 +- src/wallet/api/wallet.cpp | 8 ++++---- src/wallet/api/wallet.h | 4 ++-- src/wallet/wallet2.cpp | 10 +++++----- src/wallet/wallet2.h | 4 ++-- src/wallet/wallet_rpc_server.cpp | 4 ++-- tests/unit_tests/uri.cpp | 28 ++++++++++++++-------------- 7 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 178ee647869..ac1349b83f6 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6535,7 +6535,7 @@ bool simple_wallet::transfer_main(const std::vector &args_, bool ca std::string payment_id_uri, tx_description, error; std::vector unknown_parameters; std::vector uri_data; - bool has_uri = m_wallet->parse_uri_v2(local_args[i], uri_data, payment_id_uri, tx_description, unknown_parameters, error); + bool has_uri = m_wallet->parse_uri(local_args[i], uri_data, payment_id_uri, tx_description, unknown_parameters, error); if (has_uri) { diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 17238e02814..cd4d266f867 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2553,9 +2553,9 @@ bool WalletImpl::parse_uri(const std::string& uri, std::string& address, std::st return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error); } -bool WalletImpl::parse_uri_v2(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) +bool WalletImpl::parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) { - return m_wallet->parse_uri_v2(uri, data, payment_id, tx_description, unknown_parameters, error); + return m_wallet->parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error); } std::string WalletImpl::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const @@ -2563,9 +2563,9 @@ std::string WalletImpl::make_uri(const std::string &address, const std::string & return m_wallet->make_uri(address, payment_id, amount, tx_description, recipient_name, error); } -std::string WalletImpl::make_uri_v2(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const +std::string WalletImpl::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const { - return m_wallet->make_uri_v2(data, payment_id, tx_description, error); + return m_wallet->make_uri(data, payment_id, tx_description, error); } std::string WalletImpl::getDefaultDataDir() const diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index b6d26de05fa..f32553678e2 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -214,9 +214,9 @@ class WalletImpl : public Wallet virtual void startRefresh() override; virtual void pauseRefresh() override; virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) override; - virtual bool parse_uri_v2(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); + virtual bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const override; - virtual std::string make_uri_v2(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; + virtual std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; virtual std::string getDefaultDataDir() const override; virtual bool blackballOutputs(const std::vector &outputs, bool add) override; virtual bool blackballOutput(const std::string &amount, const std::string &offset) override; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 2c76e5d2c0e..214a7d27690 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14970,7 +14970,7 @@ std::string wallet2::custom_conver_to_url_format(const std::string &uri) const return result; } //---------------------------------------------------------------------------------------------------- -std::string wallet2::make_uri_v2(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const +std::string wallet2::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const { if (data.empty()) { @@ -15065,10 +15065,10 @@ std::string wallet2::make_uri(const std::string &address, const std::string &pay std::vector data; data.push_back(entry); - return make_uri_v2(data, payment_id, tx_description, error); + return make_uri(data, payment_id, tx_description, error); } //---------------------------------------------------------------------------------------------------- -bool wallet2::parse_uri_v2(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) +bool wallet2::parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) { if (uri.substr(0, 7) != "monero:") { @@ -15224,14 +15224,14 @@ bool wallet2::parse_uri_v2(const std::string &uri, std::vector &data, bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) { std::vector data; - if (!parse_uri_v2(uri, data, payment_id, tx_description, unknown_parameters, error)) + if (!parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error)) { error = "Failed to parse uri"; return false; } if (data.size() > 1) { - error = "Multi-recipient URIs currently unsupported; please use parse_uri_v2"; + error = "Multi-recipient URIs currently unsupported in this overload"; return false; } address = data[0].address; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 1da025c666f..0f0d02a8b2e 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1649,9 +1649,9 @@ namespace tools std::string decrypt_with_view_secret_key(const std::string &ciphertext, bool authenticated = true) const; std::string custom_conver_to_url_format(const std::string &uri) const; - std::string make_uri_v2(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; + std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const; - bool parse_uri_v2(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); + bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error); uint64_t get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day); // 1<=month<=12, 1<=day<=31 diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 3f4450e7f5a..d5c96cc7cfc 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -3134,7 +3134,7 @@ namespace tools entry_data.recipient_name = entry.recipient_name; data.push_back(entry_data); } - std::string uri = m_wallet->make_uri_v2(data, req.payment_id, req.tx_description, error); + std::string uri = m_wallet->make_uri(data, req.payment_id, req.tx_description, error); if (uri.empty()) { @@ -3165,7 +3165,7 @@ namespace tools if (!m_wallet) return not_open(er); std::string error; std::vector uri_data; - if (!m_wallet->parse_uri_v2(req.uri, uri_data, res.uri.payment_id, res.uri.tx_description, res.unknown_parameters, error)) + if (!m_wallet->parse_uri(req.uri, uri_data, res.uri.payment_id, res.uri.tx_description, res.unknown_parameters, error)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_URI; er.message = "Error parsing URI: " + error; diff --git a/tests/unit_tests/uri.cpp b/tests/unit_tests/uri.cpp index 5ba1d4e7e4d..aa6757c9433 100644 --- a/tests/unit_tests/uri.cpp +++ b/tests/unit_tests/uri.cpp @@ -41,12 +41,12 @@ bool ret = w.parse_uri(uri, address, payment_id, amount, description, recipient_name, unknown_parameters, error); \ ASSERT_EQ(ret, expected); -#define PARSE_URI_V2(uri, expected) \ +#define PARSE_MULTI_URI(uri, expected) \ std::vector data; \ std::string payment_id, description, error; \ std::vector unknown_parameters; \ tools::wallet2 w(cryptonote::TESTNET); \ - bool ret = w.parse_uri_v2(uri, data, payment_id, description, unknown_parameters, error); \ + bool ret = w.parse_uri(uri, data, payment_id, description, unknown_parameters, error); \ ASSERT_EQ(ret, expected); TEST(uri, empty_string) @@ -224,7 +224,7 @@ TEST(uri, url_encoded_once) TEST(uri, multiple_addresses_no_params) { - PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS, true); + PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS, true); ASSERT_EQ(data.size(), 2); ASSERT_EQ(data[0].address, TEST_ADDRESS); ASSERT_EQ(data[1].address, TEST_ADDRESS); @@ -232,7 +232,7 @@ TEST(uri, multiple_addresses_no_params) TEST(uri, multiple_addresses_with_amounts) { - PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0.2", true); + PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0.2", true); ASSERT_EQ(data.size(), 2); ASSERT_EQ(data[0].address, TEST_ADDRESS); ASSERT_EQ(data[0].amount, 500000000000); @@ -242,7 +242,7 @@ TEST(uri, multiple_addresses_with_amounts) TEST(uri, multiple_addresses_with_recipient_names) { - PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice;Bob", true); + PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice;Bob", true); ASSERT_EQ(data.size(), 2); ASSERT_EQ(data[0].address, TEST_ADDRESS); ASSERT_EQ(data[0].recipient_name, "Alice"); @@ -252,17 +252,17 @@ TEST(uri, multiple_addresses_with_recipient_names) TEST(uri, multiple_addresses_with_mismatched_amounts) { - PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5", false); + PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5", false); } TEST(uri, multiple_addresses_with_mismatched_recipient_names) { - PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice", false); + PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice", false); } TEST(uri, multiple_addresses_with_partial_params) { - PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0&recipient_name=Alice;", true); + PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0&recipient_name=Alice;", true); ASSERT_EQ(data.size(), 2); ASSERT_EQ(data[0].address, TEST_ADDRESS); ASSERT_EQ(data[0].amount, 500000000000); @@ -274,36 +274,36 @@ TEST(uri, multiple_addresses_with_partial_params) TEST(uri, multiple_addresses_with_unknown_params) { - PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?unknown_param=123;456", true); + PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?unknown_param=123;456", true); ASSERT_EQ(unknown_parameters.size(), 1); ASSERT_EQ(unknown_parameters[0], "unknown_param=123;456"); } TEST(uri, multiple_addresses_with_payment_id) { - PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=1234567890123456789012345678901234567890123456789012345678901234", true); + PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=1234567890123456789012345678901234567890123456789012345678901234", true); ASSERT_EQ(payment_id, "1234567890123456789012345678901234567890123456789012345678901234"); } TEST(uri, multiple_addresses_with_invalid_payment_id) { - PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=123456", false); + PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_payment_id=123456", false); } TEST(uri, multiple_addresses_with_description) { - PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_description=Payment%20for%20services", true); + PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_description=Payment%20for%20services", true); ASSERT_EQ(description, "Payment for services"); } TEST(uri, multiple_addresses_mismatched_params) { - PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5&recipient_name=Alice", false); + PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5&recipient_name=Alice", false); } TEST(uri, multiple_addresses_all_params_correct) { - PARSE_URI_V2("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0.2&recipient_name=Alice;Bob&tx_description=Payment%20for%20services", true); + PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0.2&recipient_name=Alice;Bob&tx_description=Payment%20for%20services", true); ASSERT_EQ(data.size(), 2); ASSERT_EQ(data[0].address, TEST_ADDRESS); ASSERT_EQ(data[0].amount, 500000000000); From 0d7cb1ab44495d1752508341e63099884c352011 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Tue, 11 Feb 2025 12:51:04 +0530 Subject: [PATCH 36/50] fix make_uri_v2 and parse_uri_v2 calling make_uri and parse_uri in python rpc server --- utils/python-rpc/framework/wallet.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/python-rpc/framework/wallet.py b/utils/python-rpc/framework/wallet.py index d4303c31ade..7d7c9773274 100644 --- a/utils/python-rpc/framework/wallet.py +++ b/utils/python-rpc/framework/wallet.py @@ -1015,7 +1015,7 @@ def parse_uri(self, uri): def make_uri_v2(self, payments, payment_id, tx_description): make_uri_v2 = { - 'method': 'make_uri', + 'method': 'make_uri_v2', 'jsonrpc': '2.0', 'params': { 'payments': payments, @@ -1028,7 +1028,7 @@ def make_uri_v2(self, payments, payment_id, tx_description): def parse_uri_v2(self, uri): parse_uri = { - 'method': 'parse_uri', + 'method': 'parse_uri_v2', 'jsonrpc': '2.0', 'params': { 'uri': uri, From 3562a5041efdf9147dde3ac08f48bdec48cb2419 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Tue, 11 Feb 2025 17:23:07 +0530 Subject: [PATCH 37/50] fix uri.py not providing payment_id to one of the tests --- tests/functional_tests/uri.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional_tests/uri.py b/tests/functional_tests/uri.py index bfae981d8e5..fc3acfc36df 100755 --- a/tests/functional_tests/uri.py +++ b/tests/functional_tests/uri.py @@ -312,7 +312,7 @@ def test_multi_uri(self): ] # the RPC should URL-encode these parameters. - res = wallet.make_uri_v2(payments=payments, tx_description=special_desc) + res = wallet.make_uri_v2(payments=payments, payment_id='', tx_description=special_desc) parsed = wallet.parse_uri_v2(res.uri) # check that the decoded values match the original. for pay in parsed.uri.payments: From 33ad3f064cfc6c1e5998bd763ecddeda80494776 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Tue, 11 Feb 2025 20:44:28 +0530 Subject: [PATCH 38/50] remove extra new lines in wallet2_api.h --- src/wallet/api/wallet2_api.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 46dcf1f9b75..2bedcc7d280 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1066,10 +1066,8 @@ struct Wallet virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const = 0; virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) = 0; - virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const = 0; - virtual std::string getDefaultDataDir() const = 0; /* From 71aa95edac88d64a72b3fc572fff958a18451531 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 12 Feb 2025 17:47:46 +0530 Subject: [PATCH 39/50] only accept standard types as parameters --- src/simplewallet/simplewallet.cpp | 12 +- src/wallet/api/wallet.cpp | 8 +- src/wallet/api/wallet.h | 4 +- src/wallet/api/wallet2_api.h | 4 +- src/wallet/wallet2.cpp | 124 ++++++++----------- src/wallet/wallet2.h | 7 -- src/wallet/wallet_rpc_server.cpp | 33 ++--- src/wallet/wallet_rpc_server_commands_defs.h | 31 ++--- tests/functional_tests/uri.py | 76 +++++------- tests/unit_tests/uri.cpp | 61 ++++----- utils/python-rpc/framework/wallet.py | 6 +- 11 files changed, 165 insertions(+), 201 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index ac1349b83f6..42cdbdf916d 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6534,14 +6534,16 @@ bool simple_wallet::transfer_main(const std::vector &args_, bool ca // check for a URI std::string payment_id_uri, tx_description, error; std::vector unknown_parameters; - std::vector uri_data; - bool has_uri = m_wallet->parse_uri(local_args[i], uri_data, payment_id_uri, tx_description, unknown_parameters, error); + std::vector addresses; + std::vector amounts; + std::vector recipient_names; + bool has_uri = m_wallet->parse_uri(local_args[i], addresses, amounts, recipient_names, payment_id_uri, tx_description, unknown_parameters, error); if (has_uri) { for (size_t j = 0; j < uri_data.size(); j++) { - r = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), uri_data[j].address, oa_prompter); + r = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), addresses[j], oa_prompter); if (payment_id_uri.size() == 16) { if (!tools::wallet2::parse_short_payment_id(payment_id_uri, info.payment_id)) @@ -6551,8 +6553,8 @@ bool simple_wallet::transfer_main(const std::vector &args_, bool ca } info.has_payment_id = true; } - de.amount = uri_data[j].amount; - de.original = uri_data[j].address; + de.amount = amounts[j]; + de.original = addresses[j]; if (!r) { fail_msg_writer() << tr("failed to parse address"); diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index cd4d266f867..a2677f82d6b 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2553,9 +2553,9 @@ bool WalletImpl::parse_uri(const std::string& uri, std::string& address, std::st return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error); } -bool WalletImpl::parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) +bool WalletImpl::parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) { - return m_wallet->parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error); + return m_wallet->parse_uri(uri, addresses, amounts, recipient_names, payment_id, tx_description, unknown_parameters, error); } std::string WalletImpl::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const @@ -2563,9 +2563,9 @@ std::string WalletImpl::make_uri(const std::string &address, const std::string & return m_wallet->make_uri(address, payment_id, amount, tx_description, recipient_name, error); } -std::string WalletImpl::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const +std::string WalletImpl::make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const { - return m_wallet->make_uri(data, payment_id, tx_description, error); + return m_wallet->make_uri(addresses, amounts, recipient_names, payment_id, tx_description, error); } std::string WalletImpl::getDefaultDataDir() const diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index f32553678e2..263641ca4e1 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -214,9 +214,9 @@ class WalletImpl : public Wallet virtual void startRefresh() override; virtual void pauseRefresh() override; virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) override; - virtual bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); + virtual bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) override; virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const override; - virtual std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; + virtual std::string make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const override; virtual std::string getDefaultDataDir() const override; virtual bool blackballOutputs(const std::vector &outputs, bool add) override; virtual bool blackballOutput(const std::string &amount, const std::string &offset) override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 2bedcc7d280..746ff94f0c2 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1066,8 +1066,10 @@ struct Wallet virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const = 0; virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) = 0; + bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) override; + virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const = 0; - + std::string make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const override; virtual std::string getDefaultDataDir() const = 0; /* diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 214a7d27690..25d9c8a9f51 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14970,24 +14970,32 @@ std::string wallet2::custom_conver_to_url_format(const std::string &uri) const return result; } //---------------------------------------------------------------------------------------------------- -std::string wallet2::make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const +std::string wallet2::make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const { - if (data.empty()) + if (addresses.empty()) { error = "No recipient data provided."; return std::string(); } - std::string addresses = ""; - std::string amounts = ""; + + if (addresses.size() != amounts.size() || addresses.size() != recipient_names.size()) + { + error = "Mismatch between the number of addresses, amounts, and recipient names."; + return std::string(); + } + + std::string addresses_str = ""; + std::string amounts_str = ""; bool amounts_used = false; - std::string recipients = ""; + std::string recipients_str = ""; bool recipients_used = false; - for (const uri_data& entry : data) - { + + for (size_t i = 0; i < addresses.size(); i++) { + std::string &address = addresses[i]; cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, nettype(), entry.address)) + if (!get_account_address_from_str(info, nettype(), address)) { - error = std::string("wrong address: ") + entry.address; + error = std::string("wrong address: ") + address; return std::string(); } if (info.has_payment_id && !payment_id.empty()) @@ -14995,45 +15003,45 @@ std::string wallet2::make_uri(std::vector data, const std::string &pay error = "Separate payment id given with an integrated address"; return std::string(); } - if (!addresses.empty()) + if (!addresses_str.empty()) { - addresses += ";"; + addresses_str += ";"; } - addresses += entry.address; + addresses_str += address; - if (!amounts.empty()) + if (!amounts_str.empty()) { - amounts += ";"; + amounts_str += ";"; } - if (entry.amount > 0) + if (amounts[i] > 0) { amounts_used = true; } - amounts += cryptonote::print_money(entry.amount); - - if (!recipients.empty()) + amounts_str += cryptonote::print_money(entry.amount); + + if (!recipients_str.empty()) { recipients += ";"; } - if (!entry.recipient_name.empty()) + if (!recipient_names[i].empty()) { recipients_used = true; - recipients += custom_conver_to_url_format(entry.recipient_name); + recipients += custom_conver_to_url_format(recipient_names[i]); } } - std::string uri = "monero:" + addresses; + std::string uri = "monero:" + addresses_str; unsigned int n_fields = 0; if (amounts_used) { // URI encoded amount is in decimal units, not atomic units - uri += (n_fields++ ? "&" : "?") + std::string("tx_amount=") + amounts; + uri += (n_fields++ ? "&" : "?") + std::string("tx_amount=") + amounts_str; } if (recipients_used) { - uri += (n_fields++ ? "&" : "?") + std::string("recipient_name=") + recipients; + uri += (n_fields++ ? "&" : "?") + std::string("recipient_name=") + recipients_str; } if (!tx_description.empty()) @@ -15057,18 +15065,13 @@ std::string wallet2::make_uri(std::vector data, const std::string &pay //---------------------------------------------------------------------------------------------------- std::string wallet2::make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const { - tools::wallet2::uri_data entry; - entry.address = address; - entry.amount = amount; - entry.recipient_name = recipient_name; - - std::vector data; - data.push_back(entry); - - return make_uri(data, payment_id, tx_description, error); + std::vector addresses { address }; + std::vector amounts { amount }; + std::vector recipient_names { recipient_name}; + return make_uri(addresses, amounts, recipient_names, payment_id, tx_description, error); } //---------------------------------------------------------------------------------------------------- -bool wallet2::parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) +bool wallet2::parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) { if (uri.substr(0, 7) != "monero:") { @@ -15079,8 +15082,6 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std std::string remainder = uri.substr(7); const char *ptr = strchr(remainder.c_str(), '?'); std::string addresses_string = ptr ? remainder.substr(0, ptr-remainder.c_str()) : remainder; - std::vector addresses, recipient_names; - std::vector amounts; boost::split(addresses, addresses_string, boost::is_any_of(";")); addresses.erase(std::remove(addresses.begin(), addresses.end(), ""), addresses.end()); @@ -15090,20 +15091,19 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std return false; } - for (const std::string& address : addresses) + for (const std::string &address : addresses) { cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, nettype(), address)) + if (!get_account_address_from_str(info, nettype(), address)) { - error = std::string("URI constains improper address: ") + address; + error = std::string("URI contains improper address: ") + address; return false; } - uri_data recipient_data; - recipient_data.address = address; - recipient_data.amount = 0; - data.push_back(recipient_data); } + amounts.assign(addresses.size(), 0); + recipient_names.assign(addresses.size(), ""); + if (ptr == NULL) return true; @@ -15131,16 +15131,13 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std { std::vector amounts_split; boost::split(amounts_split, kv[1], boost::is_any_of(";")); - size_t expected_size = addresses.size(); - // enforce parameter consistency - if (amounts_split.size() != expected_size) + if (amounts_split.size() != addresses.size()) { error = "Incorrect tx_amount count"; return false; } - for (size_t i = 0; i < amounts_split.size(); i++) { uint64_t amount; @@ -15149,7 +15146,7 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std error = std::string("URI has invalid amount: ") + amounts_split[i]; return false; } - amounts.push_back(amount); + amounts[i] = amount; } } else if (kv[0] == "tx_payment_id") @@ -15173,10 +15170,7 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std { std::vector names_split; boost::split(names_split, kv[1], boost::is_any_of(";")); - size_t expected_size = addresses.size(); - - // enforce parameter consistency - if (names_split.size() != expected_size) + if (names_split.size() != addresses.size()) { error = "Incorrect recipient_name count"; return false; @@ -15184,7 +15178,7 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std for (size_t i = 0; i < names_split.size(); i++) { - recipient_names.push_back(epee::net_utils::convert_from_url_format(names_split[i])); + recipient_names[i] = epee::net_utils::convert_from_url_format(names_split[i]); } } else if (kv[0] == "tx_description") @@ -15207,36 +15201,28 @@ bool wallet2::parse_uri(const std::string &uri, std::vector &data, std error = "Incorrect amount count. Amount count must match address count. Zero may be use as a filler"; return false; } - for(size_t i = 0; i < data.size(); i++) - { - if (!amounts.empty()) - { - data[i].amount = amounts[i]; - } - if (!recipient_names.empty()) - { - data[i].recipient_name = recipient_names[i]; - } - } return true; } //---------------------------------------------------------------------------------------------------- bool wallet2::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) { - std::vector data; - if (!parse_uri(uri, data, payment_id, tx_description, unknown_parameters, error)) + std::vector addresses; + std::vector amounts; + std::vector recipient_names; + + if (!parse_uri(uri, addresses, amounts, recipient_names, payment_id, tx_description, unknown_parameters, error)) { error = "Failed to parse uri"; return false; } - if (data.size() > 1) + if (addresses.size() > 1) { error = "Multi-recipient URIs currently unsupported in this overload"; return false; } - address = data[0].address; - amount = data[0].amount; - recipient_name = data[0].recipient_name; + address = addresses[0]; + amount = amounts[0]; + recipient_name = recipient_names[0]; return true; } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 0f0d02a8b2e..a217ee6b9a0 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -871,13 +871,6 @@ namespace tools bool empty() const { return tx_extra_fields.empty() && primary.empty() && additional.empty(); } }; - struct uri_data - { - std::string address; - uint64_t amount = 0; - std::string recipient_name; - }; - struct detached_blockchain_data { hashchain detached_blockchain; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index d5c96cc7cfc..0dbdba6945f 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -3125,22 +3125,12 @@ namespace tools { if (!m_wallet) return not_open(er); std::string error; - std::vector data; - for (const tools::wallet_rpc::uri_payment &entry : req.payments) - { - tools::wallet2::uri_data entry_data; - entry_data.address = entry.address; - entry_data.amount = entry.amount; - entry_data.recipient_name = entry.recipient_name; - data.push_back(entry_data); - } - std::string uri = m_wallet->make_uri(data, req.payment_id, req.tx_description, error); - + std::string uri = m_wallet->make_uri(req.addresses, req.amounts, req.recipient_names, req.payment_id, req.tx_description, error); if (uri.empty()) { - er.code = WALLET_RPC_ERROR_CODE_WRONG_URI; - er.message = std::string("Cannot make URI from supplied parameters: ") + error; - return false; + er.code = WALLET_RPC_ERROR_CODE_WRONG_URI; + er.message = std::string("Cannot make URI from supplied parameters: ") + error; + return false; } res.uri = uri; @@ -3164,18 +3154,19 @@ namespace tools { if (!m_wallet) return not_open(er); std::string error; - std::vector uri_data; - if (!m_wallet->parse_uri(req.uri, uri_data, res.uri.payment_id, res.uri.tx_description, res.unknown_parameters, error)) + std::vector addresses; + std::vector amounts; + std::vector recipient_names; + if (!m_wallet->parse_uri(req.uri, addresses, amounts, recipient_names, res.uri.payment_id, res.uri.tx_description, res.unknown_parameters, error)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_URI; er.message = "Error parsing URI: " + error; return false; } - for (const tools::wallet2::uri_data &entry : uri_data) - { - tools::wallet_rpc::uri_payment entry_spec = {entry.address, entry.amount, entry.recipient_name}; - res.uri.payments.push_back(entry_spec); - } + + res.uri.addresses = addresses; + res.uri.amounts = amounts; + res.uri.recipient_names = recipient_names; return true; } //------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index f687e6faec1..16dc1474271 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -1829,7 +1829,7 @@ namespace wallet_rpc { std::string address; std::string payment_id; - uint64_t amount; + std::uint64_t amount; std::string tx_description; std::string recipient_name; @@ -1885,27 +1885,18 @@ namespace wallet_rpc typedef epee::misc_utils::struct_init response; }; - struct uri_payment - { - std::string address; - uint64_t amount; - std::string recipient_name; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(address) - KV_SERIALIZE(amount) - KV_SERIALIZE(recipient_name) - END_KV_SERIALIZE_MAP() - }; - struct uri_spec_v2 { - std::vector payments; + std::vector addresses; + std::vector amounts; + std::vector recipient_names; std::string tx_description; std::string payment_id; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(payments); + KV_SERIALIZE(addresses); + KV_SERIALIZE(amounts); + KV_SERIALIZE(recipient_names); KV_SERIALIZE(tx_description); KV_SERIALIZE(payment_id); END_KV_SERIALIZE_MAP() @@ -1915,11 +1906,15 @@ namespace wallet_rpc { struct request_t { - std::vector payments; + std::vector addresses; + std::vector amounts; + std::vector recipient_names; std::string tx_description; std::string payment_id; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(payments); + KV_SERIALIZE(addresses); + KV_SERIALIZE(amounts); + KV_SERIALIZE(recipient_names); KV_SERIALIZE(tx_description); KV_SERIALIZE(payment_id); END_KV_SERIALIZE_MAP() diff --git a/tests/functional_tests/uri.py b/tests/functional_tests/uri.py index fc3acfc36df..44385634099 100755 --- a/tests/functional_tests/uri.py +++ b/tests/functional_tests/uri.py @@ -242,50 +242,44 @@ def test_multi_uri(self): utf8string = [u'えんしゅう', u'あまやかす'] # build multi-recipient URI with two payments. - payments = [ - {'address': addr1, 'amount': 500000000000, 'recipient_name': utf8string[0]}, - {'address': addr2, 'amount': 200000000000, 'recipient_name': utf8string[1]} - ] - res = wallet.make_uri_v2(payments=payments, payment_id='', tx_description='multi test') + addresses = [ addr1, addr2] + amounts = [ 500000000000, 200000000000 ] + recipient_names = [ utf8string[0], utf8string[1]] + res = wallet.make_uri_v2(addresses=addresses, amounts=amounts, recipient_names=recipient_names, payment_id='', tx_description='multi test') + # expect URI like: # monero:addr1;addr2?tx_amount=0.5;0.2&recipient_name=;&tx_description=multi%20test parsed = wallet.parse_uri_v2(res.uri) # verify that both payments are present. assert len(parsed.uri.payments) == 2, "Expected 2 payments in multi-recipient URI" - assert parsed.uri.payments[0].address == addr1 - assert parsed.uri.payments[0].amount == 500000000000 - assert parsed.uri.payments[0].recipient_name == utf8string[0] - assert parsed.uri.payments[1].address == addr2 - assert parsed.uri.payments[1].amount == 200000000000 - assert parsed.uri.payments[1].recipient_name == utf8string[1] + assert parsed.uri.addresses[0] == addr1 + assert parsed.uri.amounts[0] == 500000000000 + assert parsed.uri.recipient_names[0] == utf8string[0] + assert parsed.uri.address[1] == addr2 + assert parsed.uri.amount[1] == 200000000000 + assert parsed.uri.recipient_name[1] == utf8string[1] # check tx_description at the top level. assert parsed.uri.tx_description == 'multi test' assert parsed.uri.payment_id == '' # build multi-recipient URI with three payments. - payments = [ - {'address': addr1, 'amount': 1000000000000, 'recipient_name': utf8string[0]}, - {'address': addr2, 'amount': 500000000000, 'recipient_name': utf8string[1]}, - {'address': addr3, 'amount': 250000000000, 'recipient_name': ''} - ] - res = wallet.make_uri_v2(payments=payments, payment_id='', tx_description='three pay') + addresses = [ addr1, addr2, addr3 ] + amounts = [ 1000000000000, 500000000000, 250000000000 ] + recipient_names = [ utf8string[0], utf8string[1], '' ] + res = wallet.make_uri_v2(addresses=addresses, amounts=amounts, recipient_names=recipient_names, payment_id='', tx_description='three pay') parsed = wallet.parse_uri_v2(res.uri) assert len(parsed.uri.payments) == 3, "Expected 3 payments in multi-recipient URI" - assert parsed.uri.payments[0].address == addr1 - assert parsed.uri.payments[0].amount == 1000000000000 - assert parsed.uri.payments[0].recipient_name == utf8string[0] - assert parsed.uri.payments[1].address == addr2 - assert parsed.uri.payments[1].amount == 500000000000 - assert parsed.uri.payments[1].recipient_name == utf8string[1] - assert parsed.uri.payments[2].address == addr3 - assert parsed.uri.payments[2].amount == 250000000000 - assert parsed.uri.payments[2].recipient_name == '' + assert parsed.uri.address[0] == addr1 + assert parsed.uri.amount[0] == 1000000000000 + assert parsed.uri.recipient_name[0] == utf8string[0] + assert parsed.uri.address[1] == addr2 + assert parsed.uri.amount[1] == 500000000000 + assert parsed.uri.recipient_name[1] == utf8string[1] + assert parsed.uri.address[2] == addr3 + assert parsed.uri.amount[2] == 250000000000 + assert parsed.uri.recipient_name[2] == '' assert parsed.uri.tx_description == 'three pay' - payments = [ - {'address': addr1, 'amount': 500000000000, 'recipient_name': 'Alice'}, - {'address': addr2, 'amount': 0, 'recipient_name': 'Bob'} - ] # manually build a URI with mismatched amounts (remove Bob's amount). # simulate this by concatenating amounts incorrectly. # (this step assumes you have control over the output URI; in practice, the server would reject it. For testing, we assume the RPC returns an error.) @@ -301,32 +295,28 @@ def test_multi_uri(self): uri_trailing = 'monero:' + addr1 + ';' + addr2 + ';' + '?tx_amount=0.5;0.2&recipient_name=Alice;Bob' # depending on the implementation, a trailing empty value might be dropped. parsed = wallet.parse_uri_v2(uri_trailing) - assert len(parsed.uri.payments) == 2, "Trailing delimiter should not add empty payment" + assert len(parsed.uri.addresses) == 2, "Trailing delimiter should not add empty payment" # case: special characters in recipient names and descriptions special_name = "A&B=Test?" special_desc = "Desc with spaces & symbols!" - payments = [ - {'address': addr1, 'amount': 750000000000, 'recipient_name': special_name}, - {'address': addr2, 'amount': 250000000000, 'recipient_name': special_name} - ] + addresses = [ addr1, addr2] + amounts = [ 750000000000, 250000000000 ] + recipient_names = [ special_name, special_name] # the RPC should URL-encode these parameters. - res = wallet.make_uri_v2(payments=payments, payment_id='', tx_description=special_desc) + res = wallet.make_uri_v2(addresses=addresses, amounts=amounts, recipient_names=recipient_names, payment_id='', tx_description=special_desc) parsed = wallet.parse_uri_v2(res.uri) # check that the decoded values match the original. - for pay in parsed.uri.payments: - assert pay.recipient_name == special_name, "Special characters in recipient name mismatch" + for recipient_name in parsed.uri.recipient_names: + assert recipient_name == special_name, "Special characters in recipient name mismatch" assert parsed.uri.tx_description == special_desc, "Special characters in description mismatch" # build a well-formed multi-recipient URI and tack on unknown parameters. - payments = [ - {'address': addr1, 'amount': 239390140000000, 'recipient_name': ''} - ] uri_with_unknown = 'monero:' + addr1 + '?tx_amount=239.39014&foo=bar&baz=quux' parsed = wallet.parse_uri_v2(uri_with_unknown) - assert parsed.uri.payments[0].address == addr1 - assert parsed.uri.payments[0].amount == 239390140000000 + assert parsed.uri.address[0] == addr1 + assert parsed.uri.amount[0] == 239390140000000 # unknown parameters should be collected in the unknown_parameters list. assert parsed.unknown_parameters == ['foo=bar', 'baz=quux'], "Unknown parameters mismatch" diff --git a/tests/unit_tests/uri.cpp b/tests/unit_tests/uri.cpp index aa6757c9433..5216a470373 100644 --- a/tests/unit_tests/uri.cpp +++ b/tests/unit_tests/uri.cpp @@ -42,11 +42,14 @@ ASSERT_EQ(ret, expected); #define PARSE_MULTI_URI(uri, expected) \ - std::vector data; \ + std::vector addresses; \ + std::vector amounts; \ + std::vector recipient_names; \ std::string payment_id, description, error; \ std::vector unknown_parameters; \ tools::wallet2 w(cryptonote::TESTNET); \ - bool ret = w.parse_uri(uri, data, payment_id, description, unknown_parameters, error); \ + bool ret = w.parse_uri(uri, addresses, amounts, recipient_names, \ + payment_id, description, unknown_parameters, error); \ ASSERT_EQ(ret, expected); TEST(uri, empty_string) @@ -225,29 +228,29 @@ TEST(uri, url_encoded_once) TEST(uri, multiple_addresses_no_params) { PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS, true); - ASSERT_EQ(data.size(), 2); - ASSERT_EQ(data[0].address, TEST_ADDRESS); - ASSERT_EQ(data[1].address, TEST_ADDRESS); + ASSERT_EQ(addresses.size(), 2); + ASSERT_EQ(addresses[0], TEST_ADDRESS); + ASSERT_EQ(addresses[1], TEST_ADDRESS); } TEST(uri, multiple_addresses_with_amounts) { PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0.2", true); - ASSERT_EQ(data.size(), 2); - ASSERT_EQ(data[0].address, TEST_ADDRESS); - ASSERT_EQ(data[0].amount, 500000000000); - ASSERT_EQ(data[1].address, TEST_ADDRESS); - ASSERT_EQ(data[1].amount, 200000000000); + ASSERT_EQ(addresses.size(), 2); + ASSERT_EQ(addresses[0], TEST_ADDRESS); + ASSERT_EQ(amounts[0], 500000000000); + ASSERT_EQ(addresses[1], TEST_ADDRESS); + ASSERT_EQ(amounts[1], 200000000000); } TEST(uri, multiple_addresses_with_recipient_names) { PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?recipient_name=Alice;Bob", true); - ASSERT_EQ(data.size(), 2); - ASSERT_EQ(data[0].address, TEST_ADDRESS); - ASSERT_EQ(data[0].recipient_name, "Alice"); - ASSERT_EQ(data[1].address, TEST_ADDRESS); - ASSERT_EQ(data[1].recipient_name, "Bob"); + ASSERT_EQ(addresses.size(), 2); + ASSERT_EQ(addresses[0], TEST_ADDRESS); + ASSERT_EQ(recipient_names[0], "Alice"); + ASSERT_EQ(addresses[1], TEST_ADDRESS); + ASSERT_EQ(recipient_names[1], "Bob"); } TEST(uri, multiple_addresses_with_mismatched_amounts) @@ -263,13 +266,13 @@ TEST(uri, multiple_addresses_with_mismatched_recipient_names) TEST(uri, multiple_addresses_with_partial_params) { PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0&recipient_name=Alice;", true); - ASSERT_EQ(data.size(), 2); - ASSERT_EQ(data[0].address, TEST_ADDRESS); - ASSERT_EQ(data[0].amount, 500000000000); - ASSERT_EQ(data[0].recipient_name, "Alice"); - ASSERT_EQ(data[1].address, TEST_ADDRESS); - ASSERT_EQ(data[1].amount, 0); - ASSERT_EQ(data[1].recipient_name, ""); + ASSERT_EQ(addresses.size(), 2); + ASSERT_EQ(addresses[0], TEST_ADDRESS); + ASSERT_EQ(amounts[0], 500000000000); + ASSERT_EQ(recipient_names[0], "Alice"); + ASSERT_EQ(addresses[1], TEST_ADDRESS); + ASSERT_EQ(amounts[1], 0); + ASSERT_EQ(recipient_names[1], ""); } TEST(uri, multiple_addresses_with_unknown_params) @@ -304,12 +307,12 @@ TEST(uri, multiple_addresses_mismatched_params) TEST(uri, multiple_addresses_all_params_correct) { PARSE_MULTI_URI("monero:" TEST_ADDRESS ";" TEST_ADDRESS "?tx_amount=0.5;0.2&recipient_name=Alice;Bob&tx_description=Payment%20for%20services", true); - ASSERT_EQ(data.size(), 2); - ASSERT_EQ(data[0].address, TEST_ADDRESS); - ASSERT_EQ(data[0].amount, 500000000000); - ASSERT_EQ(data[0].recipient_name, "Alice"); - ASSERT_EQ(data[1].address, TEST_ADDRESS); - ASSERT_EQ(data[1].amount, 200000000000); - ASSERT_EQ(data[1].recipient_name, "Bob"); + ASSERT_EQ(addresses.size(), 2); + ASSERT_EQ(addresses[0], TEST_ADDRESS); + ASSERT_EQ(amounts[0], 500000000000); + ASSERT_EQ(recipient_names[0], "Alice"); + ASSERT_EQ(addresses[1], TEST_ADDRESS); + ASSERT_EQ(amounts[1], 200000000000); + ASSERT_EQ(recipient_names[1], "Bob"); ASSERT_EQ(description, "Payment for services"); } diff --git a/utils/python-rpc/framework/wallet.py b/utils/python-rpc/framework/wallet.py index 7d7c9773274..dffaae0a669 100644 --- a/utils/python-rpc/framework/wallet.py +++ b/utils/python-rpc/framework/wallet.py @@ -1013,12 +1013,14 @@ def parse_uri(self, uri): } return self.rpc.send_json_rpc_request(parse_uri) - def make_uri_v2(self, payments, payment_id, tx_description): + def make_uri_v2(self, addresses, amounts, recipient_names, payment_id, tx_description): make_uri_v2 = { 'method': 'make_uri_v2', 'jsonrpc': '2.0', 'params': { - 'payments': payments, + 'addresses': addresses, + 'amounts': amounts, + 'recipient_names': recipient_names, 'payment_id': payment_id, 'tx_description': tx_description, }, From 44b70c1e80710e66cb7d0b52c99aacd6a1ff1cad Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 12 Feb 2025 17:55:15 +0530 Subject: [PATCH 40/50] update wallet2 --- src/wallet/wallet2.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index a217ee6b9a0..695e40766bc 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1642,10 +1642,10 @@ namespace tools std::string decrypt_with_view_secret_key(const std::string &ciphertext, bool authenticated = true) const; std::string custom_conver_to_url_format(const std::string &uri) const; - std::string make_uri(std::vector data, const std::string &payment_id, const std::string &tx_description, std::string &error) const; + std::string make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const; std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const; - bool parse_uri(const std::string &uri, std::vector &data, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); - bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error); + bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); + bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error); uint64_t get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day); // 1<=month<=12, 1<=day<=31 From eeb3051e29555ef45e55628ac54a2ff50cc3ff39 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 12 Feb 2025 17:59:40 +0530 Subject: [PATCH 41/50] fix typos and overlooked references to old variables --- src/wallet/wallet2.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 25d9c8a9f51..6ae9ff3ef3e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -15017,16 +15017,16 @@ std::string wallet2::make_uri(std::vector &addresses, std::vector &addresses, std::vector addresses { address }; - std::vector amounts { amount }; + std::vector amounts { amount }; std::vector recipient_names { recipient_name}; return make_uri(addresses, amounts, recipient_names, payment_id, tx_description, error); } From bbcc0430637dd0deef54f8d1e33c7a0c1879d63d Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 12 Feb 2025 18:16:27 +0530 Subject: [PATCH 42/50] fix typos --- src/simplewallet/simplewallet.cpp | 2 +- src/wallet/api/wallet.h | 2 +- src/wallet/api/wallet2_api.h | 4 ++-- src/wallet/wallet2.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 42cdbdf916d..fabb9b9c305 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6541,7 +6541,7 @@ bool simple_wallet::transfer_main(const std::vector &args_, bool ca if (has_uri) { - for (size_t j = 0; j < uri_data.size(); j++) + for (size_t j = 0; j < addresses.size(); j++) { r = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), addresses[j], oa_prompter); if (payment_id_uri.size() == 16) diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 263641ca4e1..d982e1b7fb6 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -216,7 +216,7 @@ class WalletImpl : public Wallet virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) override; virtual bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) override; virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const override; - virtual std::string make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const override; + virtual std::string make_uri(const std::vector &addresses, const std::vector &amounts, const std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const override; virtual std::string getDefaultDataDir() const override; virtual bool blackballOutputs(const std::vector &outputs, bool add) override; virtual bool blackballOutput(const std::string &amount, const std::string &offset) override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 746ff94f0c2..a20c0ad8672 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1066,10 +1066,10 @@ struct Wallet virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const = 0; virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) = 0; - bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) override; + virtual bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) override; virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const = 0; - std::string make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const override; + virtual std::string make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const override; virtual std::string getDefaultDataDir() const = 0; /* diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 695e40766bc..997cbf379c7 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1642,7 +1642,7 @@ namespace tools std::string decrypt_with_view_secret_key(const std::string &ciphertext, bool authenticated = true) const; std::string custom_conver_to_url_format(const std::string &uri) const; - std::string make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const; + std::string make_uri(const std::vector &addresses, const std::vector &amounts, const std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const; std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const; bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); bool parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error); From a647610e4f84cd94a37eca7283d845d891e84f75 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 12 Feb 2025 18:21:49 +0530 Subject: [PATCH 43/50] add const keyword --- src/wallet/wallet2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 6ae9ff3ef3e..ba56e69361f 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14970,7 +14970,7 @@ std::string wallet2::custom_conver_to_url_format(const std::string &uri) const return result; } //---------------------------------------------------------------------------------------------------- -std::string wallet2::make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const +std::string wallet2::make_uri(const std::vector &addresses, const std::vector &amounts, const std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const { if (addresses.empty()) { From c1964b167258ba3883bf2a66167426eaaab3b8f6 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 12 Feb 2025 18:26:40 +0530 Subject: [PATCH 44/50] fix const keyword dropping error --- src/wallet/wallet2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index ba56e69361f..d7024b61f15 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -14991,7 +14991,7 @@ std::string wallet2::make_uri(const std::vector &addresses, const s bool recipients_used = false; for (size_t i = 0; i < addresses.size(); i++) { - std::string &address = addresses[i]; + const std::string &address = addresses[i]; cryptonote::address_parse_info info; if (!get_account_address_from_str(info, nettype(), address)) { From 707700dd546863b6710ba99dabe12fe7fafa624b Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 12 Feb 2025 18:35:30 +0530 Subject: [PATCH 45/50] remove override keyword --- src/wallet/api/wallet2_api.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index a20c0ad8672..a0f843c13d6 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1066,10 +1066,10 @@ struct Wallet virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const = 0; virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) = 0; - virtual bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) override; + virtual bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const = 0; - virtual std::string make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const override; + virtual std::string make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const; virtual std::string getDefaultDataDir() const = 0; /* From 952486e5bcadcdda1da95bf16bde8c5bc9f5c9e0 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 12 Feb 2025 18:45:59 +0530 Subject: [PATCH 46/50] add const keyword to wallet2 interface --- src/wallet/api/wallet2_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index a0f843c13d6..91c8394007b 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1069,7 +1069,7 @@ struct Wallet virtual bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const = 0; - virtual std::string make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const; + virtual std::string make_uri(const std::vector &addresses, const std::vector &amounts, const std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const; virtual std::string getDefaultDataDir() const = 0; /* From cc6decaa48dbb3ce229d37876bd949437d879aa9 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 12 Feb 2025 19:18:55 +0530 Subject: [PATCH 47/50] add const keyword --- src/wallet/api/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index a2677f82d6b..4580b8419be 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2563,7 +2563,7 @@ std::string WalletImpl::make_uri(const std::string &address, const std::string & return m_wallet->make_uri(address, payment_id, amount, tx_description, recipient_name, error); } -std::string WalletImpl::make_uri(std::vector &addresses, std::vector &amounts, std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const +std::string WalletImpl::make_uri(const std::vector &addresses, const std::vector &amounts, const std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const { return m_wallet->make_uri(addresses, amounts, recipient_names, payment_id, tx_description, error); } From 0d8698fcc7d6bceb65110b0d16b1e0f669357073 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 12 Feb 2025 19:58:26 +0530 Subject: [PATCH 48/50] restore unnecessary edits and address sneedlewoods' comments --- src/wallet/api/wallet.cpp | 2 +- src/wallet/api/wallet.h | 4 ++-- src/wallet/api/wallet2_api.h | 4 ++-- tests/functional_tests/uri.py | 34 ++++++++++++++++------------------ 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 4580b8419be..8e3d3872af6 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -2548,7 +2548,7 @@ bool WalletImpl::checkBackgroundSync(const std::string &message) const return false; } -bool WalletImpl::parse_uri(const std::string& uri, std::string& address, std::string& payment_id, uint64_t& amount, std::string& tx_description, std::string& recipient_name, std::vector& unknown_parameters, std::string& error) +bool WalletImpl::parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) { return m_wallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error); } diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index d982e1b7fb6..7445e035919 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -214,9 +214,9 @@ class WalletImpl : public Wallet virtual void startRefresh() override; virtual void pauseRefresh() override; virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) override; - virtual bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) override; + bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) override; virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const override; - virtual std::string make_uri(const std::vector &addresses, const std::vector &amounts, const std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const override; + std::string make_uri(const std::vector &addresses, const std::vector &amounts, const std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const override; virtual std::string getDefaultDataDir() const override; virtual bool blackballOutputs(const std::vector &outputs, bool add) override; virtual bool blackballOutput(const std::string &amount, const std::string &offset) override; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 91c8394007b..9da5b6331bd 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -1066,10 +1066,10 @@ struct Wallet virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const = 0; virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) = 0; - virtual bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error); + virtual bool parse_uri(const std::string &uri, std::vector &addresses, std::vector &amounts, std::vector &recipient_names, std::string &payment_id, std::string &tx_description, std::vector &unknown_parameters, std::string &error) = 0; virtual std::string make_uri(const std::string &address, const std::string &payment_id, uint64_t amount, const std::string &tx_description, const std::string &recipient_name, std::string &error) const = 0; - virtual std::string make_uri(const std::vector &addresses, const std::vector &amounts, const std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const; + virtual std::string make_uri(const std::vector &addresses, const std::vector &amounts, const std::vector &recipient_names, const std::string &payment_id, const std::string &tx_description, std::string &error) const = 0; virtual std::string getDefaultDataDir() const = 0; /* diff --git a/tests/functional_tests/uri.py b/tests/functional_tests/uri.py index 44385634099..479ebf6e5bd 100755 --- a/tests/functional_tests/uri.py +++ b/tests/functional_tests/uri.py @@ -85,20 +85,19 @@ def test_monero_uri(self): assert res.uri == 'monero:' + address res = wallet.parse_uri(res.uri) assert res.uri.address == address - assert res.uri.amount == 0 - assert res.uri.recipient_name == '' assert res.uri.payment_id == '' + assert res.uri.amount == 0 assert res.uri.tx_description == '' - + assert res.uri.recipient_name == '' assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 res = wallet.make_uri(address = address, amount = 11000000000) assert res.uri == 'monero:' + address + '?tx_amount=0.011' or res.uri == 'monero:' + address + '?tx_amount=0.011000000000' res = wallet.parse_uri(res.uri) assert res.uri.address == address - assert res.uri.amount == 11000000000 - assert res.uri.recipient_name == '' assert res.uri.payment_id == '' + assert res.uri.amount == 11000000000 assert res.uri.tx_description == '' + assert res.uri.recipient_name == '' assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 address = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' @@ -107,40 +106,40 @@ def test_monero_uri(self): assert res.uri == 'monero:' + address + '?tx_description=' + quoted_utf8string[0] res = wallet.parse_uri(res.uri) assert res.uri.address == address - assert res.uri.amount == 0 - assert res.uri.recipient_name == '' assert res.uri.payment_id == '' + assert res.uri.amount == 0 assert res.uri.tx_description == utf8string[0] + assert res.uri.recipient_name == '' assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 res = wallet.make_uri(address = address, recipient_name = utf8string[0]) assert res.uri == 'monero:' + address + '?recipient_name=' + quoted_utf8string[0] res = wallet.parse_uri(res.uri) assert res.uri.address == address - assert res.uri.amount == 0 - assert res.uri.recipient_name == utf8string[0] assert res.uri.payment_id == '' + assert res.uri.amount == 0 assert res.uri.tx_description == '' + assert res.uri.recipient_name == utf8string[0] assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1]) assert res.uri == 'monero:' + address + '?recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1] res = wallet.parse_uri(res.uri) assert res.uri.address == address - assert res.uri.amount == 0 - assert res.uri.recipient_name == utf8string[0] assert res.uri.payment_id == '' assert res.uri.tx_description == utf8string[1] + assert res.uri.amount == 0 + assert res.uri.recipient_name == utf8string[0] assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 res = wallet.make_uri(address = address, recipient_name = utf8string[0], tx_description = utf8string[1], amount = 1000000000000) assert res.uri == 'monero:' + address + '?tx_amount=1.000000000000&recipient_name=' + quoted_utf8string[0] + '&tx_description=' + quoted_utf8string[1] res = wallet.parse_uri(res.uri) assert res.uri.address == address - assert res.uri.amount == 1000000000000 - assert res.uri.recipient_name == utf8string[0] assert res.uri.payment_id == '' + assert res.uri.amount == 1000000000000 assert res.uri.tx_description == utf8string[1] + assert res.uri.recipient_name == utf8string[0] assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 # standalone payment ids are supported but not recommended @@ -160,20 +159,19 @@ def test_monero_uri(self): assert res.uri == 'monero:' + address + '?tx_amount=1.000000000000&tx_description=%20' + quoted_utf8string[1] + '%20' + quoted_utf8string[0] + '%20' res = wallet.parse_uri(res.uri) assert res.uri.address == address - assert res.uri.amount == 1000000000000 - assert res.uri.recipient_name == '' assert res.uri.payment_id == '' + assert res.uri.amount == 1000000000000 assert res.uri.tx_description == ' ' + utf8string[1] + ' ' + utf8string[0] + ' ' + assert res.uri.recipient_name == '' assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 # the example from the docs res = wallet.parse_uri('monero:46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em?tx_amount=239.39014&tx_description=donation') assert res.uri.address == '46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em' + assert res.uri.payment_id == '' assert res.uri.amount == 239390140000000 - assert res.uri.recipient_name == '' assert res.uri.tx_description == 'donation' - - assert res.uri.payment_id == '' + assert res.uri.recipient_name == '' assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 # malformed/invalid From c6f16a62984ede40cfa438317725ab2c3ba7a9f1 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 12 Feb 2025 21:40:51 +0530 Subject: [PATCH 49/50] remove some unnecessary edits and old references to removed variables in uri.py --- tests/functional_tests/uri.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/functional_tests/uri.py b/tests/functional_tests/uri.py index 479ebf6e5bd..e818cd7a0d1 100755 --- a/tests/functional_tests/uri.py +++ b/tests/functional_tests/uri.py @@ -127,8 +127,8 @@ def test_monero_uri(self): res = wallet.parse_uri(res.uri) assert res.uri.address == address assert res.uri.payment_id == '' - assert res.uri.tx_description == utf8string[1] assert res.uri.amount == 0 + assert res.uri.tx_description == utf8string[1] assert res.uri.recipient_name == utf8string[0] assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 @@ -168,10 +168,10 @@ def test_monero_uri(self): # the example from the docs res = wallet.parse_uri('monero:46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em?tx_amount=239.39014&tx_description=donation') assert res.uri.address == '46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em' - assert res.uri.payment_id == '' assert res.uri.amount == 239390140000000 assert res.uri.tx_description == 'donation' assert res.uri.recipient_name == '' + assert res.uri.payment_id == '' assert not 'unknown_parameters' in res or len(res.unknown_parameters) == 0 # malformed/invalid @@ -249,7 +249,7 @@ def test_multi_uri(self): # monero:addr1;addr2?tx_amount=0.5;0.2&recipient_name=;&tx_description=multi%20test parsed = wallet.parse_uri_v2(res.uri) # verify that both payments are present. - assert len(parsed.uri.payments) == 2, "Expected 2 payments in multi-recipient URI" + assert len(parsed.uri.addresses) == 2, "Expected 2 payments in multi-recipient URI" assert parsed.uri.addresses[0] == addr1 assert parsed.uri.amounts[0] == 500000000000 assert parsed.uri.recipient_names[0] == utf8string[0] @@ -266,7 +266,7 @@ def test_multi_uri(self): recipient_names = [ utf8string[0], utf8string[1], '' ] res = wallet.make_uri_v2(addresses=addresses, amounts=amounts, recipient_names=recipient_names, payment_id='', tx_description='three pay') parsed = wallet.parse_uri_v2(res.uri) - assert len(parsed.uri.payments) == 3, "Expected 3 payments in multi-recipient URI" + assert len(parsed.uri.addresses) == 3, "Expected 3 payments in multi-recipient URI" assert parsed.uri.address[0] == addr1 assert parsed.uri.amount[0] == 1000000000000 assert parsed.uri.recipient_name[0] == utf8string[0] From 1f14a22fb58e2c1a3973117a8ab87bb8c0d64e03 Mon Sep 17 00:00:00 2001 From: U65535F <132809543+U65535F@users.noreply.github.com> Date: Wed, 12 Feb 2025 23:20:18 +0530 Subject: [PATCH 50/50] fix silly typos --- tests/functional_tests/uri.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/functional_tests/uri.py b/tests/functional_tests/uri.py index e818cd7a0d1..3ea939a7e37 100755 --- a/tests/functional_tests/uri.py +++ b/tests/functional_tests/uri.py @@ -253,9 +253,9 @@ def test_multi_uri(self): assert parsed.uri.addresses[0] == addr1 assert parsed.uri.amounts[0] == 500000000000 assert parsed.uri.recipient_names[0] == utf8string[0] - assert parsed.uri.address[1] == addr2 - assert parsed.uri.amount[1] == 200000000000 - assert parsed.uri.recipient_name[1] == utf8string[1] + assert parsed.uri.addresses[1] == addr2 + assert parsed.uri.amounts[1] == 200000000000 + assert parsed.uri.recipient_names[1] == utf8string[1] # check tx_description at the top level. assert parsed.uri.tx_description == 'multi test' assert parsed.uri.payment_id == '' @@ -267,15 +267,15 @@ def test_multi_uri(self): res = wallet.make_uri_v2(addresses=addresses, amounts=amounts, recipient_names=recipient_names, payment_id='', tx_description='three pay') parsed = wallet.parse_uri_v2(res.uri) assert len(parsed.uri.addresses) == 3, "Expected 3 payments in multi-recipient URI" - assert parsed.uri.address[0] == addr1 - assert parsed.uri.amount[0] == 1000000000000 - assert parsed.uri.recipient_name[0] == utf8string[0] - assert parsed.uri.address[1] == addr2 - assert parsed.uri.amount[1] == 500000000000 - assert parsed.uri.recipient_name[1] == utf8string[1] - assert parsed.uri.address[2] == addr3 - assert parsed.uri.amount[2] == 250000000000 - assert parsed.uri.recipient_name[2] == '' + assert parsed.uri.addresses[0] == addr1 + assert parsed.uri.amounts[0] == 1000000000000 + assert parsed.uri.recipient_names[0] == utf8string[0] + assert parsed.uri.addresses[1] == addr2 + assert parsed.uri.amounts[1] == 500000000000 + assert parsed.uri.recipient_names[1] == utf8string[1] + assert parsed.uri.addresses[2] == addr3 + assert parsed.uri.amounts[2] == 250000000000 + assert parsed.uri.recipient_names[2] == '' assert parsed.uri.tx_description == 'three pay' # manually build a URI with mismatched amounts (remove Bob's amount). @@ -313,8 +313,8 @@ def test_multi_uri(self): # build a well-formed multi-recipient URI and tack on unknown parameters. uri_with_unknown = 'monero:' + addr1 + '?tx_amount=239.39014&foo=bar&baz=quux' parsed = wallet.parse_uri_v2(uri_with_unknown) - assert parsed.uri.address[0] == addr1 - assert parsed.uri.amount[0] == 239390140000000 + assert parsed.uri.addresses[0] == addr1 + assert parsed.uri.amounts[0] == 239390140000000 # unknown parameters should be collected in the unknown_parameters list. assert parsed.unknown_parameters == ['foo=bar', 'baz=quux'], "Unknown parameters mismatch"