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:
2026-02-26 02:31:52 -06:00
commit 3aee55b49c
306 changed files with 177789 additions and 0 deletions

224
scripts/legacy/build-release.sh Executable file
View File

@@ -0,0 +1,224 @@
#!/bin/bash
# DragonX ImGui Wallet - Release Build Script
# Copyright 2024-2026 The Hush Developers
# Released under the GPLv3
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BUILD_DIR="${SCRIPT_DIR}/build/linux"
VERSION="1.0.0"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
print_status() {
echo -e "${GREEN}[*]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[!]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
usage() {
echo "DragonX ImGui Wallet Build Script"
echo ""
echo "Usage: $0 [options]"
echo ""
echo "Options:"
echo " -d, --debug Build debug version"
echo " -r, --release Build release version (default)"
echo " -c, --clean Clean build directory first"
echo " -j N Use N parallel jobs (default: auto)"
echo " -a, --appimage Create AppImage after build"
echo " -h, --help Show this help"
echo ""
echo "Examples:"
echo " $0 -r # Release build"
echo " $0 -c -r # Clean + release build"
echo " $0 -r -a # Release build + AppImage"
echo " $0 -d -j4 # Debug build with 4 threads"
}
# Default options
BUILD_TYPE="Release"
CLEAN=false
JOBS=$(nproc 2>/dev/null || echo 4)
CREATE_APPIMAGE=false
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-d|--debug)
BUILD_TYPE="Debug"
shift
;;
-r|--release)
BUILD_TYPE="Release"
shift
;;
-c|--clean)
CLEAN=true
shift
;;
-j)
JOBS="$2"
shift 2
;;
-a|--appimage)
CREATE_APPIMAGE=true
shift
;;
-h|--help)
usage
exit 0
;;
*)
print_error "Unknown option: $1"
usage
exit 1
;;
esac
done
print_status "DragonX ImGui Wallet v${VERSION} - Build Script"
print_status "Build type: ${BUILD_TYPE}"
print_status "Parallel jobs: ${JOBS}"
# Clean if requested
if [ "$CLEAN" = true ]; then
print_status "Cleaning build directory..."
rm -rf "${BUILD_DIR}"
fi
# Create build directory
mkdir -p "${BUILD_DIR}"
cd "${BUILD_DIR}"
# Configure
print_status "Running CMake configuration..."
cmake .. \
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
-DCMAKE_CXX_FLAGS_RELEASE="-O3 -DNDEBUG" \
-DDRAGONX_USE_SYSTEM_SDL3=ON
# Build
print_status "Building with ${JOBS} parallel jobs..."
cmake --build . -j "${JOBS}"
# Check if build succeeded
if [ -f "bin/ObsidianDragon" ]; then
print_status "Build successful!"
# Show binary info
BINARY_SIZE=$(du -h bin/ObsidianDragon | cut -f1)
print_status "Binary size: ${BINARY_SIZE}"
# Strip in release mode
if [ "$BUILD_TYPE" = "Release" ]; then
print_status "Stripping debug symbols..."
strip bin/ObsidianDragon
STRIPPED_SIZE=$(du -h bin/ObsidianDragon | cut -f1)
print_status "Stripped size: ${STRIPPED_SIZE}"
fi
# Bundle daemon files if available
DAEMON_BUNDLED=0
# Look for hush-arrakis-chain in common locations (the daemon launcher script)
LAUNCHER_PATHS=(
"${SCRIPT_DIR}/prebuilt-binaries/dragonxd-linux/hush-arrakis-chain"
"${SCRIPT_DIR}/../hush-arrakis-chain"
"${SCRIPT_DIR}/hush-arrakis-chain"
"$HOME/hush3/src/hush-arrakis-chain"
)
for lpath in "${LAUNCHER_PATHS[@]}"; do
if [ -f "$lpath" ]; then
print_status "Bundling hush-arrakis-chain from $lpath"
cp "$lpath" bin/hush-arrakis-chain
chmod +x bin/hush-arrakis-chain
DAEMON_BUNDLED=1
break
fi
done
# Also look for hushd (the actual daemon binary)
HUSHD_PATHS=(
"${SCRIPT_DIR}/prebuilt-binaries/dragonxd-linux/hushd"
"${SCRIPT_DIR}/../hushd"
"${SCRIPT_DIR}/hushd"
"$HOME/hush3/src/hushd"
)
for hpath in "${HUSHD_PATHS[@]}"; do
if [ -f "$hpath" ]; then
print_status "Bundling hushd from $hpath"
cp "$hpath" bin/hushd
chmod +x bin/hushd
break
fi
done
# Also copy dragonxd script if available (alternative launcher)
DRAGONXD_PATHS=(
"${SCRIPT_DIR}/prebuilt-binaries/dragonxd-linux/dragonxd"
"${SCRIPT_DIR}/../dragonxd"
"${SCRIPT_DIR}/dragonxd"
"$HOME/hush3/src/dragonxd"
)
for dpath in "${DRAGONXD_PATHS[@]}"; do
if [ -f "$dpath" ]; then
print_status "Bundling dragonxd script from $dpath"
cp "$dpath" bin/dragonxd
chmod +x bin/dragonxd
break
fi
done
# Look for asmap.dat
ASMAP_PATHS=(
"${SCRIPT_DIR}/prebuilt-binaries/dragonxd-linux/asmap.dat"
"${SCRIPT_DIR}/../asmap.dat"
"${SCRIPT_DIR}/asmap.dat"
"$HOME/hush3/asmap.dat"
"$HOME/hush3/contrib/asmap/asmap.dat"
)
for apath in "${ASMAP_PATHS[@]}"; do
if [ -f "$apath" ]; then
print_status "Bundling asmap.dat from $apath"
cp "$apath" bin/
break
fi
done
if [ $DAEMON_BUNDLED -eq 1 ]; then
print_status "Daemon bundled - ready for distribution!"
else
print_warning "dragonxd not found - place prebuilt-binaries/dragonxd-linux/ in project directory for bundling"
fi
else
print_error "Build failed - binary not found"
exit 1
fi
# Create AppImage if requested
if [ "$CREATE_APPIMAGE" = true ]; then
print_status "Creating AppImage..."
"${SCRIPT_DIR}/create-appimage.sh" || print_warning "AppImage creation failed"
fi
print_status ""
print_status "Build complete!"
print_status "Binary: ${BUILD_DIR}/bin/ObsidianDragon"
print_status ""
print_status "To run: cd ${BUILD_DIR}/bin && ./ObsidianDragon"

View File

@@ -0,0 +1,60 @@
@echo off
REM DragonX Wallet - Windows Build Script (Native MSVC/MinGW)
REM Run from Visual Studio Developer Command Prompt or MSYS2 MinGW64
setlocal enabledelayedexpansion
echo DragonX Wallet - Windows Build
echo ==============================
REM Check for CMake
where cmake >nul 2>nul
if %errorlevel% neq 0 (
echo Error: CMake not found! Please install CMake and add to PATH.
exit /b 1
)
REM Create build directory
if not exist build-win mkdir build-win
cd build-win
REM Detect compiler
where cl >nul 2>nul
if %errorlevel% equ 0 (
echo Using MSVC compiler
set GENERATOR=-G "Visual Studio 17 2022" -A x64
) else (
where gcc >nul 2>nul
if %errorlevel% equ 0 (
echo Using MinGW/GCC compiler
set GENERATOR=-G "MinGW Makefiles"
) else (
echo Error: No compiler found! Run from VS Developer Command Prompt or MSYS2.
exit /b 1
)
)
echo.
echo Configuring with CMake...
cmake .. %GENERATOR% -DCMAKE_BUILD_TYPE=Release -DDRAGONX_USE_SYSTEM_SDL3=OFF
if %errorlevel% neq 0 (
echo CMake configuration failed!
exit /b 1
)
echo.
echo Building...
cmake --build . --config Release --parallel
if %errorlevel% neq 0 (
echo Build failed!
exit /b 1
)
echo.
echo Build successful!
echo Output: build-win\bin\Release\ObsidianDragon.exe (MSVC)
echo or: build-win\bin\ObsidianDragon.exe (MinGW)
endlocal

477
scripts/legacy/build-windows.sh Executable file
View File

@@ -0,0 +1,477 @@
#!/bin/bash
# DragonX Wallet - Windows Cross-Compile Build Script
# Requires: mingw-w64 toolchain with POSIX threads
#
# On Ubuntu/Debian:
# sudo apt install mingw-w64 cmake
# sudo update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix
# sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix
#
# On Arch Linux:
# sudo pacman -S mingw-w64-gcc cmake
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
BUILD_DIR="$SCRIPT_DIR/build/windows"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo -e "${GREEN}DragonX Wallet - Windows Cross-Compile Build${NC}"
echo "=============================================="
# Check for mingw toolchain (prefer POSIX variant)
MINGW_GCC=""
MINGW_GXX=""
if command -v x86_64-w64-mingw32-gcc-posix &> /dev/null; then
MINGW_GCC="x86_64-w64-mingw32-gcc-posix"
MINGW_GXX="x86_64-w64-mingw32-g++-posix"
echo -e "${GREEN}Using POSIX thread model (recommended)${NC}"
elif command -v x86_64-w64-mingw32-gcc &> /dev/null; then
# Check if it's the posix variant
if x86_64-w64-mingw32-gcc -v 2>&1 | grep -q "posix"; then
MINGW_GCC="x86_64-w64-mingw32-gcc"
MINGW_GXX="x86_64-w64-mingw32-g++"
echo -e "${GREEN}Using POSIX thread model${NC}"
else
echo -e "${YELLOW}Warning: Using win32 thread model - may have threading issues${NC}"
echo "Run these commands to switch to POSIX threads:"
echo " sudo update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix"
echo " sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix"
MINGW_GCC="x86_64-w64-mingw32-gcc"
MINGW_GXX="x86_64-w64-mingw32-g++"
fi
else
echo -e "${RED}Error: mingw-w64 not found!${NC}"
echo "Install with:"
echo " Ubuntu/Debian: sudo apt install mingw-w64"
echo " Arch Linux: sudo pacman -S mingw-w64-gcc"
exit 1
fi
echo "C compiler: $MINGW_GCC"
echo "C++ compiler: $MINGW_GXX"
# Clean and create build directory
if [ "$1" == "clean" ]; then
echo -e "${YELLOW}Cleaning build directory...${NC}"
rm -rf "$BUILD_DIR"
fi
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
# Create CMake toolchain file for MinGW
cat > mingw-toolchain.cmake << EOF
# MinGW-w64 Cross-Compilation Toolchain
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
# Compilers (using POSIX threads)
set(CMAKE_C_COMPILER $MINGW_GCC)
set(CMAKE_CXX_COMPILER $MINGW_GXX)
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
# Target environment
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
# Search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# Search for libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# Static linking - no DLLs needed
set(CMAKE_EXE_LINKER_FLAGS "-static -static-libgcc -static-libstdc++ -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive")
set(CMAKE_CXX_FLAGS "\${CMAKE_CXX_FLAGS} -static")
set(CMAKE_C_FLAGS "\${CMAKE_C_FLAGS} -static")
# Prefer static libraries
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
set(BUILD_SHARED_LIBS OFF)
EOF
# -----------------------------------------------------------------------------
# Generate embedded resources (Sapling params, asmap.dat)
# -----------------------------------------------------------------------------
echo -e "${GREEN}Generating embedded resources...${NC}"
GENERATED_DIR="$BUILD_DIR/generated"
mkdir -p "$GENERATED_DIR"
# Find resource files
SAPLING_SPEND=""
SAPLING_OUTPUT=""
ASMAP_DAT=""
# Look for Sapling params
PARAMS_PATHS=(
"$HOME/.zcash-params"
"$HOME/.hush-params"
"$SCRIPT_DIR/../SilentDragonX"
"$SCRIPT_DIR/prebuilt-binaries/dragonxd-win"
"$SCRIPT_DIR"
)
for ppath in "${PARAMS_PATHS[@]}"; do
if [ -f "$ppath/sapling-spend.params" ] && [ -f "$ppath/sapling-output.params" ]; then
SAPLING_SPEND="$ppath/sapling-spend.params"
SAPLING_OUTPUT="$ppath/sapling-output.params"
echo " Found Sapling params in $ppath"
break
fi
done
# Look for asmap.dat
ASMAP_PATHS=(
"$HOME/hush3/asmap.dat"
"$HOME/hush3/contrib/asmap/asmap.dat"
"$SCRIPT_DIR/../asmap.dat"
"$SCRIPT_DIR/asmap.dat"
"$SCRIPT_DIR/../SilentDragonX/asmap.dat"
)
for apath in "${ASMAP_PATHS[@]}"; do
if [ -f "$apath" ]; then
ASMAP_DAT="$apath"
echo " Found asmap.dat at $apath"
break
fi
done
# ---------------------------------------------------------------------------
# Generate embedded_data.h using INCBIN (assembler .incbin directive).
#
# Instead of converting binaries to giant hex arrays (530MB+ C source),
# we copy the raw files into generated/res/ and generate a small header
# that uses INCBIN() macros. The assembler streams the bytes directly
# into the object file, using near-zero compile-time RAM.
# ---------------------------------------------------------------------------
if [ -n "$SAPLING_SPEND" ] && [ -n "$SAPLING_OUTPUT" ]; then
echo -e "${GREEN}Embedding resources via INCBIN (assembler .incbin)...${NC}"
# Stage raw binaries into generated/res/ so .incbin can find them
EMBED_RES_DIR="$GENERATED_DIR/res"
mkdir -p "$EMBED_RES_DIR"
cp -f "$SAPLING_SPEND" "$EMBED_RES_DIR/sapling-spend.params"
echo " Staged sapling-spend.params ($(du -h "$SAPLING_SPEND" | cut -f1))"
cp -f "$SAPLING_OUTPUT" "$EMBED_RES_DIR/sapling-output.params"
echo " Staged sapling-output.params ($(du -h "$SAPLING_OUTPUT" | cut -f1))"
if [ -n "$ASMAP_DAT" ]; then
cp -f "$ASMAP_DAT" "$EMBED_RES_DIR/asmap.dat"
echo " Staged asmap.dat ($(du -h "$ASMAP_DAT" | cut -f1))"
HAS_ASMAP=1
else
HAS_ASMAP=0
fi
# Start writing the header — use absolute paths for .incbin
cat > "$GENERATED_DIR/embedded_data.h" << HEADER_START
// Auto-generated embedded resource data — INCBIN edition
// DO NOT EDIT — generated by build-windows.sh
//
// Uses assembler .incbin directive via incbin.h so the compiler never
// has to parse hundreds of millions of hex literals. Compile-time RAM
// drops from 12 GB+ to well under 1 GB.
#pragma once
#include <cstdint>
#include <cstddef>
#include "incbin.h"
// ---- Sapling params (always present when this header exists) ----
INCBIN(sapling_spend_params, "$EMBED_RES_DIR/sapling-spend.params");
INCBIN(sapling_output_params, "$EMBED_RES_DIR/sapling-output.params");
HEADER_START
# asmap.dat
if [ "$HAS_ASMAP" = "1" ]; then
echo "INCBIN(asmap_dat, \"$EMBED_RES_DIR/asmap.dat\");" >> "$GENERATED_DIR/embedded_data.h"
else
echo 'extern "C" { static const uint8_t* g_asmap_dat_data = nullptr; }' >> "$GENERATED_DIR/embedded_data.h"
echo 'static const unsigned int g_asmap_dat_size = 0;' >> "$GENERATED_DIR/embedded_data.h"
fi
echo "" >> "$GENERATED_DIR/embedded_data.h"
# Daemon binaries
DAEMON_DIR="$SCRIPT_DIR/prebuilt-binaries/dragonxd-win"
if [ -d "$DAEMON_DIR" ] && [ -f "$DAEMON_DIR/hushd.exe" ]; then
echo -e "${GREEN}Embedding daemon binaries via INCBIN...${NC}"
echo "" >> "$GENERATED_DIR/embedded_data.h"
echo "#define HAS_EMBEDDED_DAEMON 1" >> "$GENERATED_DIR/embedded_data.h"
echo "" >> "$GENERATED_DIR/embedded_data.h"
cp -f "$DAEMON_DIR/hushd.exe" "$EMBED_RES_DIR/hushd.exe"
echo " Staged hushd.exe ($(du -h "$DAEMON_DIR/hushd.exe" | cut -f1))"
echo "INCBIN(hushd_exe, \"$EMBED_RES_DIR/hushd.exe\");" >> "$GENERATED_DIR/embedded_data.h"
if [ -f "$DAEMON_DIR/hush-cli.exe" ]; then
cp -f "$DAEMON_DIR/hush-cli.exe" "$EMBED_RES_DIR/hush-cli.exe"
echo " Staged hush-cli.exe ($(du -h "$DAEMON_DIR/hush-cli.exe" | cut -f1))"
echo "INCBIN(hush_cli_exe, \"$EMBED_RES_DIR/hush-cli.exe\");" >> "$GENERATED_DIR/embedded_data.h"
else
echo 'extern "C" { static const uint8_t* g_hush_cli_exe_data = nullptr; }' >> "$GENERATED_DIR/embedded_data.h"
echo 'static const unsigned int g_hush_cli_exe_size = 0;' >> "$GENERATED_DIR/embedded_data.h"
fi
echo "" >> "$GENERATED_DIR/embedded_data.h"
if [ -f "$DAEMON_DIR/dragonxd.bat" ]; then
cp -f "$DAEMON_DIR/dragonxd.bat" "$EMBED_RES_DIR/dragonxd.bat"
echo " Staged dragonxd.bat"
echo "INCBIN(dragonxd_bat, \"$EMBED_RES_DIR/dragonxd.bat\");" >> "$GENERATED_DIR/embedded_data.h"
else
echo 'extern "C" { static const uint8_t* g_dragonxd_bat_data = nullptr; }' >> "$GENERATED_DIR/embedded_data.h"
echo 'static const unsigned int g_dragonxd_bat_size = 0;' >> "$GENERATED_DIR/embedded_data.h"
fi
echo "" >> "$GENERATED_DIR/embedded_data.h"
if [ -f "$DAEMON_DIR/hush-tx.exe" ]; then
cp -f "$DAEMON_DIR/hush-tx.exe" "$EMBED_RES_DIR/hush-tx.exe"
echo " Staged hush-tx.exe ($(du -h "$DAEMON_DIR/hush-tx.exe" | cut -f1))"
echo "INCBIN(hush_tx_exe, \"$EMBED_RES_DIR/hush-tx.exe\");" >> "$GENERATED_DIR/embedded_data.h"
else
echo 'extern "C" { static const uint8_t* g_hush_tx_exe_data = nullptr; }' >> "$GENERATED_DIR/embedded_data.h"
echo 'static const unsigned int g_hush_tx_exe_size = 0;' >> "$GENERATED_DIR/embedded_data.h"
fi
echo "" >> "$GENERATED_DIR/embedded_data.h"
if [ -f "$DAEMON_DIR/dragonx-cli.bat" ]; then
cp -f "$DAEMON_DIR/dragonx-cli.bat" "$EMBED_RES_DIR/dragonx-cli.bat"
echo " Staged dragonx-cli.bat"
echo "INCBIN(dragonx_cli_bat, \"$EMBED_RES_DIR/dragonx-cli.bat\");" >> "$GENERATED_DIR/embedded_data.h"
else
echo 'extern "C" { static const uint8_t* g_dragonx_cli_bat_data = nullptr; }' >> "$GENERATED_DIR/embedded_data.h"
echo 'static const unsigned int g_dragonx_cli_bat_size = 0;' >> "$GENERATED_DIR/embedded_data.h"
fi
else
echo -e "${YELLOW}Note: Daemon binaries not found in prebuilt-binaries/dragonxd-win/ — wallet only${NC}"
fi
# ── xmrig binary (from prebuilt-binaries/xmrig-hac/) ────────────────
XMRIG_DIR="$SCRIPT_DIR/prebuilt-binaries/xmrig-hac"
if [ -f "$XMRIG_DIR/xmrig.exe" ]; then
cp -f "$XMRIG_DIR/xmrig.exe" "$EMBED_RES_DIR/xmrig.exe"
echo " Staged xmrig.exe ($(du -h "$XMRIG_DIR/xmrig.exe" | cut -f1))"
echo "" >> "$GENERATED_DIR/embedded_data.h"
echo "#define HAS_EMBEDDED_XMRIG 1" >> "$GENERATED_DIR/embedded_data.h"
echo "INCBIN(xmrig_exe, \"$EMBED_RES_DIR/xmrig.exe\");" >> "$GENERATED_DIR/embedded_data.h"
else
echo 'extern "C" { static const uint8_t* g_xmrig_exe_data = nullptr; }' >> "$GENERATED_DIR/embedded_data.h"
echo 'static const unsigned int g_xmrig_exe_size = 0;' >> "$GENERATED_DIR/embedded_data.h"
fi
# ---- Theme images (backgrounds + logos) ----
# Embed ALL images from res/img/backgrounds/ subdirectories and res/img/logos/
# so the Windows single-file distribution can display theme backgrounds and logos
# without needing res/ on disk.
echo "" >> "$GENERATED_DIR/embedded_data.h"
echo "// ---- Embedded theme images ----" >> "$GENERATED_DIR/embedded_data.h"
IMAGE_TABLE_ENTRIES=""
IMAGE_COUNT=0
for IMG_DIR in "$SCRIPT_DIR/res/img/backgrounds/texture" "$SCRIPT_DIR/res/img/backgrounds/gradient" "$SCRIPT_DIR/res/img/logos"; do
if [ -d "$IMG_DIR" ]; then
for IMG_FILE in "$IMG_DIR"/*.png; do
[ -f "$IMG_FILE" ] || continue
IMG_BASENAME=$(basename "$IMG_FILE")
IMG_SYMBOL=$(echo "$IMG_BASENAME" | sed 's/[^a-zA-Z0-9]/_/g')
echo " Staged image: $IMG_BASENAME ($(du -h "$IMG_FILE" | cut -f1))"
cp -f "$IMG_FILE" "$EMBED_RES_DIR/$IMG_BASENAME"
echo "INCBIN(img_${IMG_SYMBOL}, \"$EMBED_RES_DIR/$IMG_BASENAME\");" >> "$GENERATED_DIR/embedded_data.h"
IMAGE_TABLE_ENTRIES="${IMAGE_TABLE_ENTRIES} { g_img_${IMG_SYMBOL}_data, g_img_${IMG_SYMBOL}_size, \"${IMG_BASENAME}\" },\n"
IMAGE_COUNT=$((IMAGE_COUNT + 1))
done
fi
done
echo "" >> "$GENERATED_DIR/embedded_data.h"
echo "#define HAS_EMBEDDED_IMAGES 1" >> "$GENERATED_DIR/embedded_data.h"
echo "#define EMBEDDED_IMAGE_COUNT $IMAGE_COUNT" >> "$GENERATED_DIR/embedded_data.h"
# Backward compat defines (referenced by s_resources[] guards)
echo "#define HAS_EMBEDDED_GRADIENT 1" >> "$GENERATED_DIR/embedded_data.h"
echo "#define HAS_EMBEDDED_LOGO 1" >> "$GENERATED_DIR/embedded_data.h"
# Backward compat aliases for the old symbol names
echo "static const uint8_t* g_dark_gradient_png_data = g_img_dark_gradient_png_data;" >> "$GENERATED_DIR/embedded_data.h"
echo "static const unsigned int g_dark_gradient_png_size = g_img_dark_gradient_png_size;" >> "$GENERATED_DIR/embedded_data.h"
echo "static const uint8_t* g_logo_ObsidianDragon_dark_png_data = g_img_logo_ObsidianDragon_dark_png_data;" >> "$GENERATED_DIR/embedded_data.h"
echo "static const unsigned int g_logo_ObsidianDragon_dark_png_size = g_img_logo_ObsidianDragon_dark_png_size;" >> "$GENERATED_DIR/embedded_data.h"
echo "" >> "$GENERATED_DIR/embedded_data.h"
echo "struct EmbeddedImageEntry { const uint8_t* data; unsigned int size; const char* filename; };" >> "$GENERATED_DIR/embedded_data.h"
echo "static const EmbeddedImageEntry s_embedded_images[] = {" >> "$GENERATED_DIR/embedded_data.h"
echo -e "$IMAGE_TABLE_ENTRIES" >> "$GENERATED_DIR/embedded_data.h"
echo " { nullptr, 0, nullptr }" >> "$GENERATED_DIR/embedded_data.h"
echo "};" >> "$GENERATED_DIR/embedded_data.h"
# Embed bundled overlay themes (dark.toml, light.toml, obsidian.toml, etc.)
# These are extracted to the config dir on first run so the theme selector can find them.
THEMES_DIR="$SCRIPT_DIR/res/themes"
THEME_COUNT=0
THEME_TABLE_ENTRIES=""
echo "" >> "$GENERATED_DIR/embedded_data.h"
echo "// ---- Bundled overlay themes ----" >> "$GENERATED_DIR/embedded_data.h"
for THEME_FILE in "$THEMES_DIR"/*.toml; do
THEME_BASENAME=$(basename "$THEME_FILE")
# Skip ui.toml — it's embedded separately via cmake
if [ "$THEME_BASENAME" = "ui.toml" ]; then
continue
fi
THEME_SYMBOL=$(echo "$THEME_BASENAME" | sed 's/[^a-zA-Z0-9]/_/g')
cp -f "$THEME_FILE" "$EMBED_RES_DIR/$THEME_BASENAME"
echo " Staged $THEME_BASENAME"
echo "INCBIN(theme_${THEME_SYMBOL}, \"$EMBED_RES_DIR/$THEME_BASENAME\");" >> "$GENERATED_DIR/embedded_data.h"
THEME_TABLE_ENTRIES="${THEME_TABLE_ENTRIES} { g_theme_${THEME_SYMBOL}_data, g_theme_${THEME_SYMBOL}_size, \"${THEME_BASENAME}\" },\n"
THEME_COUNT=$((THEME_COUNT + 1))
done
echo "" >> "$GENERATED_DIR/embedded_data.h"
echo "#define EMBEDDED_THEME_COUNT $THEME_COUNT" >> "$GENERATED_DIR/embedded_data.h"
echo "" >> "$GENERATED_DIR/embedded_data.h"
# Generate the theme table struct
echo "// Auto-generated theme table" >> "$GENERATED_DIR/embedded_data.h"
echo "struct EmbeddedThemeEntry { const uint8_t* data; unsigned int size; const char* filename; };" >> "$GENERATED_DIR/embedded_data.h"
echo "static const EmbeddedThemeEntry s_embedded_themes[] = {" >> "$GENERATED_DIR/embedded_data.h"
echo -e "$THEME_TABLE_ENTRIES" >> "$GENERATED_DIR/embedded_data.h"
echo " { nullptr, 0, nullptr }" >> "$GENERATED_DIR/embedded_data.h"
echo "};" >> "$GENERATED_DIR/embedded_data.h"
echo "" >> "$GENERATED_DIR/embedded_data.h"
echo -e "${GREEN}Embedded resources header generated (INCBIN — near-zero compile RAM)${NC}"
else
echo -e "${YELLOW}Warning: Sapling params not found — building without embedded resources${NC}"
echo "The wallet will require external param files."
fi
# Ensure libsodium is available for Windows cross-compile
if [ ! -f "$SCRIPT_DIR/libs/libsodium-win/lib/libsodium.a" ]; then
echo -e "${YELLOW}libsodium for Windows not found, fetching...${NC}"
"$SCRIPT_DIR/scripts/fetch-libsodium.sh" --win
fi
echo -e "${GREEN}Configuring with CMake...${NC}"
cmake .. \
-DCMAKE_TOOLCHAIN_FILE=mingw-toolchain.cmake \
-DCMAKE_BUILD_TYPE=Release \
-DDRAGONX_USE_SYSTEM_SDL3=OFF
echo -e "${GREEN}Building...${NC}"
cmake --build . -j$(nproc)
# Check if build succeeded
if [ -f "bin/ObsidianDragon.exe" ]; then
echo ""
echo -e "${GREEN}Build successful!${NC}"
echo "Output: $BUILD_DIR/bin/ObsidianDragon.exe"
# Show file size and check if statically linked
ls -lh bin/ObsidianDragon.exe
echo ""
echo -e "${GREEN}Statically linked - no DLLs required!${NC}"
# Bundle daemon files if available from dragonxd-win directory
DAEMON_DIR="$SCRIPT_DIR/prebuilt-binaries/dragonxd-win"
DAEMON_BUNDLED=0
if [ -d "$DAEMON_DIR" ]; then
echo -e "${GREEN}Found daemon directory: $DAEMON_DIR${NC}"
# Copy all daemon files
if [ -f "$DAEMON_DIR/dragonxd.bat" ]; then
cp "$DAEMON_DIR/dragonxd.bat" bin/
echo " - dragonxd.bat"
DAEMON_BUNDLED=1
fi
if [ -f "$DAEMON_DIR/dragonx-cli.bat" ]; then
cp "$DAEMON_DIR/dragonx-cli.bat" bin/
echo " - dragonx-cli.bat"
fi
if [ -f "$DAEMON_DIR/hushd.exe" ]; then
cp "$DAEMON_DIR/hushd.exe" bin/
echo " - hushd.exe ($(du -h "$DAEMON_DIR/hushd.exe" | cut -f1))"
fi
if [ -f "$DAEMON_DIR/hush-cli.exe" ]; then
cp "$DAEMON_DIR/hush-cli.exe" bin/
echo " - hush-cli.exe"
fi
if [ -f "$DAEMON_DIR/hush-tx.exe" ]; then
cp "$DAEMON_DIR/hush-tx.exe" bin/
echo " - hush-tx.exe"
fi
else
echo -e "${YELLOW}Daemon directory not found: $DAEMON_DIR${NC}"
echo " Place prebuilt-binaries/dragonxd-win/ in the project directory to bundle the daemon."
fi
# Create distribution package
echo ""
echo -e "${GREEN}Creating distribution package...${NC}"
cd bin
DIST_NAME="DragonX-Wallet-Windows-x64"
rm -rf "$DIST_NAME" "$DIST_NAME.zip"
mkdir -p "$DIST_NAME"
cp ObsidianDragon.exe "$DIST_NAME/"
# Copy all daemon files
[ -f dragonxd.bat ] && cp dragonxd.bat "$DIST_NAME/"
[ -f dragonx-cli.bat ] && cp dragonx-cli.bat "$DIST_NAME/"
[ -f hushd.exe ] && cp hushd.exe "$DIST_NAME/"
[ -f hush-cli.exe ] && cp hush-cli.exe "$DIST_NAME/"
[ -f hush-tx.exe ] && cp hush-tx.exe "$DIST_NAME/"
# Create README
cat > "$DIST_NAME/README.txt" << 'READMEEOF'
DragonX Wallet - Windows Edition
================================
SINGLE-FILE DISTRIBUTION
========================
This wallet is a true single-file executable with all resources embedded.
Just run ObsidianDragon.exe - no additional files needed!
On first run, the wallet will automatically extract:
- Sapling parameters to %APPDATA%\ZcashParams\
- asmap.dat to %APPDATA%\Hush\DRAGONX\
The wallet will look for the daemon config at:
%APPDATA%\Hush\DRAGONX\DRAGONX.conf
This will be auto-created on first run if the daemon is present.
For support: https://git.hush.is/hush/ObsidianDragon
READMEEOF
if command -v zip &> /dev/null; then
zip -r "$DIST_NAME.zip" "$DIST_NAME"
# Copy zip + single-file exe to release/windows/
local OUT_DIR="$SCRIPT_DIR/release/windows"
mkdir -p "$OUT_DIR"
cp "$DIST_NAME.zip" "$OUT_DIR/"
cp ObsidianDragon.exe "$OUT_DIR/"
echo -e "${GREEN}Distribution package: $OUT_DIR/$DIST_NAME.zip${NC}"
echo -e "${GREEN}Single-file exe: $OUT_DIR/ObsidianDragon.exe${NC}"
ls -lh "$OUT_DIR/"
else
echo "Install 'zip' to create distribution archive"
fi
cd ..
echo ""
echo -e "${GREEN}============================================${NC}"
echo -e "${GREEN}SINGLE-FILE DISTRIBUTION READY!${NC}"
echo -e "${GREEN}============================================${NC}"
echo ""
echo "The executable contains embedded:"
echo " - Sapling spend params (~48MB)"
echo " - Sapling output params (~3MB)"
echo " - asmap.dat (~1MB)"
echo ""
echo "Just copy ObsidianDragon.exe to Windows and run it!"
echo "Resources will be extracted automatically on first launch."
else
echo -e "${RED}Build failed!${NC}"
exit 1
fi