// DragonX Wallet - ImGui Edition // Copyright 2024-2026 The Hush Developers // Released under the GPLv3 #pragma once #include "types.h" #include #include #include #include #include #include namespace dragonx { namespace rpc { using json = nlohmann::json; using Callback = std::function; using ErrorCallback = std::function; /** * @brief A JSON-RPC error carrying the daemon's numeric error code. * * what() preserves the exact human-readable message (so existing string matching * still works); `code` exposes the JSON-RPC error code — notably -28 (RPC_IN_WARMUP) * for a daemon still starting up. Derives from std::runtime_error, so every existing * `catch (const std::exception&)` continues to handle it unchanged. */ class RpcError : public std::runtime_error { public: RpcError(int errorCode, const std::string& message) : std::runtime_error(message), code(errorCode) {} int code = 0; }; /** * @brief JSON-RPC client for dragonxd * * Handles all communication with the dragonxd daemon via JSON-RPC. */ class RPCClient { public: using TraceCallback = std::function; class TraceScope { public: explicit TraceScope(std::string source); ~TraceScope(); TraceScope(const TraceScope&) = delete; TraceScope& operator=(const TraceScope&) = delete; private: std::string previous_; }; RPCClient(); ~RPCClient(); // Non-copyable RPCClient(const RPCClient&) = delete; RPCClient& operator=(const RPCClient&) = delete; /** * @brief Connect to dragonxd * @param host RPC host (default: 127.0.0.1) * @param port RPC port (default: 18031) * @param user RPC username * @param password RPC password * @return true if connection successful */ bool connect(const std::string& host, const std::string& port, const std::string& user, const std::string& password); bool connect(const std::string& host, const std::string& port, const std::string& user, const std::string& password, bool useTls); /** * @brief Disconnect from dragonxd */ void disconnect(); /** * @brief Check if connected */ bool isConnected() const { return connected_; } /** * @brief True if the last connect() succeeded but daemon returned a warmup error. * The curl handle is valid and auth succeeded — RPC calls will throw warmup errors * until the daemon finishes initializing. */ bool isWarmingUp() const { return warming_up_; } /** * @brief The warmup status message (e.g. "Activating best chain..."). * Empty when not in warmup. */ const std::string& getWarmupStatus() const { return warmup_status_; } /** * @brief Get the error message from the last failed connect() attempt. */ const std::string& getLastConnectError() const { return last_connect_error_; } json getLastConnectInfo() const; static void setTraceCallback(TraceCallback callback); static void setTraceEnabled(bool enabled); static bool isTraceEnabled(); static std::string currentTraceSource(); static void setTraceSource(std::string source); /** * @brief Make a raw RPC call * @param method RPC method name * @param params Method parameters (optional) * @return JSON response or null on error */ json call(const std::string& method, const json& params = json::array()); /** * @brief Make a raw RPC call with a custom timeout * @param method RPC method name * @param params Method parameters * @param timeoutSec Timeout in seconds (0 = no timeout) * @return JSON response or throws on error */ json call(const std::string& method, const json& params, long timeoutSec); /** * @brief Make a raw RPC call and return the result field as a string * @param method RPC method name * @param params Method parameters (optional) * @return Raw JSON string of the "result" field (preserves key order) */ std::string callRaw(const std::string& method, const json& params = json::array()); // High-level API methods - mirror the Qt version // Info methods void getInfo(Callback cb, ErrorCallback err = nullptr); void getBlockchainInfo(Callback cb, ErrorCallback err = nullptr); void getMiningInfo(Callback cb, ErrorCallback err = nullptr); // Balance methods void getBalance(Callback cb, ErrorCallback err = nullptr); void z_getTotalBalance(Callback cb, ErrorCallback err = nullptr); void listUnspent(Callback cb, ErrorCallback err = nullptr); void z_listUnspent(Callback cb, ErrorCallback err = nullptr); // Address methods void getAddressesByAccount(Callback cb, ErrorCallback err = nullptr); void z_listAddresses(Callback cb, ErrorCallback err = nullptr); void getNewAddress(Callback cb, ErrorCallback err = nullptr); void z_getNewAddress(Callback cb, ErrorCallback err = nullptr); // Transaction methods void listTransactions(int count, Callback cb, ErrorCallback err = nullptr); void z_viewTransaction(const std::string& txid, Callback cb, ErrorCallback err = nullptr); void getRawTransaction(const std::string& txid, Callback cb, ErrorCallback err = nullptr); void sendToAddress(const std::string& address, double amount, Callback cb, ErrorCallback err = nullptr); void z_sendMany(const std::string& from, const json& recipients, Callback cb, ErrorCallback err = nullptr); // Mining methods void setGenerate(bool generate, int threads, Callback cb, ErrorCallback err = nullptr); void getNetworkHashPS(Callback cb, ErrorCallback err = nullptr); void getLocalHashrate(Callback cb, ErrorCallback err = nullptr); // Peer methods void getPeerInfo(Callback cb, ErrorCallback err = nullptr); void listBanned(Callback cb, ErrorCallback err = nullptr); void setBan(const std::string& ip, const std::string& command, Callback cb, ErrorCallback err = nullptr, int bantime = 86400); void clearBanned(Callback cb, ErrorCallback err = nullptr); // Key management void dumpPrivKey(const std::string& address, Callback cb, ErrorCallback err = nullptr); void z_exportKey(const std::string& address, Callback cb, ErrorCallback err = nullptr); void z_exportViewingKey(const std::string& address, Callback cb, ErrorCallback err = nullptr); void importPrivKey(const std::string& key, bool rescan, Callback cb, ErrorCallback err = nullptr); void z_importKey(const std::string& key, bool rescan, Callback cb, ErrorCallback err = nullptr); // Utility void validateAddress(const std::string& address, Callback cb, ErrorCallback err = nullptr); void z_validateAddress(const std::string& address, Callback cb, ErrorCallback err = nullptr); void getBlock(const std::string& hash_or_height, Callback cb, ErrorCallback err = nullptr); void getBlockHash(int height, Callback cb, ErrorCallback err = nullptr); void getTransaction(const std::string& txid, Callback cb, ErrorCallback err = nullptr); void getWalletInfo(Callback cb, ErrorCallback err = nullptr); void stop(Callback cb, ErrorCallback err = nullptr); // Wallet maintenance void rescanBlockchain(int startHeight, Callback cb, ErrorCallback err = nullptr); // Wallet encryption & locking void encryptWallet(const std::string& passphrase, Callback cb, ErrorCallback err = nullptr); void walletPassphrase(const std::string& passphrase, int timeout, Callback cb, ErrorCallback err = nullptr); void walletLock(Callback cb, ErrorCallback err = nullptr); void walletPassphraseChange(const std::string& oldPass, const std::string& newPass, Callback cb, ErrorCallback err = nullptr); // Wallet export/import (for decrypt flow) void z_exportWallet(const std::string& filename, Callback cb, ErrorCallback err = nullptr); void z_importWallet(const std::string& filename, Callback cb, ErrorCallback err = nullptr); // Shielding operations void z_shieldCoinbase(const std::string& fromAddr, const std::string& toAddr, double fee, int limit, Callback cb, ErrorCallback err = nullptr); void z_mergeToAddress(const std::vector& fromAddrs, const std::string& toAddr, double fee, int limit, Callback cb, ErrorCallback err = nullptr); // Operation status monitoring void z_getOperationStatus(const std::vector& opids, Callback cb, ErrorCallback err = nullptr); void z_getOperationResult(const std::vector& opids, Callback cb, ErrorCallback err = nullptr); // Received transactions void z_listReceivedByAddress(const std::string& address, int minconf, Callback cb, ErrorCallback err = nullptr); // Unified callback versions (result + error) using UnifiedCallback = std::function; void getInfo(UnifiedCallback cb); void rescanBlockchain(int startHeight, UnifiedCallback cb); void z_shieldCoinbase(const std::string& fromAddr, const std::string& toAddr, double fee, int limit, UnifiedCallback cb); void z_mergeToAddress(const std::vector& fromAddrs, const std::string& toAddr, double fee, int limit, UnifiedCallback cb); void z_getOperationStatus(const std::vector& opids, UnifiedCallback cb); void getBlock(int height, UnifiedCallback cb); private: json makePayload(const std::string& method, const json& params = json::array()); void doRPC(const std::string& method, const json& params, Callback cb, ErrorCallback err); std::string host_; std::string port_; std::string auth_; // Base64 encoded "user:password" bool connected_ = false; bool warming_up_ = false; std::string warmup_status_; std::string last_connect_error_; json last_connect_info_; mutable std::recursive_mutex curl_mutex_; // serializes all curl handle access // HTTP client (implementation hidden) class Impl; std::unique_ptr impl_; }; } // namespace rpc } // namespace dragonx