aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/api/wallet.cpp11
-rw-r--r--src/wallet/api/wallet.h1
-rw-r--r--src/wallet/api/wallet_manager.cpp65
-rw-r--r--src/wallet/api/wallet_manager.h8
-rw-r--r--src/wallet/wallet2.cpp155
-rw-r--r--src/wallet/wallet2.h7
-rw-r--r--src/wallet/wallet2_api.h18
-rw-r--r--src/wallet/wallet_rpc_server.cpp27
-rw-r--r--src/wallet/wallet_rpc_server.h4
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h56
-rw-r--r--src/wallet/wallet_rpc_server_error_codes.h1
11 files changed, 343 insertions, 10 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 8b873a7e2..a772498cd 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -399,6 +399,11 @@ std::string WalletImpl::integratedAddress(const std::string &payment_id) const
return m_wallet->get_account().get_public_integrated_address_str(pid, m_wallet->testnet());
}
+std::string WalletImpl::path() const
+{
+ return m_wallet->path();
+}
+
bool WalletImpl::store(const std::string &path)
{
clearStatus();
@@ -906,11 +911,11 @@ bool WalletImpl::connectToDaemon()
Wallet::ConnectionStatus WalletImpl::connected() const
{
- bool same_version = false;
- bool is_connected = m_wallet->check_connection(&same_version);
+ uint32_t version = 0;
+ bool is_connected = m_wallet->check_connection(&version);
if (!is_connected)
return Wallet::ConnectionStatus_Disconnected;
- if (!same_version)
+ if ((version >> 16) != CORE_RPC_VERSION_MAJOR)
return Wallet::ConnectionStatus_WrongVersion;
return Wallet::ConnectionStatus_Connected;
}
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 02a46da8c..5e4a64ff8 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -64,6 +64,7 @@ public:
bool setPassword(const std::string &password);
std::string address() const;
std::string integratedAddress(const std::string &payment_id) const;
+ std::string path() const;
bool store(const std::string &path);
std::string filename() const;
std::string keysFilename() const;
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index 2d1c44d0e..25b081921 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -130,9 +130,26 @@ std::string WalletManagerImpl::errorString() const
return m_errorString;
}
-void WalletManagerImpl::setDaemonHost(const std::string &hostname)
+void WalletManagerImpl::setDaemonAddress(const std::string &address)
{
+ m_daemonAddress = address;
+}
+bool WalletManagerImpl::connected(uint32_t *version = NULL) const
+{
+ epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_VERSION::request> req_t = AUTO_VAL_INIT(req_t);
+ epee::json_rpc::response<cryptonote::COMMAND_RPC_GET_VERSION::response, std::string> resp_t = AUTO_VAL_INIT(resp_t);
+ req_t.jsonrpc = "2.0";
+ req_t.id = epee::serialization::storage_entry(0);
+ req_t.method = "get_version";
+ epee::net_utils::http::http_simple_client http_client;
+ bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/json_rpc", req_t, resp_t, http_client);
+ if (!r)
+ return false;
+
+ if (version)
+ *version = resp_t.result.version;
+ return true;
}
bool WalletManagerImpl::checkPayment(const std::string &address_text, const std::string &txid_text, const std::string &txkey_text, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const
@@ -287,6 +304,52 @@ bool WalletManagerImpl::checkPayment(const std::string &address_text, const std:
return true;
}
+uint64_t WalletManagerImpl::blockchainHeight() const
+{
+ cryptonote::COMMAND_RPC_GET_INFO::request ireq;
+ cryptonote::COMMAND_RPC_GET_INFO::response ires;
+
+ epee::net_utils::http::http_simple_client http_client;
+ if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/getinfo", ireq, ires, http_client))
+ return 0;
+ return ires.height;
+}
+
+uint64_t WalletManagerImpl::blockchainTargetHeight() const
+{
+ cryptonote::COMMAND_RPC_GET_INFO::request ireq;
+ cryptonote::COMMAND_RPC_GET_INFO::response ires;
+
+ epee::net_utils::http::http_simple_client http_client;
+ if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/getinfo", ireq, ires, http_client))
+ return 0;
+ return ires.target_height >= ires.height ? ires.target_height : ires.height;
+}
+
+uint64_t WalletManagerImpl::networkDifficulty() const
+{
+ cryptonote::COMMAND_RPC_GET_INFO::request ireq;
+ cryptonote::COMMAND_RPC_GET_INFO::response ires;
+
+ epee::net_utils::http::http_simple_client http_client;
+ if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/getinfo", ireq, ires, http_client))
+ return 0;
+ return ires.difficulty;
+}
+
+double WalletManagerImpl::miningHashRate() const
+{
+ cryptonote::COMMAND_RPC_MINING_STATUS::request mreq;
+ cryptonote::COMMAND_RPC_MINING_STATUS::response mres;
+
+ epee::net_utils::http::http_simple_client http_client;
+ if (!epee::net_utils::invoke_http_json_remote_command2(m_daemonAddress + "/getinfo", mreq, mres, http_client))
+ return 0.0;
+ if (!mres.active)
+ return 0.0;
+ return mres.speed;
+}
+
///////////////////// WalletManagerFactory implementation //////////////////////
WalletManager *WalletManagerFactory::getWalletManager()
diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h
index 489abe764..d454548f8 100644
--- a/src/wallet/api/wallet_manager.h
+++ b/src/wallet/api/wallet_manager.h
@@ -45,12 +45,18 @@ public:
bool walletExists(const std::string &path);
std::vector<std::string> findWallets(const std::string &path);
std::string errorString() const;
- void setDaemonHost(const std::string &hostname);
+ void setDaemonAddress(const std::string &address);
+ bool connected(uint32_t *version) const;
bool checkPayment(const std::string &address, const std::string &txid, const std::string &txkey, const std::string &daemon_address, uint64_t &received, uint64_t &height, std::string &error) const;
+ uint64_t blockchainHeight() const;
+ uint64_t blockchainTargetHeight() const;
+ uint64_t networkDifficulty() const;
+ double miningHashRate() const;
private:
WalletManagerImpl() {}
friend struct WalletManagerFactory;
+ std::string m_daemonAddress;
std::string m_errorString;
};
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 4e200b544..f34bb59e9 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -2221,7 +2221,7 @@ bool wallet2::prepare_file_names(const std::string& file_path)
return true;
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::check_connection(bool *same_version)
+bool wallet2::check_connection(uint32_t *version)
{
boost::lock_guard<boost::mutex> lock(m_daemon_rpc_mutex);
@@ -2239,7 +2239,7 @@ bool wallet2::check_connection(bool *same_version)
return false;
}
- if (same_version)
+ if (version)
{
epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_VERSION::request> req_t = AUTO_VAL_INIT(req_t);
epee::json_rpc::response<cryptonote::COMMAND_RPC_GET_VERSION::response, std::string> resp_t = AUTO_VAL_INIT(resp_t);
@@ -2248,9 +2248,9 @@ bool wallet2::check_connection(bool *same_version)
req_t.method = "get_version";
bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client);
if (!r || resp_t.result.status != CORE_RPC_STATUS_OK)
- *same_version = false;
+ *version = 0;
else
- *same_version = resp_t.result.version == CORE_RPC_VERSION;
+ *version = resp_t.result.version;
}
return true;
@@ -2353,6 +2353,11 @@ void wallet2::check_genesis(const crypto::hash& genesis_hash) const {
THROW_WALLET_EXCEPTION_IF(genesis_hash != m_blockchain[0], error::wallet_internal_error, what);
}
//----------------------------------------------------------------------------------------------------
+std::string wallet2::path() const
+{
+ return m_wallet_file;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::store()
{
store_to("", "");
@@ -4989,6 +4994,148 @@ 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)
+{
+ cryptonote::account_public_address tmp_address;
+ bool has_payment_id;
+ crypto::hash8 new_payment_id;
+ if(!get_account_integrated_address_from_str(tmp_address, has_payment_id, new_payment_id, testnet(), address))
+ {
+ error = std::string("wrong address: ") + address;
+ return std::string();
+ }
+
+ // we want only one payment id
+ if (has_payment_id && !payment_id.empty())
+ {
+ error = "A single payment id is allowed";
+ return std::string();
+ }
+
+ if (!payment_id.empty())
+ {
+ crypto::hash pid32;
+ crypto::hash8 pid8;
+ if (!wallet2::parse_long_payment_id(payment_id, pid32) && !wallet2::parse_short_payment_id(payment_id, pid8))
+ {
+ error = "Invalid payment id";
+ return std::string();
+ }
+ }
+
+ std::string uri = "monero:" + address;
+ bool n_fields = 0;
+
+ if (!payment_id.empty())
+ {
+ uri += (n_fields++ ? "&" : "?") + std::string("tx_payment_id=") + payment_id;
+ }
+
+ if (amount > 0)
+ {
+ // URI encoded amount is in decimal units, not atomic units
+ uri += (n_fields++ ? "&" : "?") + std::string("tx_amount=") + cryptonote::print_money(amount);
+ }
+
+ if (!recipient_name.empty())
+ {
+ uri += (n_fields++ ? "&" : "?") + std::string("recipient_name=") + epee::net_utils::conver_to_url_format(recipient_name);
+ }
+
+ if (!tx_description.empty())
+ {
+ uri += (n_fields++ ? "&" : "?") + std::string("tx_description=") + epee::net_utils::conver_to_url_format(tx_description);
+ }
+
+ 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<std::string> &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(), '?');
+ address = ptr ? remainder.substr(0, ptr-remainder.c_str()) : remainder;
+
+ cryptonote::account_public_address addr;
+ bool has_payment_id;
+ crypto::hash8 new_payment_id;
+ if(!get_account_integrated_address_from_str(addr, has_payment_id, new_payment_id, testnet(), address))
+ {
+ error = std::string("URI has wrong address: ") + address;
+ return false;
+ }
+ if (!strchr(remainder.c_str(), '?'))
+ return true;
+
+ std::vector<std::string> arguments;
+ std::string body = remainder.substr(address.size() + 1);
+ if (body.empty())
+ return true;
+ boost::split(arguments, body, boost::is_any_of("&"));
+ std::set<std::string> have_arg;
+ for (const auto &arg: arguments)
+ {
+ std::vector<std::string> 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")
+ {
+ amount = 0;
+ 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")
+ {
+ if (has_payment_id)
+ {
+ error = "Separate payment id given with an integrated address";
+ return false;
+ }
+ crypto::hash hash;
+ crypto::hash8 hash8;
+ if (!wallet2::parse_long_payment_id(kv[1], hash) && !wallet2::parse_short_payment_id(kv[1], hash8))
+ {
+ 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")
+ {
+ tx_description = epee::net_utils::convert_from_url_format(kv[1]);
+ }
+ else
+ {
+ unknown_parameters.push_back(arg);
+ }
+ }
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::generate_genesis(cryptonote::block& b) {
if (m_testnet)
{
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 88fbe1eaf..dcb6367d1 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -332,6 +332,8 @@ namespace tools
*/
void store_to(const std::string &path, const std::string &password);
+ std::string path() const;
+
/*!
* \brief verifies given password is correct for default wallet keys file
*/
@@ -408,7 +410,7 @@ namespace tools
std::vector<wallet2::pending_tx> create_transactions_all(const cryptonote::account_public_address &address, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t> extra, bool trusted_daemon);
std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t> extra, bool trusted_daemon);
std::vector<pending_tx> create_unmixable_sweep_transactions(bool trusted_daemon);
- bool check_connection(bool *same_version = NULL);
+ bool check_connection(uint32_t *version = NULL);
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
void get_payments(const crypto::hash& payment_id, std::list<wallet2::payment_details>& payments, uint64_t min_height = 0) const;
void get_payments(std::list<std::pair<crypto::hash,wallet2::payment_details>>& payments, uint64_t min_height, uint64_t max_height = (uint64_t)-1) const;
@@ -547,6 +549,9 @@ namespace tools
std::string 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);
+ 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<std::string> &unknown_parameters, std::string &error);
+
private:
/*!
* \brief Stores wallet information to wallet file.
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index e624ffa69..60907b436 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -195,6 +195,7 @@ struct Wallet
virtual std::string errorString() const = 0;
virtual bool setPassword(const std::string &password) = 0;
virtual std::string address() const = 0;
+ virtual std::string path() const = 0;
/*!
* \brief integratedAddress - returns integrated address for current wallet address and given payment_id.
@@ -486,6 +487,23 @@ struct WalletManager
//! returns verbose error string regarding last error;
virtual std::string errorString() const = 0;
+ //! set the daemon address (hostname and port)
+ virtual void setDaemonAddress(const std::string &address) = 0;
+
+ //! returns whether the daemon can be reached, and its version number
+ virtual bool connected(uint32_t *version = NULL) const = 0;
+
+ //! returns current blockchain height
+ virtual uint64_t blockchainHeight() const = 0;
+
+ //! returns current blockchain target height
+ virtual uint64_t blockchainTargetHeight() const = 0;
+
+ //! returns current network difficulty
+ virtual uint64_t networkDifficulty() const = 0;
+
+ //! returns current mining hash rate (0 if not mining)
+ virtual double miningHashRate() const = 0;
};
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 2135e7b56..5352b0b73 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -1075,6 +1075,33 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ 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)
+ {
+ 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_parse_uri(const wallet_rpc::COMMAND_RPC_PARSE_URI::request& req, wallet_rpc::COMMAND_RPC_PARSE_URI::response& res, epee::json_rpc::error& 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;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
}
int main(int argc, char** argv) {
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index 4eceb1d55..7d6f94e56 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -80,6 +80,8 @@ namespace tools
MAP_JON_RPC_WE("verify", on_verify, wallet_rpc::COMMAND_RPC_VERIFY)
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("parse_uri", on_parse_uri, wallet_rpc::COMMAND_RPC_PARSE_URI)
END_JSON_RPC_MAP()
END_URI_MAP2()
@@ -107,6 +109,8 @@ namespace tools
bool on_verify(const wallet_rpc::COMMAND_RPC_VERIFY::request& req, wallet_rpc::COMMAND_RPC_VERIFY::response& res, epee::json_rpc::error& er);
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);
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);
+ 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);
+ 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);
bool handle_command_line(const boost::program_options::variables_map& vm);
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 76de7bc9d..50b1613f9 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -703,5 +703,61 @@ namespace wallet_rpc
};
};
+ 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: public uri_spec
+ {
+ };
+
+ struct response
+ {
+ std::string uri;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(uri)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ struct COMMAND_RPC_PARSE_URI
+ {
+ struct request
+ {
+ std::string uri;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(uri)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ uri_spec uri;
+ std::vector<std::string> unknown_parameters;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(uri);
+ KV_SERIALIZE(unknown_parameters);
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
}
}
diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h
index 4617a1449..38fbffcc2 100644
--- a/src/wallet/wallet_rpc_server_error_codes.h
+++ b/src/wallet/wallet_rpc_server_error_codes.h
@@ -41,3 +41,4 @@
#define WALLET_RPC_ERROR_CODE_WRONG_TXID -8
#define WALLET_RPC_ERROR_CODE_WRONG_SIGNATURE -9
#define WALLET_RPC_ERROR_CODE_WRONG_KEY_IMAGE -10
+#define WALLET_RPC_ERROR_CODE_WRONG_URI -11