ObsidianDragon - DragonX ImGui Wallet
Full-node GUI wallet for DragonX cryptocurrency. Built with Dear ImGui, SDL3, and OpenGL3/DX11. Features: - Send/receive shielded and transparent transactions - Autoshield with merged transaction display - Built-in CPU mining (xmrig) - Peer management and network monitoring - Wallet encryption with PIN lock - QR code generation for receive addresses - Transaction history with pagination - Console for direct RPC commands - Cross-platform (Linux, Windows)
This commit is contained in:
184
src/data/address_book.cpp
Normal file
184
src/data/address_book.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
// DragonX Wallet - ImGui Edition
|
||||
// Copyright 2024-2026 The Hush Developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#include "address_book.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
#include "../util/logger.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <shlobj.h>
|
||||
#else
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace dragonx {
|
||||
namespace data {
|
||||
|
||||
AddressBook::AddressBook() = default;
|
||||
AddressBook::~AddressBook() = default;
|
||||
|
||||
std::string AddressBook::getDefaultPath()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
char path[MAX_PATH];
|
||||
if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, 0, path))) {
|
||||
std::string dir = std::string(path) + "\\ObsidianDragon";
|
||||
fs::create_directories(dir);
|
||||
return dir + "\\addressbook.json";
|
||||
}
|
||||
return "addressbook.json";
|
||||
#elif defined(__APPLE__)
|
||||
const char* home = getenv("HOME");
|
||||
if (!home) {
|
||||
struct passwd* pw = getpwuid(getuid());
|
||||
home = pw->pw_dir;
|
||||
}
|
||||
std::string dir = std::string(home) + "/Library/Application Support/ObsidianDragon";
|
||||
fs::create_directories(dir);
|
||||
return dir + "/addressbook.json";
|
||||
#else
|
||||
const char* home = getenv("HOME");
|
||||
if (!home) {
|
||||
struct passwd* pw = getpwuid(getuid());
|
||||
home = pw->pw_dir;
|
||||
}
|
||||
std::string dir = std::string(home) + "/.config/ObsidianDragon";
|
||||
fs::create_directories(dir);
|
||||
return dir + "/addressbook.json";
|
||||
#endif
|
||||
}
|
||||
|
||||
bool AddressBook::load()
|
||||
{
|
||||
file_path_ = getDefaultPath();
|
||||
|
||||
std::ifstream file(file_path_);
|
||||
if (!file.is_open()) {
|
||||
// No file yet - that's OK
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
json j;
|
||||
file >> j;
|
||||
|
||||
entries_.clear();
|
||||
|
||||
if (j.contains("entries") && j["entries"].is_array()) {
|
||||
for (const auto& entry : j["entries"]) {
|
||||
AddressBookEntry e;
|
||||
e.label = entry.value("label", "");
|
||||
e.address = entry.value("address", "");
|
||||
e.notes = entry.value("notes", "");
|
||||
|
||||
if (!e.address.empty()) {
|
||||
entries_.push_back(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOGF("Address book loaded: %zu entries\n", entries_.size());
|
||||
return true;
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG_LOGF("Error loading address book: %s\n", e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AddressBook::save()
|
||||
{
|
||||
if (file_path_.empty()) {
|
||||
file_path_ = getDefaultPath();
|
||||
}
|
||||
|
||||
try {
|
||||
json j;
|
||||
j["entries"] = json::array();
|
||||
|
||||
for (const auto& entry : entries_) {
|
||||
json e;
|
||||
e["label"] = entry.label;
|
||||
e["address"] = entry.address;
|
||||
e["notes"] = entry.notes;
|
||||
j["entries"].push_back(e);
|
||||
}
|
||||
|
||||
// Ensure directory exists
|
||||
fs::path p(file_path_);
|
||||
fs::create_directories(p.parent_path());
|
||||
|
||||
std::ofstream file(file_path_);
|
||||
if (!file.is_open()) {
|
||||
DEBUG_LOGF("Could not open address book for writing: %s\n", file_path_.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
file << j.dump(2);
|
||||
DEBUG_LOGF("Address book saved: %zu entries\n", entries_.size());
|
||||
return true;
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG_LOGF("Error saving address book: %s\n", e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool AddressBook::addEntry(const AddressBookEntry& entry)
|
||||
{
|
||||
// Check for duplicate address
|
||||
if (findByAddress(entry.address) >= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
entries_.push_back(entry);
|
||||
return save();
|
||||
}
|
||||
|
||||
bool AddressBook::updateEntry(size_t index, const AddressBookEntry& entry)
|
||||
{
|
||||
if (index >= entries_.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for duplicate address (excluding current entry)
|
||||
int existing = findByAddress(entry.address);
|
||||
if (existing >= 0 && static_cast<size_t>(existing) != index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
entries_[index] = entry;
|
||||
return save();
|
||||
}
|
||||
|
||||
bool AddressBook::removeEntry(size_t index)
|
||||
{
|
||||
if (index >= entries_.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
entries_.erase(entries_.begin() + index);
|
||||
return save();
|
||||
}
|
||||
|
||||
int AddressBook::findByAddress(const std::string& address) const
|
||||
{
|
||||
for (size_t i = 0; i < entries_.size(); i++) {
|
||||
if (entries_[i].address == address) {
|
||||
return static_cast<int>(i);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace data
|
||||
} // namespace dragonx
|
||||
Reference in New Issue
Block a user