diff --git a/.gitignore b/.gitignore index fba6e92a1..97898a884 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ node_modules # Local SSL certificates /certs/ + +# CDK mint data directory +/.cdk-mint/ diff --git a/README.md b/README.md index 4b25638cf..21b9edc2e 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,39 @@ or run the certificate script directly by executing `generate-ssl-cert`. `master` is the main branch. When working on a feature, branch of `master` and when ready make a PR back to `master`. Try to make feature branches short-lived and concise (avoid implementing multiple features in one PR). +### Running a local CDK mint + +Start the mint in background using devenv: + +```bash +devenv processes up -d +``` + +Or you can simply run `cdk-mintd` from your devenv shell. + +Either of these methods will create a new directory called `.cdk-mintd` in the root of this project and clone the repository specified by the `CDK_REPO` env variable in [devenv.nix](devenv.nix). After the specified repository is cloned, the script will build and run cdk-mintd on http://localhost:8085. You can configure cdk by modifying the [cdk-mint.config.toml](tools/devenv/cdk/cdk-mint.config.toml) + +Once the mint is running and you are in your devenv shell, you can tail the mint's logs with `cdk-logs`. + +#### Keycloak + +Keycloak is the auth provider that we use when auth is enabled in the mint's config. If auth is enabled, then the `cdk-mintd` script will also use docker compose to start keycloak on http://localhost:8080. Keycloak will be initialized with the data found [here](https://github.com/cashubtc/cdk/tree/main/misc/keycloak/keycloak-export), and then any changes made in the keycloak UI will be persisted in the docker volume. + +###### Admin login + +To log in to the admin interface the username is `admin` and password is `admin` + +###### Creating a new user + +Once you are logged into the Keycloak UI, make sure you are in the "cdk-test-realm", then navigate to "Users" and "Add user". Once you create a user go to "Credentials" and set a password. Now you can authenticate with the mint using these credentials. + +###### Access settings + +You will need to specify the URL of your wallet in "Clients" -> "cashu-client" -> "Access settings". Set the "Valid redirect URIs" to the OIDC callback endpoint of the wallet and "Web origins" to the base URL of your wallet. For example, if your wallet runs on localhost:3000 you would set something like: +- "Valid redirect URIs": http://localhost:3000/oidc-callback +- "Web origins": http://localhost:3000 + + ### Updating development environment To update devenv packages run `devenv update`. When updating `bun`, make sure to update the `engines` version in diff --git a/devenv.nix b/devenv.nix index 2d053c229..8cd3a129f 100644 --- a/devenv.nix +++ b/devenv.nix @@ -1,8 +1,9 @@ { pkgs, lib, config, inputs, ... }: -{ - # https://devenv.sh/basics/ - env.GREET = "devenv"; +{ + # CDK repository configuration + env.CDK_REPO = "https://github.com/cashubtc/cdk.git"; + env.CDK_REF = "aa624d3afd739a82aa31dfde2632480934004fc2"; # Can be branch, tag, or commit hash # https://devenv.sh/packages/ packages = [ @@ -16,26 +17,35 @@ ]; # https://devenv.sh/languages/ - # languages.rust.enable = true; + languages.rust.enable = true; # https://devenv.sh/processes/ - # processes.cargo-watch.exec = "cargo-watch"; + processes.cdk-mint.exec = '' + cdk-mint + ''; # https://devenv.sh/services/ # services.postgres.enable = true; # https://devenv.sh/scripts/ - scripts.hello.exec = '' - echo Hello from $GREET - ''; scripts.webstorm.exec = "$DEVENV_ROOT/tools/devenv/webstorm.sh $@"; scripts.generate-ssl-cert.exec = "$DEVENV_ROOT/tools/devenv/generate-ssl-cert.sh"; + scripts.cdk-mint.exec = "$DEVENV_ROOT/tools/devenv/cdk/cdk-mint.sh"; + scripts.cdk-logs.exec = "$DEVENV_ROOT/tools/devenv/cdk/cdk-logs.sh $@"; enterShell = '' - hello git --version echo Bun version: $(bun --version) generate-ssl-cert + + echo "" + echo "Local CDK Mint:" + echo "๐Ÿ”ง $CDK_REPO (ref: $CDK_REF)" + echo "๐Ÿ“ Mint logs: 'cdk-logs'" + echo "๐Ÿš€ Start CDK mint: 'devenv processes up' (or 'devenv processes up -d' for background)" + echo " This will start cdk-mintd and Keycloak if auth is enabled in config" + echo "Configure cdk by changing $DEVENV_ROOT/tools/devenv/cdk/cdk-mint.config.toml" + echo "" ''; # https://devenv.sh/tasks/ @@ -51,19 +61,19 @@ ''; # https://devenv.sh/pre-commit-hooks/ - pre-commit.hooks.generate-db-types = { + git-hooks.hooks.generate-db-types = { enable = true; name = "Generate database types from local db"; entry = "bun run db:generate-types"; }; - pre-commit.hooks.typecheck = { + git-hooks.hooks.typecheck = { enable = true; entry = "bun run typecheck"; pass_filenames = false; }; - pre-commit.hooks.biome = { + git-hooks.hooks.biome = { enable = true; entry = "bun run fix:staged"; }; diff --git a/tools/devenv/cdk/cdk-logs.sh b/tools/devenv/cdk/cdk-logs.sh new file mode 100755 index 000000000..ddb894321 --- /dev/null +++ b/tools/devenv/cdk/cdk-logs.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Default number of lines to show +DEFAULT_LINES=50 + +# Parse command line arguments +LINES=${1:-$DEFAULT_LINES} + +# Validate that LINES is a number +if ! [[ "$LINES" =~ ^[0-9]+$ ]]; then + echo "โŒ Invalid number of lines: $LINES" + echo "Usage: cdk-logs [number_of_lines]" + echo "Example: cdk-logs 100" + echo "Default: $DEFAULT_LINES lines" + exit 1 +fi + +LOGS_DIR="$DEVENV_ROOT/.cdk-mint/logs" + +# Check if logs directory exists +if [ ! -d "$LOGS_DIR" ]; then + echo "โŒ No logs directory found. Start the mint first with 'cdk-mint'" + exit 1 +fi + +# Find the latest log file (format: cdk-mintd.log.YYYY-MM-DD) +LATEST_LOG=$(ls -t "$LOGS_DIR"/cdk-mintd.log.* 2>/dev/null | head -n 1) + +if [ -n "$LATEST_LOG" ] && [ -f "$LATEST_LOG" ]; then + echo "๐Ÿ“– Showing latest CDK mint logs from $(basename "$LATEST_LOG") (last $LINES lines):" + echo "๐Ÿ“ $LATEST_LOG" + echo "" + + tail -n "$LINES" -f "$LATEST_LOG" +else + echo "โŒ No CDK mint log files found in $LOGS_DIR" + echo "๐Ÿ“ Available files:" + ls -la "$LOGS_DIR/" 2>/dev/null || echo " (directory is empty)" +fi diff --git a/tools/devenv/cdk/cdk-mint.config.toml b/tools/devenv/cdk/cdk-mint.config.toml new file mode 100644 index 000000000..b8ac353fb --- /dev/null +++ b/tools/devenv/cdk/cdk-mint.config.toml @@ -0,0 +1,70 @@ +# see https://github.com/cashubtc/cdk/blob/main/crates/cdk-mintd/example.config.toml for more options + +[info] +url = "http://127.0.0.1:8085/" +listen_host = "127.0.0.1" +listen_port = 8085 +mnemonic = "solar decline pole link deposit coconut region race flame truck correct yard" +enable_swagger_ui = true + +[mint_management_rpc] +enabled = false + +[info.http_cache] +backend = "memory" +ttl = 60 +tti = 60 + + +[info.logging] +# Where to output logs: "stdout", "file", or "both" (default: "both") +# Note: "stdout" actually outputs to stderr (standard error stream) +# output = "both" +# Log level for console output (default: "info") +# console_level = "info" +# Log level for file output (default: "debug") +# file_level = "debug" + +[mint_info] +name = "Agicash local mint" +description = "Local development mint for testing!" +description_long = "" +motd = "" + +[database] +engine = "sqlite" + +[ln] +ln_backend = "fakewallet" +min_mint = 1 +max_mint = 500000 +min_melt = 1 +max_melt = 500000 + +[fake_wallet] +supported_units = ["sat"] +fee_percent = 0.02 +reserve_fee_min = 1 +min_delay_time = 1 +max_delay_time = 3 + +[auth] +auth_enabled = false +openid_discovery = "http://127.0.0.1:8080/realms/cdk-test-realm/.well-known/openid-configuration" +openid_client_id = "cashu-client" +mint_max_bat=50 + +# Authentication settings for endpoints +# Options: "clear", "blind", "none" (none = disabled) +mint = "blind" +get_mint_quote = "none" +check_mint_quote = "none" + +melt = "none" +get_melt_quote = "none" +check_melt_quote = "none" + +swap = "blind" +restore = "blind" +check_proof_state = "none" + diff --git a/tools/devenv/cdk/cdk-mint.sh b/tools/devenv/cdk/cdk-mint.sh new file mode 100755 index 000000000..76798eccf --- /dev/null +++ b/tools/devenv/cdk/cdk-mint.sh @@ -0,0 +1,158 @@ +#!/bin/bash + +echo "๐Ÿช™ Starting CDK Mint..." + +# Fallback to main if not set +CDK_REF="${CDK_REF:-main}" +echo "๐Ÿ“ Using CDK reference: $CDK_REF" + +ensure_docker_compose() { + command -v docker &> /dev/null || { + echo "โŒ Docker not found. Install Docker to use Keycloak authentication" + return 1 + } + docker compose version &> /dev/null || { + echo "โŒ Docker Compose not available" + return 1 + } +} + +# Function to check if auth is enabled in config +check_auth_enabled() { + local config_file="$DEVENV_ROOT/tools/devenv/cdk/cdk-mint.config.toml" + [ -f "$config_file" ] && grep -q "^auth_enabled = true" "$config_file" +} + +start_keycloak() { + local cdk_dir="$1" + local keycloak_compose="$cdk_dir/misc/keycloak/docker-compose-recover.yml" + local keycloak_export="$cdk_dir/misc/keycloak/keycloak-export" + + ensure_docker_compose || return 1 + + [ -f "$keycloak_compose" ] && [ -d "$keycloak_export" ] || { + echo "โŒ Keycloak files not found:" + echo " Expected: $keycloak_compose" + echo " Expected: $keycloak_export" + return 1 + } + + echo "๐Ÿ” Starting Keycloak..." + cd "$cdk_dir/misc/keycloak" + docker compose -f docker-compose-recover.yml up -d || { + echo "โŒ Failed to start Keycloak" + return 1 + } + + sleep 2 + echo "๐Ÿ“‹ Monitoring Keycloak logs..." + docker compose -f docker-compose-recover.yml logs -f & + echo $! > "$DEVENV_ROOT/.cdk-mint/keycloak-logs.pid" + + echo "โœ… Keycloak started at http://127.0.0.1:8080" +} + +cleanup() { + echo "๐Ÿงน Cleaning up..." + + # Kill Keycloak logs if running + if [ -f "$DEVENV_ROOT/.cdk-mint/keycloak-logs.pid" ]; then + local logs_pid=$(cat "$DEVENV_ROOT/.cdk-mint/keycloak-logs.pid") + kill -0 "$logs_pid" 2>/dev/null && kill "$logs_pid" 2>/dev/null + rm -f "$DEVENV_ROOT/.cdk-mint/keycloak-logs.pid" + fi + + # Stop Keycloak if it was started + if [ -f "$DEVENV_ROOT/.cdk-mint/keycloak-started" ]; then + echo "๐Ÿ” Stopping Keycloak..." + cd "$CDK_DIR/misc/keycloak" 2>/dev/null && docker compose -f docker-compose-recover.yml down + rm -f "$DEVENV_ROOT/.cdk-mint/keycloak-started" + fi + + exit 0 +} + +# Set up signal handlers for cleanup +trap cleanup SIGINT SIGTERM + +mkdir -p "$DEVENV_ROOT/.cdk-mint" +CDK_DIR="$DEVENV_ROOT/.cdk-mint/cdk-source" + +# Function to extract GitHub org/user from URL +get_github_remote_name() { + local url="$1" + # Extract org/user from GitHub URL (handles both https and git formats) + echo "$url" | sed -E 's|.*github\.com[:/]([^/]+)/.*|\1|' +} + +# Check if we need to clone or update the repository +if [ ! -d "$CDK_DIR" ]; then + echo "๐Ÿ“ฆ Cloning CDK repository..." + git clone "$CDK_REPO" "$CDK_DIR" + cd "$CDK_DIR" + git checkout "$CDK_REF" +else + cd "$CDK_DIR" + + # Get the remote name based on GitHub org/user + remote_name=$(get_github_remote_name "$CDK_REPO") + current_origin=$(git remote get-url origin 2>/dev/null || echo "") + + if [ "$current_origin" != "$CDK_REPO" ]; then + echo "๐Ÿ”„ Switching from $(get_github_remote_name "$current_origin") to $remote_name" + + # Check if we already have this remote + if git remote get-url "$remote_name" &>/dev/null; then + echo "๐Ÿ“ก Remote '$remote_name' already exists, updating URL..." + git remote set-url "$remote_name" "$CDK_REPO" + else + echo "๐Ÿ“ก Adding new remote '$remote_name'..." + git remote add "$remote_name" "$CDK_REPO" + fi + + # Fetch from the new remote + echo "๐Ÿ“ฅ Fetching from $remote_name..." + git fetch "$remote_name" --tags + + # Set the new remote as origin + git remote set-url origin "$CDK_REPO" + + # Try to checkout the ref from the new remote + echo "๐Ÿ”„ Switching to $CDK_REF from $remote_name..." + git checkout "$CDK_REF" 2>/dev/null || { + # If the ref doesn't exist locally, try to create it from the remote + git checkout -b "$CDK_REF" "$remote_name/$CDK_REF" 2>/dev/null || { + # If it's a tag or commit, just checkout directly + git fetch "$remote_name" "$CDK_REF:$CDK_REF" 2>/dev/null || true + git checkout "$CDK_REF" + } + } + else + echo "๐Ÿ”„ Updating CDK repository from $remote_name..." + git fetch --all --tags + git checkout "$CDK_REF" + if git show-ref --verify --quiet "refs/heads/$CDK_REF" || git show-ref --verify --quiet "refs/remotes/origin/$CDK_REF"; then + git pull origin "$CDK_REF" 2>/dev/null || true + fi + fi +fi + +cd "$CDK_DIR" + +# Check if auth is enabled and start Keycloak if needed +if check_auth_enabled; then start_keycloak "$CDK_DIR" || { + echo "โŒ Failed to start Keycloak. Cannot start CDK mint with auth enabled." + exit 1 + } + touch "$DEVENV_ROOT/.cdk-mint/keycloak-started" + FEATURES="auth,fakewallet" +else + FEATURES="fakewallet" +fi + +echo "๐Ÿš€ Starting CDK mint with features: $FEATURES" + +cargo run --package cdk-mintd --features "$FEATURES" -- \ + --config "$DEVENV_ROOT/tools/devenv/cdk/cdk-mint.config.toml" \ + --work-dir "$DEVENV_ROOT/.cdk-mint" \ + 2>&1