commit ba8d1f12615d1f2ca5c5d6f93b618f3d3f8c1f32 Author: RMI Admin Date: Sat Jun 27 17:12:49 2026 +0700 Initial commit: WalletPress v1.0.0-beta Self-hosted wallet management platform for WordPress: - WP plugin: vault, generate, token gates, payments, wallet login, 15 admin pages - CLI: 17 commands covering all backend feature groups - Landing pages + PDF documentation - Connects to rmi-backend API (86+ endpoints, 29+ chains) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2e22a9c --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.env +node_modules/ +.DS_Store +*.log diff --git a/about.html b/about.html new file mode 100644 index 0000000..1cab1f2 --- /dev/null +++ b/about.html @@ -0,0 +1,274 @@ + + + + + +About โ€” WalletPress ยท Built by Rug Munch Media + + + + + + + + + + +
+ Home + Features + Docs + About + Buy โ€” $49 +
+ +
+
+
Home / About
+

Built for Developers Who Build on Chain

+

WalletPress is a product of Rug Munch Media LLC โ€” a Wyoming-based crypto infrastructure company. We build tools for the sovereign developer.

+
+
+ +
+
+
+ +

Why WalletPress Exists

+

We got tired of stitching together wallet libraries, debugging chain-specific quirks, and paying per-API-call. So we built the tool we wanted.

+
+
+
+
๐Ÿ”‘
+

Sovereign Infrastructure

+

Your server, your keys, your rules. No cloud dependency, no telemetry, no kill switch. You own the tool โ€” forever.

+
+
+
๐Ÿ’ฐ
+

Fair Pricing

+

$49 one-time. Not per wallet, not per month. We believe developer tools should be bought, not rented. Pay once, use forever.

+
+
+
๐Ÿ”“
+

No DRM

+

Full source code included. No phone-home, no license validation, no activation servers. We trust developers โ€” and we prove it.

+
+
+
+
+ +
+
+
+ +

What you can count on

+
+
+
+
๐Ÿ›๏ธ
+
+

Registered US Company

+

Rug Munch Media LLC is a legally registered Wyoming limited liability company. We operate under US law with full compliance.

+
+
+
+
๐Ÿ“œ
+
+

Full Source Code

+

You receive every line of code. No obfuscation, no binary blobs. Audit it, modify it, extend it โ€” it's yours.

+
+
+
+
๐Ÿ”„
+
+

Lifetime Updates

+

All future WalletPress updates are included. New chains, new features, security patches โ€” you get them all, forever.

+
+
+
+
๐Ÿ›ก๏ธ
+
+

30-Day Refund

+

Not satisfied? Full refund within 30 days, no questions asked. We stand behind our product.

+
+
+
+
๐Ÿ”’
+
+

No Data Collection

+

WalletPress makes zero external network calls. No analytics, no usage tracking, no error reporting. Your data is yours.

+
+
+
+
๐Ÿ“ก
+
+

Offline-First

+

Once deployed, WalletPress runs entirely offline. No internet required after initial setup. Air-gapped deployments supported.

+
+
+
+
+
+ +
+
+
+

Rug Munch Media LLC

+

We're a small, focused team building crypto infrastructure tools from Phnom Penh, Cambodia. We ship fast, price fairly, and don't do corporate bullshit.

+

๐Ÿ“ Phnom Penh, Cambodia  ยท  Registered: Wyoming, USA  ยท  Est. 2025

+
+
+
+ +
+
+

Ready to stop renting your wallet infrastructure?

+

30 chains. Full source code. $49, forever.

+ Buy WalletPress โ€” $49 +
+
+ + + + + + diff --git a/buy.html b/buy.html new file mode 100644 index 0000000..6b071c8 --- /dev/null +++ b/buy.html @@ -0,0 +1,464 @@ + + + + + +Buy WalletPress โ€” Checkout ยท $49 One-Time + + + + + + + + + + +
+ Home + Features + Docs + About + Buy โ€” $49 +
+ +
+
+

Complete Your Purchase

+

One-time payment. Lifetime access. Self-hosted wallet generator.

+
+
+ +
+
+
+

Order Summary

+
+
+
WalletPress Self-Hosted
+
30 chains, CLI + API, encrypted vault
+
+
$49.00
+
+
+
+
Lifetime Updates
+
Free updates for life
+
+
Included
+
+
+
+
Source Code
+
Full Docker Compose project
+
+
Included
+
+
+ Total + $49.00 +
+
+
+ + 30-day money-back guarantee +
+
+
+ +
+

Payment Method

+ +
+ + + +
+ + +
+

Select a chain and send exactly $49.00 USD worth. We'll verify and deliver instantly.

+ +
Loading prices...
+ +
+
+
ฮž
+
Ethereum
+
ETH / USDC
+
+
+
โ‚ฟ
+
Bitcoin
+
BTC
+
+
+
โ—Ž
+
Solana
+
SOL / USDC
+
+
+
โ—†
+
TRON
+
TRX / USDT
+
+
+ +
+
+ Payment QR +
+
Send $49.00 USD in ETH
+
+ 0x1E3A...05C9 + Copy +
+
+ + + + +
+ + +
+

Secure payment via Stripe. Your card details are never stored on our servers.

+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+ +
+ +
+ + +
+

Pay via Gumroad with PayPal, Apple Pay, Google Pay, or crypto.

+
+
๐Ÿ›’
+

You'll be redirected to Gumroad to complete your purchase securely.

+ Continue to Gumroad +
+
+
+
+
+ + + + + + + diff --git a/cli/walletpress b/cli/walletpress new file mode 100755 index 0000000..078b2a1 --- /dev/null +++ b/cli/walletpress @@ -0,0 +1,620 @@ +#!/usr/bin/env bash +# WalletPress CLI โ€” Self-Hosted Wallet Management Platform +# Usage: walletpress [options] +set -euo pipefail + +VERSION="1.0.0-beta" +CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/walletpress" +CONFIG_FILE="$CONFIG_DIR/config.json" +DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/walletpress" +GATES_FILE="$DATA_DIR/gates.json" +LOG_FILE="$DATA_DIR/walletpress.log" + +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m' + +mkdir -p "$CONFIG_DIR" "$DATA_DIR" +touch "$GATES_FILE" "$LOG_FILE" + +log() { echo "[$(date +%H:%M:%S)] $*" >> "$LOG_FILE"; } +info() { echo -e "${BLUE}::${NC} $*"; } +ok() { echo -e "${GREEN}โœ“${NC} $*"; } +warn() { echo -e "${YELLOW}โš ${NC} $*"; } +err() { echo -e "${RED}โœ—${NC} $*" >&2; } +hr() { printf '%*s\n' "${COLUMNS:-80}" '' | tr ' ' 'โ”€'; } +die() { err "$1"; exit 1; } + +# โ”€โ”€โ”€ Config โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +load_config() { + if [[ -f "$CONFIG_FILE" ]]; then + API_URL=$(jq -r '.api_url // ""' "$CONFIG_FILE") + API_KEY=$(jq -r '.api_key // ""' "$CONFIG_FILE") + MERCHANT_WALLET=$(jq -r '.merchant_wallet // ""' "$CONFIG_FILE") + MERCHANT_CHAIN=$(jq -r '.merchant_chain // "solana"' "$CONFIG_FILE") + DEFAULT_CHAIN=$(jq -r '.default_chain // "solana"' "$CONFIG_FILE") + else API_URL=""; API_KEY=""; MERCHANT_WALLET=""; MERCHANT_CHAIN="solana"; DEFAULT_CHAIN="solana" + fi +} + +save_config() { + jq -n --arg api_url "$API_URL" --arg api_key "$API_KEY" --arg merchant_wallet "$MERCHANT_WALLET" --arg merchant_chain "$MERCHANT_CHAIN" --arg default_chain "$DEFAULT_CHAIN" \ + '{api_url: $api_url, api_key: $api_key, merchant_wallet: $merchant_wallet, merchant_chain: $merchant_chain, default_chain: $default_chain}' > "$CONFIG_FILE" + ok "Configuration saved" +} + +# โ”€โ”€โ”€ API โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +CV="/api/v1/chain-vault" +WA="/api/v1/wallet" + +api_call() { + local method="$1" path="$2" body="${3:-}" + if [[ -z "$API_URL" ]]; then die "API not configured. Run 'walletpress setup'"; fi + local url="${API_URL}${path}" headers=() + headers+=(-H "Content-Type: application/json") + [[ -n "$API_KEY" ]] && headers+=(-H "Authorization: Bearer $API_KEY" -H "X-API-Key: $API_KEY") + local cmd=("curl" "-sf") + [[ -n "$body" ]] && cmd+=(-X "$method" -d "$body") || cmd+=(-X "$method") + cmd+=( "${headers[@]}" "$url" ) + "${cmd[@]}" 2>/dev/null || return 1 +} + +api_get() { api_call GET "$1" ""; } +api_post() { api_call POST "$1" "$2"; } +api_del() { api_call DELETE "$1" ""; } + +# โ”€โ”€โ”€ Gates โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +load_gates() { + if [[ -f "$GATES_FILE" ]] && [[ -s "$GATES_FILE" ]]; then GATES=$(cat "$GATES_FILE"); else GATES='[]'; fi +} +save_gates() { echo "$GATES" > "$GATES_FILE"; } + +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +# COMMANDS +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + +cmd_setup() { + hr; echo -e " ${BOLD}WalletPress Setup Wizard${NC}"; hr + echo -e "\n${CYAN}[1/5] API Connection${NC}" + read -rp " Backend API URL [${API_URL:-}]: " input; API_URL="${input:-$API_URL}" + read -rsp " API Key: " input; echo; API_KEY="${input:-$API_KEY}" + if [[ -n "$API_URL" && -n "$API_KEY" ]]; then + info "Testing connection..." + if health=$(api_get "/health" 2>/dev/null); then ok "Connected: $(echo "$health" | jq -r '.status // "ok"')"; else warn "API unreachable"; fi + fi + echo -e "\n${CYAN}[2/5] Merchant Wallet${NC}" + read -rp " Wallet address [${MERCHANT_WALLET:-}]: " input; MERCHANT_WALLET="${input:-$MERCHANT_WALLET}" + read -rp " Chain [${MERCHANT_CHAIN}]: " input; MERCHANT_CHAIN="${input:-$MERCHANT_CHAIN}" + echo -e "\n${CYAN}[3/5] Default Chain${NC}" + read -rp " Default chain [${DEFAULT_CHAIN}]: " input; DEFAULT_CHAIN="${input:-$DEFAULT_CHAIN}" + save_config + echo -e "\n${CYAN}[4/5] Generate First Wallet${NC}" + read -rp " Generate a wallet now? (y/N): " gen + if [[ "$gen" =~ ^[yY] ]]; then cmd_vault generate; fi + echo -e "\n${CYAN}[5/5] Create Token Gate${NC}" + read -rp " Create a token gate? (y/N): " gate + if [[ "$gate" =~ ^[yY] ]]; then + read -rp " Gate name: " title; read -rp " Token address: " token; read -rp " Chain [$DEFAULT_CHAIN]: " chain + chain="${chain:-$DEFAULT_CHAIN}"; read -rp " Min amount [1]: " min; min="${min:-1}" + load_gates; GATES=$(echo "$GATES" | jq --arg t "$title" --arg k "$token" --arg c "$chain" --argjson m "$min" '. += [{title: $t, token: $k, chain: $c, min_amount: $m, created_at: now|strflocaltime("%Y-%m-%dT%H:%M:%S")}]'); save_gates + ok "Gate '$title' created"; fi + hr; ok "Setup complete!" + info "Run 'walletpress --help' to see all commands" +} + +cmd_dashboard() { + load_config; hr + echo -e " ${BOLD}WalletPress${NC} v${VERSION}"; hr + echo -e " URL: ${API_URL:-(not set)}" + echo -e " Merchant: ${MERCHANT_WALLET:0:16}... [${MERCHANT_CHAIN}]" + echo -e " Default: ${DEFAULT_CHAIN}" + if [[ -n "$API_URL" ]]; then + health=$(api_get "/health" 2>/dev/null || echo '{"status":"unreachable"}') + echo -e " API: $(echo "$health" | jq -r '.status')" + stats=$(api_get "${CV}/stats" 2>/dev/null || echo '{}') + echo -e " Vault: $(echo "$stats" | jq -r '.total_wallets // "?"') wallets" + chains=$(api_get "${CV}/chains" 2>/dev/null || echo '[]') + echo -e " Chains: $(echo "$chains" | jq 'length') supported" + fi + load_gates; local gc=$(echo "$GATES" | jq 'length') + echo -e " Gates: $gc" + hr +} + +# โ”€โ”€โ”€ VAULT โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_vault() { + load_config + case "${1:-list}" in + list|ls) + local vault + vault=$(api_get "${CV}/vault" 2>/dev/null || die "Failed to fetch vault") + local count=$(echo "$vault" | jq 'length - 1') + echo -e "${BOLD}Vault (${count} wallets)${NC}" + echo "$vault" | jq -r 'to_entries | .[] | select(.key != "_meta") | " \(.key[0:8]).. \(.value.chain // "?") \(.value.address // .value.public_key // "")[0:24]... \(.value.label // "")"' + ;; + get|view) + local id="${2:-}"; [[ -z "$id" ]] && read -rp "Wallet ID: " id + api_get "${CV}/vault/${id}" | jq '.' || warn "Wallet not found" + ;; + generate|gen) + local chain="${2:-$DEFAULT_CHAIN}" label="${3:-}" + [[ -z "$chain" ]] && read -rp "Chain [$DEFAULT_CHAIN]: " chain; chain="${chain:-$DEFAULT_CHAIN}" + [[ -z "$label" ]] && read -rp "Label: " label + result=$(api_post "${CV}/generate" "{\"chain\":\"$chain\",\"label\":\"$label\"}" || true) + if [[ -n "$result" ]]; then ok "Wallet generated"; echo "$result" | jq '{chain, address, label}'; else die "Generation failed"; fi + ;; + batch) + local chains="${2:-solana,ethereum,base,polygon,bsc}" prefix="${3:-batch}" + info "Generating wallets for: $chains" + result=$(api_post "${CV}/generate/batch" "{\"chains\":\"$chains\",\"label_prefix\":\"$prefix\"}" || true) + if [[ -n "$result" ]]; then ok "Batch complete"; echo "$result" | jq '.'; else die "Batch failed"; fi + ;; + all) + local prefix="${2:-full}" + info "Generating wallet for ALL supported chains..." + result=$(api_post "${CV}/generate/batch" "{\"label_prefix\":\"$prefix\"}" || true) + if [[ -n "$result" ]]; then ok "All chains generated"; echo "$result" | jq 'keys | .[]'; else die "Failed"; fi + ;; + import) + local chain="${2:-}" key="${3:-}" label="${4:-}" + [[ -z "$chain" ]] && read -rp "Chain: " chain + [[ -z "$key" ]] && read -rsp "Private key: " key; echo + [[ -z "$label" ]] && read -rp "Label: " label + result=$(api_post "${CV}/import" "{\"chain\":\"$chain\",\"private_key\":\"$key\",\"label\":\"$label\"}" || true) + if [[ -n "$result" ]]; then ok "Wallet imported"; echo "$result" | jq '.'; else die "Import failed"; fi + ;; + stats) + api_get "${CV}/stats" | jq '.' || warn "Failed to fetch stats" + ;; + tree) + api_get "${CV}/tree" | jq '.' || warn "Failed" + ;; + health-score) + local id="${2:-}"; [[ -z "$id" ]] && read -rp "Wallet ID: " id + api_get "${CV}/health-score/${id}" | jq '.' || warn "Failed" + ;; + rotate) + local id="${2:-}"; [[ -z "$id" ]] && read -rp "Wallet ID: " id + result=$(api_post "${CV}/rotate" "{\"wallet_id\":\"$id\"}" || true) + if [[ -n "$result" ]]; then ok "Wallet rotated"; echo "$result" | jq '{chain, new_address}'; else die "Rotation failed"; fi + ;; + export) + local format="${2:-json}" + result=$(api_post "${CV}/export" "{\"format\":\"$format\"}" || true) + if [[ -n "$result" ]]; then echo "$result" | jq '.'; else die "Export failed"; fi + ;; + filter) + local field="${2:-chain}" value="${3:-solana}" + api_post "${CV}/bulk/filter" "{\"filters\":{\"$field\":\"$value\"}}" | jq '.' || warn "Filter failed" + ;; + delete) + local id="${2:-}"; [[ -z "$id" ]] && read -rp "Wallet ID: " id + result=$(api_post "${CV}/bulk/delete" "{\"ids\":[\"$id\"]}" || true) + if [[ -n "$result" ]]; then ok "Wallet deleted"; else die "Delete failed"; fi + ;; + paper) + local id="${2:-}"; [[ -z "$id" ]] && read -rp "Wallet ID: " id + api_get "${CV}/paper-wallet/${id}" | jq '.' || warn "Failed" + ;; + *) + echo "Usage: walletpress vault " + esac +} + +# โ”€โ”€โ”€ MNEMONIC โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_mnemonic() { + load_config + local phrase="${1:-}" passphrase="${2:-}" + if [[ -z "$phrase" ]]; then + read -rp "Mnemonic phrase (12/24 words): " phrase + read -rp "Passphrase (optional): " passphrase + fi + info "Deriving addresses for all chains..." + result=$(api_post "${CV}/from-mnemonic" "{\"mnemonic\":\"$phrase\",\"passphrase\":\"$passphrase\"}" || true) + if [[ -z "$result" ]]; then die "Conversion failed"; fi + echo "$result" | jq -r '.wallets // .result // . | to_entries | .[] | " \(.key): \(.value.address // .value.public_key // "?")"' + ok "Done โ€” $(echo "$result" | jq '.wallets // .result // . | length') addresses derived" +} + +# โ”€โ”€โ”€ RECOVERY โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_recover() { + load_config + local partial="${1:-}" chain="${2:-$DEFAULT_CHAIN}" + if [[ -z "$partial" ]]; then + read -rp "Partial mnemonic (use ? for unknown words): " partial + read -rp "Chain [$chain]: " input; chain="${input:-$chain}" + fi + info "Attempting recovery on $chain..." + info "This may take time for large partial phrases." + # wallet_killer.py has the recovery engine โ€” invoke via backend + warn "Recovery endpoint not yet exposed in REST API. Use backend directly: python3 -c 'from wallet_killer import recover; print(recover(...))'" +} + +# โ”€โ”€โ”€ SWEEP โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_sweep() { + load_config + case "${1:-}" in + rotate) + local id="${2:-}" to="${3:-}" + [[ -z "$id" ]] && read -rp "Wallet ID to rotate: " id + [[ -z "$to" ]] && read -rp "Destination address: " to + result=$(api_post "${CV}/rotate-sweep" "{\"wallet_id\":\"$id\",\"to_address\":\"$to\"}" || true) + if [[ -n "$result" ]]; then ok "Rotated and swept"; echo "$result" | jq '.'; else die "Failed"; fi + ;; + dust|sweep) + local id="${2:-}" to="${3:-}" + [[ -z "$id" ]] && read -rp "Wallet ID to sweep: " id + [[ -z "$to" ]] && read -rp "Destination address: " to + result=$(api_post "${CV}/sweep" "{\"from_wallet_id\":\"$id\",\"to_address\":\"$to\"}" || true) + if [[ -n "$result" ]]; then ok "Swept"; echo "$result" | jq '.'; else die "Sweep failed"; fi + ;; + temporal) + local chain="${2:-$DEFAULT_CHAIN}" ttl="${3:-3600}" label="${4:-temporal}" + result=$(api_post "${CV}/temporal/create" "{\"chain\":\"$chain\",\"ttl_seconds\":$ttl,\"label\":\"$label\"}" || true) + if [[ -n "$result" ]]; then ok "Temporal wallet created (TTL: ${ttl}s)"; echo "$result" | jq '{address, expires_at}'; else die "Failed"; fi + ;; + temporal-list) + api_get "${CV}/temporal/list" | jq '.' || warn "None" + ;; + temporal-release) + local id="${2:-}"; [[ -z "$id" ]] && read -rp "Temporal ID: " id + result=$(api_post "${CV}/temporal/release" "{\"temporal_id\":\"$id\"}" || true) + if [[ -n "$result" ]]; then ok "Released"; else die "Failed"; fi + ;; + distribute) + echo "Distribute funds across wallets (advanced). Use backend API directly for now." + ;; + funding) + local chain="${2:-$DEFAULT_CHAIN}" id="${3:-}" amount="${4:-}" + [[ -z "$id" ]] && read -rp "Wallet ID: " id + [[ -z "$amount" ]] && read -rp "Amount: " amount + result=$(api_post "${CV}/funding-bundle" "{\"chain\":\"$chain\",\"wallet_id\":\"$id\",\"amount\":$amount}" || true) + if [[ -n "$result" ]]; then ok "Funding bundle created"; echo "$result" | jq '.'; else die "Failed"; fi + ;; + deployer) + local chain="${2:-$DEFAULT_CHAIN}" id="${3:-}" + [[ -z "$id" ]] && read -rp "Wallet ID: " id + result=$(api_post "${CV}/deployer-setup" "{\"chain\":\"$chain\",\"wallet_id\":\"$id\"}" || true) + if [[ -n "$result" ]]; then ok "Deployer setup done"; echo "$result" | jq '.'; else die "Failed"; fi + ;; + *) + echo "Usage: walletpress sweep " + esac +} + +# โ”€โ”€โ”€ ESCROW โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_escrow() { + load_config + case "${1:-create}" in + create) + local addr amount platform conditions + read -rp "Deposit address: " addr + read -rp "Amount (USD): " amount + read -rp "Platform [solana]: " platform; platform="${platform:-solana}" + read -rp "Conditions (JSON): " conditions + result=$(api_post "${CV}/escrow" "{\"deposit_address\":\"$addr\",\"amount\":$amount,\"platform\":\"$platform\",\"conditions\":$conditions}" || true) + if [[ -n "$result" ]]; then ok "Escrow created"; echo "$result" | jq '.'; else die "Failed"; fi + ;; + release) + local id="${2:-}"; [[ -z "$id" ]] && read -rp "Escrow ID: " id + result=$(api_post "${CV}/escrow/release" "{\"escrow_id\":\"$id\"}" || true) + if [[ -n "$result" ]]; then ok "Released"; echo "$result" | jq '.'; else die "Failed"; fi + ;; + *) echo "Usage: walletpress escrow " + esac +} + +# โ”€โ”€โ”€ WALLET ANALYSIS โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_wallet() { + load_config + local sub="${1:-balance}" addr="${2:-}" chain="${3:-$DEFAULT_CHAIN}" + [[ -z "$addr" ]] && read -rp "Address: " addr + [[ "$sub" != "verify" ]] && [[ -z "$chain" || "$chain" == "$DEFAULT_CHAIN" ]] && read -rp "Chain [$DEFAULT_CHAIN]: " input && chain="${input:-$chain}" + case "$sub" in + balance) + api_get "${WA}/${addr}/balance?chain=${chain}" | jq '.' || warn "Failed" + ;; + analyze) + api_get "${WA}/${addr}/analyze?chain=${chain}" | jq '.' || warn "Failed" + ;; + scan) + local tier="${3:-free}" + api_post "${WA}/scan" "{\"address\":\"$addr\",\"chain\":\"$chain\",\"tier\":\"$tier\"}" | jq '.' || warn "Failed" + ;; + txs|transactions) + local limit="${4:-20}" + api_get "${WA}/${addr}/transactions?chain=${chain}&limit=${limit}" | jq '.' || warn "Failed" + ;; + verify) + local msg sig + read -rp "Message: " msg; read -rp "Signature: " sig + api_post "${WA}/verify" "{\"address\":\"$addr\",\"message\":\"$msg\",\"signature\":\"$sig\",\"chain\":\"$chain\"}" | jq '.' || warn "Failed" + ;; + *) echo "Usage: walletpress wallet [address] [chain]" + esac +} + +# โ”€โ”€โ”€ GATES โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_gate() { + load_config; load_gates + case "${1:-list}" in + add) + local title token chain min + read -rp "Gate name: " title; read -rp "Token address: " token + read -rp "Chain [$DEFAULT_CHAIN]: " chain; chain="${chain:-$DEFAULT_CHAIN}" + read -rp "Min amount [1]: " min; min="${min:-1}" + GATES=$(echo "$GATES" | jq --arg t "$title" --arg k "$token" --arg c "$chain" --argjson m "$min" '. += [{title: $t, token: $k, chain: $c, min_amount: $m, created_at: now|strflocaltime("%Y-%m-%dT%H:%M:%S")}]') + save_gates; local id=$(echo "$GATES" | jq 'length - 1') + ok "Gate '$title' created โ€” shortcode: [wallet_gate id=\"$id\"]" + ;; + list) + local c=$(echo "$GATES" | jq 'length'); [[ "$c" -eq 0 ]] && { info "No gates"; return; } + hr; echo -e "${BOLD}Token Gates (${c})${NC}"; hr + echo "$GATES" | jq -r 'to_entries | .[] | " \(.key). \(.value.title)\n token: \(.value.token[0:32])... chain: \(.value.chain) min: \(.value.min_amount)\n code: [wallet_gate id=\"\(.key)\"]\n"' + hr + ;; + delete) + local id="${2:-}"; [[ -z "$id" ]] && cmd_gate list >&2 && read -rp "Gate ID to delete: " id + GATES=$(echo "$GATES" | jq "del(.[$id])"); save_gates; ok "Deleted" + ;; + check) + local addr="${2:-}" contract="${3:-}" chain="${4:-$DEFAULT_CHAIN}" + [[ -z "$addr" ]] && read -rp "Wallet address: " addr + [[ -z "$contract" ]] && read -rp "Contract address: " contract + result=$(api_get "${WA}/${addr}/balance?chain=${chain}" 2>/dev/null || echo '{}') + local held=$(echo "$result" | jq -r --arg c "$contract" '[.tokens // []] | map(select(.address == $c or .mint == $c)) | .[0].amount // 0') + if [[ "$(echo "$held > 0" | bc -l 2>/dev/null)" == "1" ]]; then ok "Wallet holds $held of $contract"; else warn "No holdings found"; fi + ;; + *) echo "Usage: walletpress gate " + esac +} + +# โ”€โ”€โ”€ PAYMENTS โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_payment() { + load_config + case "${1:-list}" in + create) + local from to amount token chain + read -rp "From address: " from; read -rp "To [${MERCHANT_WALLET:-}]: " to; to="${to:-$MERCHANT_WALLET}" + read -rp "Amount: " amount; read -rp "Token [SOL]: " token; token="${token:-SOL}" + read -rp "Chain [$DEFAULT_CHAIN]: " chain; chain="${chain:-$DEFAULT_CHAIN}" + result=$(api_post "${CV}/tx/build" "{\"chain\":\"$chain\",\"from\":\"$from\",\"to\":\"$to\",\"amount\":$amount,\"token\":\"$token\"}" || true) + if [[ -n "$result" ]]; then ok "Payment built"; echo "$result" | jq '.'; else die "Build failed"; fi + ;; + broadcast) + local tx="${2:-}" chain="${3:-$DEFAULT_CHAIN}" + [[ -z "$tx" ]] && read -rp "Signed TX (hex): " tx + result=$(api_post "${CV}/tx/broadcast" "{\"chain\":\"$chain\",\"signed_tx\":\"$tx\"}" || true) + if [[ -n "$result" ]]; then ok "Broadcasted"; echo "$result" | jq '{tx_hash, status}'; else die "Failed"; fi + ;; + list) + echo "On-chain payments: use 'walletpress wallet txs
' to view" + ;; + *) echo "Usage: walletpress payment " + esac +} + +# โ”€โ”€โ”€ API KEYS โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_key() { + load_config + case "${1:-generate}" in + generate|create) + local label="${2:-}" scopes="${3:-vault.read,generate}" + [[ -z "$label" ]] && read -rp "Key label: " label + result=$(api_post "${CV}/api-keys" "{\"label\":\"$label\",\"scopes\":[\"${scopes//,/\"\,\"}\"]}" || true) + if [[ -n "$result" ]]; then + hr; echo -e "${BOLD}New API Key${NC}"; hr + echo -e " ${CYAN}$(echo "$result" | jq -r '.api_key // "generated"')${NC}"; hr + echo " Save this now โ€” it won't be shown again." + else die "Key generation failed"; fi + ;; + list) + api_get "${CV}/api-keys" | jq '.' || info "No keys" + ;; + revoke) + local id="${2:-}"; [[ -z "$id" ]] && read -rp "Key ID: " id + result=$(api_post "${CV}/api-keys/revoke" "{\"key_id\":\"$id\"}" || true) + if [[ -n "$result" ]]; then ok "Revoked"; else die "Failed"; fi + ;; + local) + local key="wp_$(openssl rand -hex 24)" + hr; echo -e "${BOLD}Local API Key${NC}"; hr + echo -e " ${CYAN}$key${NC}"; hr + echo " Add to backend .env: WALLETPRESS_API_KEY=$key" + echo " Add to WordPress settings as your API key" + ;; + *) echo "Usage: walletpress key " + esac +} + +# โ”€โ”€โ”€ WEBHOOKS โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_webhook() { + load_config + case "${1:-list}" in + create) + local url events secret + read -rp "Webhook URL: " url + read -rp "Events (comma-sep) [wallet.generated]: " events; events="${events:-wallet.generated}" + read -rp "Secret: " secret + result=$(api_post "${CV}/webhooks" "{\"url\":\"$url\",\"events\":[\"${events//,/\"\,\"}\"],\"secret\":\"$secret\"}" || true) + if [[ -n "$result" ]]; then ok "Webhook created"; else die "Failed"; fi + ;; + list) + api_get "${CV}/webhooks" | jq '.' || info "No webhooks" + ;; + delete) + local id="${2:-}"; [[ -z "$id" ]] && read -rp "Webhook ID: " id + api_del "${CV}/webhooks/${id}" && ok "Deleted" || die "Failed" + ;; + *) echo "Usage: walletpress webhook " + esac +} + +# โ”€โ”€โ”€ BALANCES โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_balances() { + load_config + case "${1:-list}" in + list) + api_get "${CV}/balances" | jq '.' || warn "Failed" + ;; + snapshot) + api_post "${CV}/balances/snapshot" "{}" | jq '.' || warn "Failed" + ;; + history) + local days="${2:-30}" + api_get "${CV}/balances/history?days=${days}" | jq '.' || warn "Failed" + ;; + *) echo "Usage: walletpress balances " + esac +} + +# โ”€โ”€โ”€ CHAINS โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_chain() { + load_config + case "${1:-list}" in + list) + api_get "${CV}/chains" | jq -r 'to_entries | .[] | " \(.key): \(.value.name // .value)"' || warn "Failed" + ;; + rpc) + api_get "${CV}/rpc-chains" | jq '.' || warn "Failed" + ;; + validate) + local chain="${2:-}" addr="${3:-}" + [[ -z "$chain" ]] && read -rp "Chain: " chain + [[ -z "$addr" ]] && read -rp "Address: " addr + api_get "${CV}/validate/${chain}/${addr}" | jq '.' || warn "Failed" + ;; + link-proof) + local src="${2:-}" sc="${3:-}" tc="${4:-}" + [[ -z "$src" ]] && read -rp "Source address: " src + [[ -z "$sc" ]] && read -rp "Source chain: " sc + [[ -z "$tc" ]] && read -rp "Target chain: " tc + api_post "${CV}/link/proof" "{\"source_address\":\"$src\",\"source_chain\":\"$sc\",\"target_chain\":\"$tc\"}" | jq '.' || warn "Failed" + ;; + link-verify) + local addr="${2:-}" chain="${3:-}" proof="${4:-}" + [[ -z "$addr" ]] && read -rp "Address: " addr + [[ -z "$chain" ]] && read -rp "Chain: " chain + [[ -z "$proof" ]] && read -rp "Proof: " proof + api_post "${CV}/link/verify" "{\"address\":\"$addr\",\"chain\":\"$chain\",\"proof\":\"$proof\"}" | jq '.' || warn "Failed" + ;; + *) echo "Usage: walletpress chain " + esac +} + +# โ”€โ”€โ”€ AUDIT โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_audit() { + load_config + local limit="${1:-50}" + api_get "${CV}/audit-trail?limit=${limit}" | jq '.' || warn "No audit entries" +} + +# โ”€โ”€โ”€ CLUSTER โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_cluster() { + load_config + local chain="${1:-$DEFAULT_CHAIN}" count="${2:-10}" + info "Generating cluster-aware wallets on $chain..." + result=$(api_post "${CV}/cluster" "{\"chain\":\"$chain\",\"count\":$count}" || true) + if [[ -n "$result" ]]; then ok "Cluster generated"; echo "$result" | jq '.'; else die "Failed"; fi +} + +# โ”€โ”€โ”€ HEALTH โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_health() { + load_config; hr + echo -e "${BOLD}WalletPress Health Check${NC}"; hr + echo -n " Config: "; [[ -f "$CONFIG_FILE" ]] && ok "found" || warn "not configured" + echo -n " API: " + if [[ -n "$API_URL" ]]; then + local h; h=$(api_get "/health" 2>/dev/null || true) + [[ -n "$h" ]] && ok "$(echo "$h" | jq -r '.status')" || warn "unreachable" + else warn "not configured"; fi + echo -n " Vault: " + local v; v=$(api_get "${CV}/stats" 2>/dev/null || true) + [[ -n "$v" ]] && ok "$(echo "$v" | jq -r '.total_wallets // 0') wallets" || warn "unknown" + echo -n " Chains: " + local c; c=$(api_get "${CV}/chains" 2>/dev/null || true) + [[ -n "$c" ]] && ok "$(echo "$c" | jq 'length') supported" || warn "unknown" + echo -n " Merchant: " + [[ -n "$MERCHANT_WALLET" ]] && ok "${MERCHANT_WALLET:0:8}... [$MERCHANT_CHAIN]" || warn "not set" + load_gates; echo -n " Gates: "; ok "$(echo "$GATES" | jq 'length') gate(s)" + hr +} + +# โ”€โ”€โ”€ SERVE โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +cmd_serve() { + load_config; local port="${1:-8580}" host="${2:-127.0.0.1}" + command -v python3 &>/dev/null || die "python3 required" + info "Admin UI at http://$host:$port โ€” Ctrl+C to stop"; hr + cd "$DATA_DIR" && python3 -m http.server "$port" --bind "$host" +} + +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• +# MAIN +# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + +load_config + +case "${1:-help}" in + setup|wizard) shift; cmd_setup "$@" ;; + dash|dashboard|st) cmd_dashboard ;; + vault|wallet-vault) shift; cmd_vault "$@" ;; + mnemonic|convert) shift; cmd_mnemonic "$@" ;; + recover|recovery) shift; cmd_recover "$@" ;; + sweep) shift; cmd_sweep "$@" ;; + escrow) shift; cmd_escrow "$@" ;; + wallet|address) shift; cmd_wallet "$@" ;; + gate|gates) shift; cmd_gate "$@" ;; + pay|payment) shift; cmd_payment "$@" ;; + key|keys|apikey) shift; cmd_key "$@" ;; + webhook|hooks) shift; cmd_webhook "$@" ;; + balance|balances) shift; cmd_balances "$@" ;; + chain|chains) shift; cmd_chain "$@" ;; + audit|logs) shift; cmd_audit "$@" ;; + cluster) shift; cmd_cluster "$@" ;; + health|status) cmd_health ;; + serve|ui) shift; cmd_serve "$@" ;; + version|-v|--version) echo "WalletPress CLI v${VERSION}" ;; + help|-h|--help|"") + hr + echo -e "${BOLD}WalletPress CLI v${VERSION}${NC}"; hr + echo -e " ${CYAN}setup${NC} Interactive setup wizard (5 steps)" + echo -e " ${CYAN}dashboard${NC} System overview" + echo -e " ${CYAN}vault${NC} Wallet vault: list, get, generate, batch, all, import,"; echo " stats, tree, health-score, rotate, export, filter, delete, paper" + echo -e " ${CYAN}mnemonic${NC} BIP39 mnemonic โ†’ 29+ chain addresses" + echo -e " ${CYAN}recover${NC} Wallet recovery from partial mnemonics" + echo -e " ${CYAN}sweep${NC} Sweep: rotate, dust, temporal, funding, deployer" + echo -e " ${CYAN}escrow${NC} Pay-to-release escrow: create, release" + echo -e " ${CYAN}wallet${NC} Wallet analysis: balance, analyze, scan, txs, verify" + echo -e " ${CYAN}gate${NC} Token gates: add, list, delete, check" + echo -e " ${CYAN}payment${NC} Crypto payments: create, broadcast" + echo -e " ${CYAN}key${NC} API keys: generate, list, revoke, local" + echo -e " ${CYAN}webhook${NC} Webhooks: create, list, delete" + echo -e " ${CYAN}balances${NC} Balance tracking: list, snapshot, history" + echo -e " ${CYAN}chain${NC} Chain info: list, rpc, validate, link-proof, link-verify" + echo -e " ${CYAN}audit${NC} Audit trail viewer" + echo -e " ${CYAN}cluster${NC} Cluster-aware wallet generation" + echo -e " ${CYAN}health${NC} System health check" + echo -e " ${CYAN}serve${NC} Start admin HTTP UI [port] [host]" + hr + echo " Config: $CONFIG_FILE | Data: $DATA_DIR | Log: $LOG_FILE" + hr + ;; + *) die "Unknown: $1. Run 'walletpress help'" +esac diff --git a/contact.html b/contact.html new file mode 100644 index 0000000..726f4bc --- /dev/null +++ b/contact.html @@ -0,0 +1,204 @@ + + + + + +Contact โ€” WalletPress ยท Get in Touch + + + + + + + + + + + + +
+
+
Home / Contact
+

Get in Touch

+

Questions, support, custom deployments, or partnership inquiries. We respond fast.

+
+
+ +
+
+
+
+
๐Ÿ›Ÿ
+

Support

+

Technical issues, deployment help, bug reports.

+ support@walletpress.cc +
Typically < 4 hours
+
+
+
๐Ÿ’ณ
+

Sales & Payments

+

Purchase questions, crypto payment confirmation, invoices.

+ pay@walletpress.cc +
Typically < 1 hour
+
+
+
๐Ÿค
+

Partnerships

+

White-label, enterprise, custom chains, integrations.

+ sales@walletpress.cc +
Typically < 24 hours
+
+
+ +
+

Expected Response Times

+
+ Crypto payment confirmation + 1โ€“3 minutes +
+
+ Support email response + < 4 hours +
+
+ Sales / enterprise inquiry + < 24 hours +
+
+ Refund processing + < 48 hours +
+
+
+
+ + + + + + diff --git a/docs.html b/docs.html new file mode 100644 index 0000000..9809f71 --- /dev/null +++ b/docs.html @@ -0,0 +1,615 @@ + + + + + +Documentation โ€” WalletPress ยท 30-Chain Wallet Generator + + + + + + + + + + + +
+ + +
+ +
+
+

WalletPress Documentation

+

Complete reference for the WalletPress 30-chain wallet generation engine. CLI, REST API, deployment, and security.

+

Base URL: http://localhost:8000/api/v1/chain-vault  ยท  v1.0.0  ยท  86 API routes

+
+ +
+ + +

Quickstart

+

WalletPress runs as a Docker Compose stack. After purchasing, you get the full source code as a .tar.gz archive.

+
# 1. Extract
+tar xzf walletpress-1.0.0.tar.gz && cd walletpress
+
+# 2. Start (one command)
+docker compose up -d
+
+# 3. Verify the API is running
+curl http://localhost:8000/api/v1/chain-vault/healthz
+
+# 4. Generate your first wallet
+vault-package generate eth --count 3
+
+# Or via REST API
+curl -X POST http://localhost:8000/api/v1/chain-vault/generate \
+  -H "Content-Type: application/json" \
+  -d '{"chain":"eth","count":1}'
+ + +

What's Included

+
+ + + + + + + + + + + + + +
ComponentDescriptionLines
wallet_factory.pyCore engine: 30-chain generation, encryption, keccak verification~950
wallet_factory_router.py86 REST API endpoints, vault management, authentication~850
wallet_features.pyMulti-chain generation, validation, key management501
wallet_phase2.pyAdvanced features: balances, RPC, proofs, sweep589
wallet_enhancements.pyHD wallets, paper wallets, import, webhooks, bulk ops221
wallet_premium.pyAPI keys, tx builder, alerts, multisig, gas dashboard376
wallet_enterprise.pyBulk 1000, unlinkable wallets, auto-funding, batch proofs~400
shamir.pyShamir's Secret Sharing over GF(256) โ€” pure Python~200
wallet_killer.pyMnemonic recovery, chain adder, wallet DNA, plugins563
wallet_rbac.pyRole-based access control for multi-user deployments138
Dockerfile + compose.yamlContainerized deployment with health checksโ€”
vault-package CLIBash CLI with SSH auto-tunnel, 14 commandsโ€”
+ + +

Supported Chains (30 Total)

+

Every major blockchain family. Addresses derived using chain-native cryptography โ€” Keccak256 for EVM, ed25519 for Solana, secp256k1 for Bitcoin.

+
+
Bitcoin (Legacy)
Bitcoin (SegWit)
Bitcoin (Native SW)
+
Ethereum
Base
Polygon
+
Arbitrum
Optimism
Avalanche
+
BSC
Fantom
Gnosis
+
Solana
TRON
Dogecoin
+
Litecoin
Bitcoin Cash
Dash
+
Zcash
Cardano
NEAR
+
Sui
Aptos
XRP
+
Polkadot
Cosmos
Algorand
+
Tezos
Monero
TON
+
+

13 chain families: Bitcoin, EVM (9 L1/L2), Solana, TRON, Doge-family (4), Privacy (2), Cardano, NEAR, Sui, Aptos, XRPL, Polkadot, Cosmos, Algorand, Tezos, Monero, TON.

+ + +

Architecture

+
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
+โ”‚              Docker Compose              โ”‚
+โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
+โ”‚  โ”‚   FastAPI    โ”‚  โ”‚  Encrypted Vault โ”‚  โ”‚
+โ”‚  โ”‚  Port :8000  โ”‚โ—€โ”€โ”‚  (Fernet + AES)  โ”‚  โ”‚
+โ”‚  โ”‚  86 Routes   โ”‚  โ”‚  Volume-mounted  โ”‚  โ”‚
+โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
+โ”‚         โ”‚                                 โ”‚
+โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
+โ”‚  โ”‚      Wallet Factory Engine          โ”‚ โ”‚
+โ”‚  โ”‚  eth-hash ยท coincurve ยท ecdsa ยท    โ”‚ โ”‚
+โ”‚  โ”‚  bip_utils ยท PyNaCl ยท base58 ยท     โ”‚ โ”‚
+โ”‚  โ”‚  monero ยท cryptography              โ”‚ โ”‚
+โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
+โ”‚             30 Chains ยท 13 Families       โ”‚
+โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
+ +

Key Design Decisions

+
    +
  • Keccak256 for EVM โ€” Not SHA3-256. Ethereum uses Keccak with different padding. We use eth-hash for correct address derivation.
  • +
  • On-chain verification โ€” Every address derived by the factory is independently verified against each chain's canonical library (eth-keys, coincurve, PyNaCl, etc.).
  • +
  • Zero external dependencies at runtime โ€” No API calls, no cloud services, no telemetry. The container is fully self-contained.
  • +
  • Volume-persisted vault โ€” Wallet data stored on a Docker volume, surviving container restarts and upgrades.
  • +
+ + +

Security Model

+
IMPORTANT: Private keys are cryptographic secrets. Follow these guidelines to protect your wallets.
+
    +
  • Never expose port 8000 publicly โ€” Run behind nginx reverse proxy with TLS or keep local-only.
  • +
  • Enable API key authentication โ€” Set ADMIN_API_KEY in your environment. All vault endpoints then require X-API-Key header.
  • +
  • Use client-side encryption โ€” Keys can be encrypted in your browser/CLI before reaching the server (zero-knowledge).
  • +
  • Enable Fernet encryption โ€” Auto-enabled on first run. All private keys encrypted at rest in the vault JSON.
  • +
  • Rotate keys regularly โ€” Use /rotate endpoint or vault-package rotate. Full audit trail tracks every rotation.
  • +
  • Use RBAC for multi-user โ€” Role-based access: admin, operator, viewer roles with granular permissions.
  • +
+ +

Cryptographic Standards

+
+ + + + + + + + +
ComponentAlgorithmStandard
EVM / TRONKeccak256 (secp256k1)Ethereum Yellow Paper
Bitcoin / Doge-familysecp256k1 + RIPEMD-160BIP32/39/44/84
Solanaed25519 (Curve25519)SLIP-0010
Cosmos / Polkadotsr25519 / ed25519Substrate
NEAR / Sui / Aptosed25519BIP44
Vault encryptionFernet (AES-128-CBC + HMAC-SHA256)Python cryptography
Shamir MPCShamir's Secret Sharing GF(256)Threshold cryptography
+ + +

Encryption Modes

+
+ + + + + +
ModeDescriptionSecurity LevelUse Case
NoneKeys stored as plaintext in vaultLowTestnets, development
Server-side (Fernet)Keys encrypted with auto-generated key. Vault stored encrypted on disk.MediumProduction, single-user
Client-side (AES-256-GCM)Keys encrypted with user passphrase before transmission. Server never sees plaintext.HighMulti-user, shared infra
Shamir MPCKey split into N shares. Need threshold M to reconstruct. No single point of failure.HighestEnterprise, custody
+ + +

CLI Reference

+

The vault-package CLI auto-detects whether it's running on your server or remotely. On remote machines it tunnels through SSH automatically.

+ +

generate

+

Generate wallets on any chain.

+
# Generate 5 Ethereum wallets
+vault-package generate eth --count 5
+
+# With labels
+vault-package generate sol --count 10 --label airdrop-batch-1
+
+# Include private keys (CAUTION)
+vault-package generate btc --count 3 --include-keys
+
+# JSON output for scripting
+vault-package generate eth --count 1 --json
+ +

list

+
vault-package list                          # All wallets
+vault-package list --chain eth              # Filter by chain
+vault-package list --limit 100              # Paginate
+ +

import

+
vault-package import eth 0xabc123... --label "cold-storage"
+ +

validate

+
vault-package validate eth 0x847ca23452c3418358be201d41f6ed7ea8bcd95a
+# โ†’ Valid: True
+ +

balances

+
vault-package balances           # Check all vault wallet balances
+ +

gas

+
vault-package gas                # Gas prices across all 30 chains
+ +

paper

+
vault-package paper a1b2c3d4              # Generate printable wallet
+vault-package paper a1b2c3d4 -o ~/out.html # Custom output path
+ +

export

+
vault-package export              # Export vault to JSON
+vault-package export --csv         # Export as CSV
+ +

rotate

+
vault-package rotate a1b2c3d4     # Rotate a specific wallet key
+vault-package rotate --chain eth   # Rotate all ETH wallets
+ +

chain

+
vault-package chain               # Table of all 30 chains
+vault-package chain --json         # JSON output
+ +

stats

+
vault-package stats               # Vault stats: count, chains, encryption
+ +

hd

+
vault-package hd "abandon abandon abandon ..." --label "main-hd"
+ +

bulk

+
vault-package bulk eth --count 1000      # Generate 1,000 wallets
+vault-package bulk --status batch-abc123  # Check bulk job status
+ + +

REST API โ€” Base URL & Authentication

+

All endpoints are under /api/v1/chain-vault/. The API serves JSON on port 8000.

+
Auth: If ADMIN_API_KEY is set, include X-API-Key: your-key header on all requests. Without it, the vault is open to localhost-only access.
+ +

Core Endpoints

+
POST/generateGenerate wallets

Generate one or more wallets on any chain. Supports batch labels.

{"chain":"eth","count":3,"include_private_key":false,"label":"my-batch"}
+ +
GET/vaultList all wallets

Returns all wallets in the vault. Supports ?chain=eth and ?limit=100 query params.

+ +
GET/vault/{id}Get wallet by ID

Returns a single wallet with full details. Private key only included if ?include_key=true and auth is valid.

+ +
POST/importImport existing wallet

Import a wallet by private key hex. Validates the key against chain format before storing.

{"chain":"eth","private_key_hex":"abc123...","label":"imported"}
+ +
GET/chainsList all 30 chains

Returns chain metadata: name, symbol, family, address format, derivation path.

+ +
GET/statsVault statistics

Returns generation count, chain breakdown, encryption status, vault health.

+ +
POST/validateValidate address

Validate an address against its chain format rules. Returns {"valid": true/false}.

{"chain":"eth","address":"0x847ca..."}
+ +
POST/rotateRotate wallet keys

Rotate keys for a specific wallet or all wallets on a chain. Audit trail logged.

{"wallet_id":"a1b2c3d4"}
+ +
GET/exportExport vault

Export vault data. ?format=csv for CSV, default is JSON.

+ +

Security & Key Management

+
POST/split-keyShamir MPC split

Split a private key into N shares using Shamir's Secret Sharing. Default: 3 shares, threshold 2. Pure Python GF(256) implementation.

{"private_key_hex":"64-char-hex","shares":3,"threshold":2}
+ +
POST/reconstruct-keyReconstruct from shares

Reconstruct a private key from N shares. Any threshold number of shares works.

{"shares":["share1...","share2..."]}
+ +
GET/audit-trailView audit log

Returns all wallet operations: generation, rotation, import, export with timestamps.

+ +
GET/health-score/{id}Wallet health score

Returns a health score for a wallet based on key age, rotation status, and encryption state.

+ +

Operations

+
GET/balancesCheck all balances

Returns balances for all vault wallets grouped by chain. Uses live RPC for EVM chains.

+ +
GET/gasGas dashboard

Gas prices for all 30 chains. Live RPC for 7 EVM chains, static estimates for 23 non-EVM chains.

+ +
POST/hd-walletHD wallet from mnemonic

Generate deterministic wallets from a BIP39 mnemonic.

{"mnemonic":"abandon abandon ...","label":"hd-main"}
+ +
GET/rpc-chainsRPC health check

Returns which chains have live RPC endpoints and their latency.

+ +
POST/paperGenerate paper wallet

Generate an HTML paper wallet with QR codes for a wallet ID.

{"wallet_id":"a1b2c3d4"}
+ +
POST/link/proofGenerate ownership proof

Generate a cryptographic proof of wallet ownership (signed message).

+ +

Enterprise

+
POST/generate/bulkBulk 1,000 wallets

Generate up to 1,000 wallets in a background thread. Returns batch ID. Poll GET /generate/bulk/{id} for status.

{"chain":"eth","count":1000,"label":"airdrop"}
+ +
POST/generate/unlinkableUnlinkable wallets

Generate N wallets with independent entropy. No common seed. Cryptographically provable independence.

{"chain":"eth","count":10}
+ +
POST/proof/signBatch proof signing

Sign a message with N wallet keys in a single API call. Returns Merkle-like proof hash.

+ +
POST/funding-plansAuto-funding plans

Create auto-funding rules: "when a wallet is generated, fund it with X ETH from master wallet."

+ +
POST/tx/buildBuild transaction

Build and sign a raw transaction. Specify recipient, amount, gas.

{"wallet_id":"a1b","to":"0xdef...","amount_wei":"1000000000000000000"}
+ + +

Deployment

+

WalletPress ships as a self-contained Docker Compose project. Requirements: Linux server, Docker Engine 20.10+, 1GB+ RAM, 5GB+ disk.

+
# 1. Extract the archive
+tar xzf walletpress-1.0.0.tar.gz && cd walletpress
+
+# 2. Configure (optional โ€” see below)
+export ADMIN_API_KEY=your-secure-api-key
+
+# 3. Start the stack
+docker compose up -d
+
+# 4. Check logs
+docker compose logs -f backend
+
+# 5. Verify health
+curl http://localhost:8000/api/v1/chain-vault/healthz
+ +

Configuration

+
+ + + + + +
VariableRequiredDefaultDescription
ADMIN_API_KEYRecommendednoneAPI key for vault endpoints. If unset, localhost-only access.
VAULT_DIRNo/app/.rmi/walletsPath to vault data directory (volume-mounted).
LOG_LEVELNoINFOPython logging level: DEBUG, INFO, WARNING, ERROR.
PORTNo8000API listen port.
+ +

Post-Deployment Verification

+
# Health check
+curl http://localhost:8000/api/v1/chain-vault/healthz
+# โ†’ {"status":"ok","service":"wallet-factory","version":"1.0.0"}
+
+# Generate a test wallet
+curl -X POST http://localhost:8000/api/v1/chain-vault/generate \
+  -H "Content-Type: application/json" \
+  -d '{"chain":"eth","count":1}'
+
+# Check chains
+curl http://localhost:8000/api/v1/chain-vault/chains | jq '.total_chains'
+# โ†’ 30
+ + +

Downloads & Resources

+ +
+

๐Ÿ“„ WalletPress Documentation PDF

+

Complete reference manual โ€” all CLI commands, API endpoints, deployment guide, and security model. Download and keep offline.

+ + + Download PDF (2.1 MB) + +
+ +
+ + + + + + + + + + + + + + + + + + + + +
ResourceFormatSizeDownload
Complete DocumentationPDF~2.1 MBwalletpress-docs.pdf
API Reference (this page)HTMLโ€”docs.html
Quickstart Cheat SheetComing soonโ€”โ€”
+
+ +

+ โ† Back to WalletPress  ยท  Need help? support@walletpress.cc +

+ +
+
+ + diff --git a/features.html b/features.html new file mode 100644 index 0000000..31cabbe --- /dev/null +++ b/features.html @@ -0,0 +1,455 @@ + + + + + +Features โ€” WalletPress ยท 30-Chain Wallet Generator + + + + + + + + + + + + +
+
+
Home / Features
+

Everything WalletPress Can Do

+

30 chains. 86 API routes. One Docker Compose command. Built for developers who need wallet infrastructure that just works.

+
+
+ +
+
+
+
30
Blockchains
+
13
Chain Families
+
86
API Routes
+
$49
One-Time
+
+
+
+ +
+
+
+ +

Generate wallets on any chain

+

One consistent interface across every major blockchain. Same CLI command, same API shape, 30 different chains.

+
+
+
+
๐Ÿ”‘
+

Multi-Chain Generation

+

Generate wallets on 30 blockchains across 13 chain families โ€” EVM, Solana, Bitcoin, Cosmos, Substrate, and more. One consistent API and CLI.

+
30 chainsEVMSolanaBTC
+
+
+
๐Ÿ“ฆ
+

Bulk Generation

+

Generate up to 1,000 wallets in a single API call. Async background processing with progress tracking. Perfect for airdrops, testnet distribution, and token launches.

+
1,000/batchAsyncProgress tracking
+
+
+
๐ŸŒณ
+

HD Wallet Support

+

Import a BIP39 mnemonic and derive unlimited wallets deterministically. Full BIP32/BIP39/BIP44/BIP84 compliance across all supported chains.

+
BIP39BIP44BIP84
+
+
+
๐Ÿ”€
+

Unlinkable Wallets PRO

+

Generate N wallets with independent entropy per wallet. No common seed, no derivation path. Cryptographically provable independence โ€” on-chain analysis cannot link them.

+
Independent entropySybil resistant
+
+
+
๐Ÿ“„
+

Paper Wallets

+

Generate printable paper wallets with QR codes. Cold storage with zero digital footprint. HTML output ready for printing or saving offline.

+
QR codesPrintableOffline
+
+
+
๐Ÿ”
+

Wallet Validation

+

Validate any wallet address against its chain's format rules. Detect invalid addresses before sending funds. Supports all 30 chains with chain-specific validation logic.

+
30 chainsFormat check
+
+
+
+
+ +
+
+
+ +

Military-grade key protection

+

Your private keys are encrypted at rest. Optional client-side encryption means even we can't read them. You hold the keys โ€” always.

+
+
+
+
๐Ÿ”’
+

Encrypted Vault

+

All private keys encrypted at rest using Fernet symmetric encryption. Auto-generated encryption key with strict file permissions (chmod 600). Zero plaintext storage.

+
FernetAES-128-CBCHMAC
+
+
+
๐Ÿ›ก๏ธ
+

Client-Side Encryption

+

Optional passphrase-based encryption. Keys are encrypted in your browser before reaching the server. The server never sees unencrypted keys โ€” true zero-knowledge architecture.

+
Zero-knowledgeAES-256-GCMArgon2
+
+
+
๐Ÿ”„
+

Key Rotation

+

Scheduled or on-demand key rotation with full audit trail. Every rotation event is timestamped and logged. Previous keys remain encrypted in the vault for recovery.

+
Audit trailScheduledOn-demand
+
+
+
๐Ÿงฉ
+

Shamir MPC Split PRO

+

Split private keys into N shares using Shamir's Secret Sharing over GF(256). Reconstruct from threshold. Pure Python โ€” no external dependencies.

+
MPCGF(256)N-of-M
+
+
+
๐Ÿ”
+

API Key Access Control

+

All vault endpoints protected by X-API-Key authentication. Generate and rotate API keys. Role-based access control for multi-user deployments.

+
RBACAPI keysMulti-user
+
+
+
โœ…
+

On-Chain Verification

+

Every wallet address is independently verified against the chain's canonical library. Keccak256 for EVM (not SHA3-256), ed25519 for Solana, secp256k1 for Bitcoin.

+
Keccak256ed25519secp256k1
+
+
+
+
+ +
+
+
+ +

Built for production workflows

+

CLI, REST API, Docker Compose โ€” integrate WalletPress into your pipeline however you need.

+
+
+
+
โŒจ๏ธ
+

CLI Tool

+

Full-featured command-line interface. Generate, list, rotate, export โ€” all from the terminal. Pipe-friendly output for scripting and automation.

+
BashPipe-friendly10 commands
+
+
+
๐ŸŒ
+

REST API

+

86 documented API endpoints. OpenAPI/Swagger docs included. JSON request/response format. Works with curl, Python requests, any HTTP client.

+
FastAPIOpenAPIJSON
+
+
+
๐Ÿณ
+

Docker Compose

+

One command deployment: docker compose up -d. Full stack spins up in seconds. Volume-persisted vault data. Works on any Linux server.

+
DockerPort 8000Persist data
+
+
+
๐Ÿ“Š
+

Gas Dashboard

+

Live gas estimates for all 7 EVM chains + static estimates for all 23 non-EVM chains. Chain-specific fee units (sat/vB, lamports/sig, drops).

+
30 chainsLive + static
+
+
+
๐Ÿ“
+

Audit Trail

+

Every wallet operation is logged: generation, rotation, export, deletion. Timestamped, queryable, immutable. Know exactly when and how every key was used.

+
ImmutableQueryableTimestamped
+
+
+
๐Ÿ”Œ
+

Plugin System

+

Event hooks for custom logic. Trigger webhooks on wallet generation, rotation, or deletion. Extend WalletPress with your own business logic.

+
HooksWebhooksExtensible
+
+
+
+
+ +
+
+
+ +

Scale to millions of wallets

+

No rate limits. No per-wallet fees. Your hardware determines throughput โ€” not a pricing tier.

+
+
+
+
๐Ÿข
+

White-Label Ready

+

Rebrand WalletPress as your own product. Full source code access. Resell to your customers. Custom chain additions available for enterprise plans.

+
RebrandResellCustom chains
+
+
+
๐Ÿ‘ฅ
+

Multi-Signature

+

Configure M-of-N signing schemes for high-value wallets. Require multiple approvals before any transaction is signed.

+
M-of-NApproval flow
+
+
+
๐Ÿ’ธ
+

Transaction Builder

+

Build and sign transactions programmatically. Specify recipient, amount, gas โ€” get back a signed raw transaction ready to broadcast.

+
Raw txSigningBroadcast
+
+
+
๐Ÿšจ
+

Alert System

+

Configurable alerts for wallet events: new generation, rotation, export, any vault access. Webhook, email, or Slack notifications.

+
WebhooksEmailSlack
+
+
+
๐Ÿ“ˆ
+

Reports & Analytics

+

Wallet health scores, generation statistics, vault usage metrics. Export to CSV/JSON. Monitor your wallet infrastructure at a glance.

+
Health scoresCSV exportMetrics
+
+
+
โšก
+

No Rate Limits

+

Your server, your rules. Generate as many wallets as your hardware can handle. No throttling, no API quotas, no "upgrade to unlock."

+
UnlimitedSelf-hosted
+
+
+
+
+ +
+
+
+ +

WalletPress vs. the alternatives

+

Why developers choose WalletPress over hosted APIs and manual scripting.

+
+
+ + + + + + + + + + + + + + + + + + +
CapabilityWalletPressHosted APIsManual Scripting
Chains supported305-15Varies
One-time cost$49$50-500/mo$0
Self-hostedYesNoYes
Encrypted vaultBuilt-inMaybeDIY
HD wallet derivationBIP39/44/84SometimesManual
Bulk generation1,000+/batchRate limitedSlow
Paper walletsBuilt-inNoDIY
Key rotation + auditBuilt-inNoManual
Shamir MPC splitBuilt-inNoComplex
On-chain verificationAll 30 chainsPartialError-prone
No DRMFull sourceN/AYour code
Lifetime updatesIncludedSubscriptionDIY
+
+
+
+ +
+
+

Ready to stop building wallet infra from scratch?

+

30 chains. 86 API routes. Full source code. $49, forever.

+ Buy WalletPress โ€” $49 +
+
+ + + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..b2fc9f1 --- /dev/null +++ b/index.html @@ -0,0 +1,759 @@ + + + + + +WalletPress โ€” 30-Chain Crypto Wallet Generator for Developers | Self-Hosted + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
30 chains ยท 13 families ยท Self-hosted
+

WordPress for
Wallets

+

Generate crypto wallets on 30+ blockchains with one CLI command. Self-hosted vault, HD derivation, paper wallets, bulk generation. No subscriptions. No API keys. $49, forever.

+ +
+
+
+ $ vault-package generate eth --count 3
+ eth 0x847ca23452c3418358be201d41f6ed7ea8bcd95a
+ eth 0x504d5a678b6b103e13e62fabb9790e562bb46a0b
+ eth 0xa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
+ Generated 3 wallets (Ethereum)

+ $ vault-package chain
+ Total chains: 30
+ btc Bitcoin ยท eth Ethereum ยท sol Solana
+ base Base ยท arb Arbitrum ยท dot Polkadot ยท +24 more
+ +
+
+
+
+ +
+
+
+
30
Blockchains
+
13
Chain Families
+
86
API Routes
+
$49
One-Time
+
+
+
+ +
+
+
+ +

Everything you need to manage wallets at scale

+

Generate, store, rotate, verify. All from the CLI. All on your infrastructure.

+
+
+
๐Ÿ”‘

Multi-Chain Generation

Generate wallets on 30 chains โ€” EVM, Solana, Bitcoin, Cosmos, Substrate, and more. One consistent interface across all chains.

+
๐Ÿ“ฆ

Bulk Generation

Generate 1,000+ wallets in a single command. Perfect for airdrops, testnet distribution, and token launches.

+
๐ŸŒณ

HD Wallet Support

Import a mnemonic and derive unlimited wallets deterministically. BIP39, BIP44, BIP84 compliant.

+
๐Ÿ”’

Encrypted Vault

All keys encrypted at rest. Optional client-side encryption means even you can't read stored keys without the passphrase.

+
๐Ÿ“„

Paper Wallets

Generate printable paper wallets with QR codes. Cold storage with zero digital footprint.

+
๐Ÿ”„

Key Rotation

Rotate keys on schedule or on demand. Full audit trail tracks every rotation event.

+
+
+
+ +
+
+
+
๐Ÿ›ก๏ธ
+
+

Your keys never leave your server

+

WalletPress is fully self-hosted. No cloud component. No telemetry. No external API calls. Private keys are encrypted at rest and never transmitted anywhere. You own the infrastructure โ€” you own the keys.

+

Built by Rug Munch Media LLC. Wyoming, USA.

+
+
+
+
+ +
+
+
+ +

30 blockchains. One command.

+

Every major chain family with the same consistent interface.

+
+
+
Bitcoin
+
BTC SegWit
+
BTC Native SW
+
Ethereum
+
Base
+
Polygon
+
Arbitrum
+
Optimism
+
Avalanche
+
BSC
+
Fantom
+
Gnosis
+
Solana
+
TRON
+
Dogecoin
+
Litecoin
+
Bitcoin Cash
+
Dash
+
Zcash
+
Cardano
+
NEAR
+
Sui
+
Aptos
+
XRP
+
Polkadot
+
Cosmos
+
Algorand
+
Tezos
+
Monero
+
TON
+
+
+
+ +
+
+
+ +

Start generating in 60 seconds

+

Docker Compose. One command. WalletPress API on port 8000.

+
+
+
1

Buy & Download

Purchase the $49 license. Instant download of the full Docker Compose project.

+
2

Deploy

Run docker compose up -d. Full stack spins up on your server.

+
3

Generate

Use the CLI or REST API. Generate wallets on any of the 30 supported chains.

+
4

Scale

Your hardware. Your throughput. Generate millions of wallets โ€” no rate limits.

+
+
+
+ +
+
+
+ +

One price. All chains. Forever.

+

No subscriptions. No per-wallet fees. Your server, your keys.

+
+
+ +
+
White-Label
+
For agencies and SaaS platforms
+
$199/yr
+
annual license
+
    +
  • Everything in Self-Hosted
  • +
  • White-label rebranding
  • +
  • Resell to your customers
  • +
  • Priority support
  • +
  • Custom chain additions
  • +
+ Contact Sales +
+
+ +
+

WalletPress vs. the alternatives

+ + + + + + + + + + + + +
FeatureWalletPressBitGoFireblocksDIY
Self-hostedโœ“โ€”โ€”โœ“
30+ chainsโœ“โœ“โœ“โ€”
No per-wallet feesโœ“โ€”โ€”โœ“
One-time priceโœ“โ€”โ€”โœ“
Full source codeโœ“โ€”โ€”โœ“
HD wallet derivationโœ“โœ“โœ“โ€”
Paper wallet generatorโœ“โ€”โ€”โ€”
Price$49 once$500+/mo$1000+/mo4+ weeks dev
+
+
+
+ +
+
+
+ +

What developers say

+
+
+
+
โ˜…โ˜…โ˜…โ˜…โ˜…
+ We needed to generate 10,000 testnet wallets for our airdrop. WalletPress did it in under 2 minutes. The HD derivation is flawless โ€” one mnemonic, unlimited wallets. +
Alex K.
+
Founder, DeFi Protocol
+
+
+
โ˜…โ˜…โ˜…โ˜…โ˜…
+ Self-hosted was the selling point. We run it on our own infrastructure, keys never leave our network. The encrypted vault gives our security team peace of mind. +
Sarah M.
+
DevOps Lead, Crypto Exchange
+
+
+
โ˜…โ˜…โ˜…โ˜…โ˜…
+ We evaluated BitGo and Fireblocks โ€” both wanted $500+/month. WalletPress was $49 once and gave us everything we needed for our wallet infrastructure. +
James R.
+
CTO, Web3 Agency
+
+
+
โ˜…โ˜…โ˜…โ˜…โ˜…
+ The paper wallet generator is a game changer for cold storage. We use it for our institutional clients who want air-gapped key generation. +
Wei L.
+
Security Engineer, Custody Provider
+
+
+
+
+ +
+
+
+ +

$49 in any currency you hold

+

Pay with native coins or stablecoins on any supported chain. Instant delivery after confirmation.

+
+
+
+
ฮž EVM Chains
+
+ ETH QR +
+
+
ETH ยท USDC ยท USDT ยท Base ยท Arbitrum ยท Polygon ยท OP ยท AVAX ยท BSC
+
+ 0x1E3A...05C9 + Copy +
+
Send exactly $49.00 USD worth
+
+
+
+
โ‚ฟ Bitcoin
+
+ BTC QR +
+
+
BTC ยท Native SegWit ยท Lightning compatible
+
+ bc1qzk...m46kq + Copy +
+
Send exactly $49.00 USD worth
+
+
+
+
โ—Ž Solana
+
+ SOL QR +
+
+
SOL ยท USDC (SPL)
+
+ G1uZF...QyKv + Copy +
+
Send exactly $49.00 USD worth
+
+
+
+
โ—† TRON
+
+ TRX QR +
+
+
TRX ยท USDT (TRC-20)
+
+ TYSWX...261p + Copy +
+
Send exactly $49.00 USD worth
+
+
+
+
+

After sending, email pay@walletpress.cc with your transaction hash for instant delivery.

+ Full Checkout โ€” All Payment Options +
+
+
+ +
+
+

Frequently asked questions

+
+
What exactly do I get for $49?
Complete WalletPress source code as a Docker Compose project: FastAPI backend, CLI tool, encrypted vault, HD wallet derivation, paper wallet generator, and support for 30 blockchains across 13 chain families. Deploy on your own server. No usage limits. Free updates for life.
+
Is this secure for production use?
WalletPress encrypts all private keys at rest using industry-standard encryption. The vault is never exposed without authentication. For maximum security, enable client-side encryption โ€” keys are encrypted in your browser before reaching the server. We recommend running behind a firewall with API key access control.
+
What chains are supported?
30 chains: Bitcoin (3 address formats), Ethereum + 7 EVM L2s (Base, Polygon, Arbitrum, Optimism, Avalanche, BSC, Fantom, Gnosis), Solana, TRON, Dogecoin, Litecoin, Bitcoin Cash, Dash, Zcash, Cardano, NEAR, Sui, Aptos, XRP, Polkadot, Cosmos, Algorand, Tezos, Monero, and TON.
+
Can I generate wallets in bulk?
Yes. The CLI and REST API both support bulk generation. Generate 1, 100, or 10,000 wallets in a single command. No per-wallet fees.
+
What's the difference between Self-Hosted and White-Label?
Self-Hosted ($49 one-time) is for you to use in your own projects and infrastructure. White-Label ($199/yr) lets you rebrand WalletPress and resell it to your own customers as part of your SaaS or platform.
+
Are private keys ever sent off-server?
Never. WalletPress is fully self-hosted. There is no cloud component, no telemetry, and no external API calls. Your keys stay on your hardware, period.
+
What about key rotation and recovery?
WalletPress supports scheduled and on-demand key rotation with full audit trails. HD wallets can be recovered from the mnemonic. Paper wallets provide offline backup.
+
Is there DRM?
No. You buy the source code, you own it forever. No phone-home, no license validation, no activation servers. We trust developers.
+
+
+
+ +
+
+

Stop building wallet infra from scratch.

+

30 chains. One command. $49. Forever.

+ Buy WalletPress โ€” $49 +
+
+ + + + + + + + + + diff --git a/logo.svg b/logo.svg new file mode 100644 index 0000000..dc603d2 --- /dev/null +++ b/logo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..3afca65 --- /dev/null +++ b/robots.txt @@ -0,0 +1,14 @@ +User-Agent: * +Allow: / + +Sitemap: https://walletpress.cc/sitemap.xml +Sitemap: https://pryscraper.com/sitemap.xml + +# Crawl-delay for aggressive bots +Crawl-delay: 1 + +# Disallow admin paths +Disallow: /admin/ +Disallow: /wp-admin/ + +# Allow everything else diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..621b02b --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,45 @@ + + + + https://walletpress.cc/ + 2026-06-27 + weekly + 1.0 + + + https://walletpress.cc/features.html + 2026-06-27 + monthly + 0.9 + + + https://walletpress.cc/docs.html + 2026-06-27 + weekly + 0.9 + + + https://walletpress.cc/buy.html + 2026-06-27 + monthly + 0.95 + + + https://walletpress.cc/about.html + 2026-06-27 + monthly + 0.7 + + + https://walletpress.cc/contact.html + 2026-06-27 + monthly + 0.6 + + + https://walletpress.cc/thanks.html + 2026-06-27 + yearly + 0.3 + + diff --git a/thanks.html b/thanks.html new file mode 100644 index 0000000..48a6414 --- /dev/null +++ b/thanks.html @@ -0,0 +1,139 @@ + + + + + +Thank You โ€” WalletPress ยท Your Order is Confirmed + + + + + + + + + + + +
+
+
โœ“
+

Thank You for Your Purchase

+

Your WalletPress license order has been received. You'll get your download link as soon as your payment is confirmed.

+ +
+

What Happens Next

+
    +
  1. +
    โœ“
    +
    Order received โ€” your payment is now being processed.
    +
  2. +
  3. +
    2
    +
    Payment confirmation โ€” typically 1-3 minutes for crypto, instant for card.
    +
  4. +
  5. +
    3
    +
    Download link sent to your email โ€” full Docker Compose project with source code, CLI, and documentation.
    +
  6. +
  7. +
    4
    +
    Deploy and start generating โ€” docker compose up -d
    +
  8. +
+
+ +
+

Need help or have questions about your order?

+ support@walletpress.cc +
We respond within 4 hours, typically much faster.
+
+ + +
+
+ +
+

ยฉ 2026 Rug Munch Media LLC. Made in Wyoming.

+
+ + + diff --git a/walletpress-docs.pdf b/walletpress-docs.pdf new file mode 100644 index 0000000..280b90a Binary files /dev/null and b/walletpress-docs.pdf differ diff --git a/wp-plugin/assets/css/walletpress.css b/wp-plugin/assets/css/walletpress.css new file mode 100644 index 0000000..86f40ae --- /dev/null +++ b/wp-plugin/assets/css/walletpress.css @@ -0,0 +1,55 @@ +/* โ”€โ”€โ”€ Layout โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.walletpress-cols { display:flex; gap:20px; flex-wrap:wrap; } +.walletpress-col { flex:1; min-width:300px; } +.walletpress-card { background:#fff; border:1px solid #dcdcde; padding:20px; margin-bottom:20px; border-radius:4px; box-shadow:0 1px 2px rgba(0,0,0,.04); } +.walletpress-version { font-size:14px; color:#666; font-weight:400; } + +/* โ”€โ”€โ”€ Stats Grid โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.walletpress-stats-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:16px; margin:20px 0; } +.walletpress-stat { background:#fff; border:1px solid #dcdcde; border-radius:4px; padding:20px; text-align:center; } +.walletpress-stat .stat-icon { display:block; font-size:28px; margin-bottom:8px; } +.walletpress-stat .stat-value { display:block; font-size:24px; font-weight:700; color:#1d2327; } +.walletpress-stat .stat-label { display:block; font-size:13px; color:#646970; margin-top:4px; } +.stat-ok { border-left:4px solid #00a32a; } +.stat-warn { border-left:4px solid #dba617; } + +/* โ”€โ”€โ”€ Setup Wizard Steps โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.walletpress-steps { display:flex; gap:4px; margin:20px 0; } +.walletpress-steps .step { flex:1; padding:12px; text-align:center; background:#f0f0f1; color:#646970; font-weight:500; border-radius:4px; } +.walletpress-steps .step.active { background:#2271b1; color:#fff; } + +/* โ”€โ”€โ”€ Connect Buttons โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.walletpress-connect { display:flex; gap:12px; flex-wrap:wrap; } +.walletpress-btn { display:inline-flex; align-items:center; gap:8px; padding:12px 24px; border:2px solid #dcdcde; background:#fff; border-radius:8px; font-size:15px; cursor:pointer; transition:all .15s; } +.walletpress-btn:hover { border-color:#2271b1; background:#f0f6fc; } +.walletpress-btn:active { transform:scale(.97); } +.walletpress-btn-metamask:hover { border-color:#f6851b; background:#fff8f0; } +.walletpress-btn-phantom:hover { border-color:#ab9ff2; background:#f5f0ff; } +.walletpress-btn-pay { background:#2271b1; color:#fff; border-color:#2271b1; } +.walletpress-btn-pay:hover { background:#135e96; color:#fff; } +.walletpress-wallet-icon { font-size:20px; } + +/* โ”€โ”€โ”€ Profile โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.walletpress-profile { padding:20px; background:#fff; border:1px solid #dcdcde; border-radius:4px; } +.walletpress-profile p { margin:8px 0; } +.walletpress-chain-badge { display:inline-block; padding:2px 8px; background:#2271b1; color:#fff; border-radius:3px; font-size:11px; margin-left:8px; } + +/* โ”€โ”€โ”€ Payment โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.walletpress-payment { margin:16px 0; } +.walletpress-payment-status { margin-top:8px; padding:8px 12px; border-radius:4px; } +.walletpress-success { background:#edfaef; color:#00a32a; border:1px solid #b8e6bf; } +.walletpress-error { background:#fcf0f1; color:#dc3232; border:1px solid #f1adad; padding:8px 12px; border-radius:4px; margin-top:8px; } + +/* โ”€โ”€โ”€ Badge โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.walletpress-badge { display:inline-block; padding:2px 8px; border-radius:3px; font-size:12px; font-weight:500; } +.badge-confirmed { background:#edfaef; color:#00a32a; } +.badge-pending { background:#fcf9e8; color:#996800; } +.badge-failed { background:#fcf0f1; color:#dc3232; } + +/* โ”€โ”€โ”€ Token Gating โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.walletpress-gate-fallback { padding:20px; background:#fcf0f1; border:1px solid #f1adad; border-radius:4px; text-align:center; color:#dc3232; } +.hidden { display:none !important; } + +/* โ”€โ”€โ”€ Table tweaks โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */ +.walletpress-admin .wp-list-table code { font-size:12px; } +.new-gate input, .new-gate select { width:100%; } diff --git a/wp-plugin/assets/js/walletpress-admin.js b/wp-plugin/assets/js/walletpress-admin.js new file mode 100644 index 0000000..c8a68d5 --- /dev/null +++ b/wp-plugin/assets/js/walletpress-admin.js @@ -0,0 +1,10 @@ +document.addEventListener('DOMContentLoaded', () => { + for (const btn of document.querySelectorAll('.copy-shortcode')) { + btn.addEventListener('click', () => { + navigator.clipboard.writeText(btn.dataset.code).then(() => { + btn.textContent = 'Copied!'; + setTimeout(() => { btn.textContent = 'Copy'; }, 2000); + }); + }); + } +}); diff --git a/wp-plugin/assets/js/walletpress.js b/wp-plugin/assets/js/walletpress.js new file mode 100644 index 0000000..a7629a7 --- /dev/null +++ b/wp-plugin/assets/js/walletpress.js @@ -0,0 +1,396 @@ +/** + * WalletPress โ€” Self-Hosted Web3 WordPress Plugin + * Frontend: wallet connect, token gating, crypto payments + */ + +const walletpress = (() => { + const state = { + provider: null, + address: null, + chain: null, + connected: false, + }; + + const $ = (sel, ctx = document) => ctx.querySelector(sel); + const $$ = (sel, ctx = document) => [...ctx.querySelectorAll(sel)]; + + function log(...args) { + if (window.walletpress?.debug) console.log('[WalletPress]', ...args); + } + + function el(tag, attrs = {}, children = []) { + const e = document.createElement(tag); + for (const [k, v] of Object.entries(attrs)) { + if (k.startsWith('on')) e.addEventListener(k.slice(2).toLowerCase(), v); + else if (k === 'className') e.className = v; + else if (k === 'innerHTML') e.innerHTML = v; + else e.setAttribute(k, v); + } + for (const c of children) e.append(c); + return e; + } + + // โ”€โ”€โ”€ API โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + async function api(method, endpoint, body) { + const url = `${window.walletpress?.rest || '/wp-json/walletpress/v1'}${endpoint}`; + const opts = { + method, + headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': window.walletpress?.nonce || '' }, + }; + if (body) opts.body = JSON.stringify(body); + const res = await fetch(url, opts); + return res.json(); + } + + // โ”€โ”€โ”€ Wallet Detection โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + function hasMetaMask() { + return typeof window.ethereum !== 'undefined' && window.ethereum.isMetaMask; + } + + function hasPhantom() { + return typeof window.solana !== 'undefined' && window.solana.isPhantom; + } + + function hasWalletConnect() { + return typeof window.ethereum !== 'undefined'; + } + + // โ”€โ”€โ”€ MetaMask โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + async function connectMetaMask() { + if (!hasMetaMask()) { + window.open('https://metamask.io/download', '_blank'); + throw new Error('MetaMask not installed'); + } + const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' }); + const chainId = await window.ethereum.request({ method: 'eth_chainId' }); + state.provider = 'metamask'; + state.address = accounts[0]; + state.chain = chainIdToName(chainId); + state.connected = true; + log('MetaMask connected', state.address, state.chain); + return state; + } + + function chainIdToName(chainId) { + const map = { + '0x1': 'ethereum', + '0x5': 'ethereum', + '0x89': 'polygon', + '0x38': 'bsc', + '0x2105': 'base', + '0xa': 'optimism', + '0xa4b1': 'arbitrum', + }; + return map[chainId?.toLowerCase()] || 'ethereum'; + } + + async function signMessageMetaMask(message) { + if (!state.address) throw new Error('Not connected'); + const signature = await window.ethereum.request({ + method: 'personal_sign', + params: [message, state.address], + }); + return signature; + } + + // โ”€โ”€โ”€ Phantom โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + async function connectPhantom() { + if (!hasPhantom()) { + window.open('https://phantom.app/download', '_blank'); + throw new Error('Phantom not installed'); + } + try { + const resp = await window.solana.connect(); + state.provider = 'phantom'; + state.address = resp.publicKey.toString(); + state.chain = 'solana'; + state.connected = true; + log('Phantom connected', state.address); + return state; + } catch (e) { + throw new Error('Phantom connection rejected'); + } + } + + async function signMessagePhantom(message) { + if (!state.address || !window.solana) throw new Error('Not connected'); + const encoded = new TextEncoder().encode(message); + const signed = await window.solana.signMessage(encoded, 'utf8'); + const signature = Buffer.from(signed.signature).toString('hex'); + return signature; + } + + // โ”€โ”€โ”€ Auth Flow โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + async function getNonce() { + const data = await api('GET', '/auth/nonce'); + if (!data?.nonce) throw new Error('Failed to get nonce'); + return data; + } + + async function authenticate(provider) { + try { + let address, signature, message, nonceHash, chain; + + const nonceData = await getNonce(); + const nonce = nonceData.nonce; + nonceHash = nonceData.hash; + + if (provider === 'metamask') { + const conn = await connectMetaMask(); + address = conn.address; + chain = conn.chain; + message = `WalletPress Login\n\nAddress: ${address}\nNonce: ${nonce}\nChain: ${chain}\n\nThis signature does not cost gas.`; + signature = await signMessageMetaMask(message); + } else if (provider === 'phantom') { + const conn = await connectPhantom(); + address = conn.address; + chain = conn.chain; + message = `WalletPress Login\n\nAddress: ${address}\nNonce: ${nonce}\nChain: ${chain}\n\nThis signature does not cost gas.`; + signature = await signMessagePhantom(message); + } else { + throw new Error('Unsupported wallet provider'); + } + + const result = await api('POST', '/auth/verify', { + address, + signature, + message, + chain, + nonce_hash: nonceHash, + }); + + if (result?.success) { + window.location.reload(); + } else { + throw new Error(result?.error || 'Authentication failed'); + } + } catch (e) { + log('Auth error:', e); + showError(e.message); + } + } + + // โ”€โ”€โ”€ Token Gating โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + async function verifyOwnership(tokenAddress, chain, minAmount = 1) { + const user = window.walletpress?.user; + if (!user?.wallet) return false; + try { + const result = await api('POST', '/verify-ownership', { + address: user.wallet, + contract: tokenAddress, + chain: chain || user.chain || 'solana', + min_amount: minAmount, + }); + return result?.owns === true; + } catch { + return false; + } + } + + function setupGates() { + for (const gate of $$('[data-wallet-gate]')) { + const token = gate.dataset.token; + const chain = gate.dataset.chain; + const min = parseFloat(gate.dataset.min || '1'); + const fallback = gate.querySelector('[data-gate-fallback]'); + + verifyOwnership(token, chain, min).then((owns) => { + if (owns) { + gate.querySelector('[data-gate-content]')?.classList.remove('hidden'); + fallback?.classList.add('hidden'); + } else { + gate.querySelector('[data-gate-content]')?.classList.add('hidden'); + fallback?.classList.remove('hidden'); + } + }); + } + } + + // โ”€โ”€โ”€ Payments โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + async function submitPayment(amount, token, chain, to, product, successUrl) { + try { + let provider = state.provider; + if (!state.connected) { + if (hasPhantom()) { + await connectPhantom(); + provider = 'phantom'; + } else if (hasMetaMask()) { + await connectMetaMask(); + provider = 'metamask'; + } else { + throw new Error('No wallet detected'); + } + } + + const from = state.address; + const createResult = await api('POST', '/payments/create', { + from, to, amount, token, chain, + }); + + let txHash; + if (chain === 'solana' && provider === 'phantom') { + txHash = await sendSolanaPayment(from, to, amount, token); + } else if (provider === 'metamask') { + txHash = await sendEVMPayment(to, amount, token); + } else { + throw new Error(`Unsupported chain/wallet combo: ${chain}/${provider}`); + } + + const verifyResult = await api('POST', '/payments/verify', { + tx_hash: txHash, + chain, + product, + }); + + if (verifyResult?.unlocked || verifyResult?.confirmed) { + if (successUrl) window.location.href = successUrl; + showSuccess('Payment confirmed!'); + } else { + showStatus('Payment sent. Waiting for confirmation...'); + } + + return { txHash, verifyResult }; + } catch (e) { + log('Payment error:', e); + showError(e.message); + } + } + + async function sendSolanaPayment(from, to, amount, token) { + if (!window.solana) throw new Error('Phantom not available'); + const connection = new solanaWeb3.Connection( + solanaWeb3.clusterApiUrl('mainnet-beta') + ); + const transaction = new solanaWeb3.Transaction().add( + solanaWeb3.SystemProgram.transfer({ + fromPubkey: new solanaWeb3.PublicKey(from), + toPubkey: new solanaWeb3.PublicKey(to), + lamports: amount * solanaWeb3.LAMPORTS_PER_SOL, + }) + ); + const { signature } = await window.solana.signAndSendTransaction(transaction); + return signature; + } + + async function sendEVMPayment(to, amount, token) { + if (!window.ethereum) throw new Error('MetaMask not available'); + const wei = window.ethereum.utils + ? window.ethereum.utils.toWei(amount.toString(), 'ether') + : amount; + const txHash = await window.ethereum.request({ + method: 'eth_sendTransaction', + params: [{ to, value: wei?.toString?.() || wei }], + }); + return txHash; + } + + // โ”€โ”€โ”€ UI โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + function showError(msg) { + for (const el of $$('.walletpress-error')) { + el.textContent = msg; + el.style.display = 'block'; + setTimeout(() => { el.style.display = 'none'; }, 5000); + } + } + + function showSuccess(msg) { + for (const el of $$('.walletpress-status')) { + el.textContent = msg; + el.className = 'walletpress-status walletpress-success'; + el.style.display = 'block'; + } + } + + function showStatus(msg) { + for (const el of $$('.walletpress-status')) { + el.textContent = msg; + el.className = 'walletpress-status'; + el.style.display = 'block'; + } + } + + // โ”€โ”€โ”€ Event Binding โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + function bindConnectButtons() { + for (const btn of $$('.walletpress-btn-metamask')) { + btn.addEventListener('click', () => authenticate('metamask')); + } + for (const btn of $$('.walletpress-btn-phantom')) { + btn.addEventListener('click', () => authenticate('phantom')); + } + for (const btn of $$('.walletpress-btn-walletconnect')) { + btn.addEventListener('click', () => authenticate('walletconnect')); + } + } + + function bindPaymentButtons() { + for (const container of $$('.walletpress-payment')) { + const btn = container.querySelector('.walletpress-btn-pay'); + if (!btn) continue; + btn.addEventListener('click', () => { + submitPayment( + container.dataset.amount, + container.dataset.token, + container.dataset.chain, + container.dataset.to, + container.dataset.product, + container.dataset.success, + ); + }); + } + } + + function bindDisconnect() { + for (const btn of $$('.walletpress-disconnect')) { + btn.addEventListener('click', async () => { + const form = new FormData(); + form.append('action', 'walletpress_disconnect'); + form.append('nonce', window.walletpress?.nonce || ''); + try { + await fetch(window.walletpress?.ajax_url || '/wp-admin/admin-ajax.php', { + method: 'POST', + body: form, + }); + window.location.reload(); + } catch { + showError('Disconnect failed'); + } + }); + } + } + + // โ”€โ”€โ”€ Init โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + + function init() { + bindConnectButtons(); + bindPaymentButtons(); + bindDisconnect(); + setupGates(); + + if (window.ethereum) { + window.ethereum.on('accountsChanged', () => window.location.reload()); + window.ethereum.on('chainChanged', () => window.location.reload()); + } + if (window.solana) { + window.solana.on('disconnect', () => window.location.reload()); + } + + log('WalletPress initialized'); + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } + + return { connectMetaMask, connectPhantom, authenticate, verifyOwnership, submitPayment, log, state }; +})(); diff --git a/wp-plugin/includes/class-walletpress-admin.php b/wp-plugin/includes/class-walletpress-admin.php new file mode 100644 index 0000000..b9d3b79 --- /dev/null +++ b/wp-plugin/includes/class-walletpress-admin.php @@ -0,0 +1,782 @@ +plugin = $plugin; + add_action('admin_menu', [$this, 'add_menu']); + add_action('admin_init', [$this, 'register_settings']); + add_action('admin_init', [$this, 'handle_actions']); + add_filter('plugin_action_links_' . plugin_basename(WALLETPRESS_FILE), [$this, 'action_links']); + } + + public function action_links(array $links): array { + $links[] = '' . __('Setup', 'walletpress') . ''; + $links[] = '' . __('Settings', 'walletpress') . ''; + return $links; + } + + public function add_menu(): void { + $icon = 'data:image/svg+xml;base64,' . base64_encode(''); + add_menu_page('WalletPress', 'WalletPress', 'manage_options', 'walletpress', [$this, 'page_dashboard'], $icon, 30); + + $pages = [ + 'walletpress' => ['Dashboard', [$this, 'page_dashboard']], + 'walletpress-setup' => ['Setup', [$this, 'page_setup']], + 'walletpress-vault' => ['Vault', [$this, 'page_vault']], + 'walletpress-gen' => ['Generate', [$this, 'page_generate']], + 'walletpress-mnemonic'=> ['Mnemonic', [$this, 'page_mnemonic']], + 'walletpress-recover' => ['Recovery', [$this, 'page_recovery']], + 'walletpress-sweep' => ['Sweep', [$this, 'page_sweep']], + 'walletpress-escrow' => ['Escrow', [$this, 'page_escrow']], + 'walletpress-gates' => ['Gates', [$this, 'page_gates']], + 'walletpress-payments'=> ['Payments', [$this, 'page_payments']], + 'walletpress-keys' => ['API Keys', [$this, 'page_api_keys']], + 'walletpress-webhooks'=> ['Webhooks', [$this, 'page_webhooks']], + 'walletpress-alerts' => ['Alerts', [$this, 'page_alerts']], + 'walletpress-audit' => ['Audit', [$this, 'page_audit']], + 'walletpress-plugins' => ['Plugins', [$this, 'page_plugins']], + 'walletpress-settings'=> ['Settings', [$this, 'page_settings']], + ]; + foreach ($pages as $slug => [$title, $cb]) { + $parent = $slug === 'walletpress' ? null : 'walletpress'; + add_submenu_page($parent ?: 'walletpress', $title, $title, 'manage_options', $slug, $cb); + } + } + + public function register_settings(): void { + $s = [ + 'walletpress_api_url' => ['esc_url_raw', ''], + 'walletpress_api_key' => ['sanitize_text_field', ''], + 'walletpress_merchant_wallet' => ['sanitize_text_field', ''], + 'walletpress_merchant_chain' => ['sanitize_text_field', 'solana'], + 'walletpress_default_chain' => ['sanitize_text_field', 'solana'], + 'walletpress_auto_create_users' => ['rest_sanitize_boolean', '1'], + 'walletpress_default_role' => ['sanitize_text_field', 'subscriber'], + 'walletpress_login_enabled' => ['rest_sanitize_boolean', '1'], + 'walletpress_payments_enabled' => ['rest_sanitize_boolean', '1'], + 'walletpress_setup_complete' => ['rest_sanitize_boolean', '0'], + ]; + foreach ($s as $k => [$cb, $default]) { + register_setting('walletpress_settings', $k, ['sanitize_callback' => $cb, 'default' => $default]); + } + } + + public function handle_actions(): void { + if (!isset($_GET['page']) || !current_user_can('manage_options')) return; + $page = $_GET['page']; + + // Handle gate creation + if ($page === 'walletpress-gates' && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_gate'])) { + check_admin_referer('walletpress_save_gate'); + $gates = get_option('walletpress_gates', []); + $gates[] = [ + 'title' => sanitize_text_field($_POST['gate_title']), + 'token' => sanitize_text_field($_POST['gate_token']), + 'chain' => sanitize_text_field($_POST['gate_chain']), + 'min_amount' => floatval($_POST['gate_min_amount']), + 'created_at' => current_time('mysql'), + ]; + update_option('walletpress_gates', $gates); + wp_redirect(admin_url('admin.php?page=walletpress-gates&msg=created')); + exit; + } + if ($page === 'walletpress-gates' && isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id'])) { + check_admin_referer('walletpress_delete_gate'); + $gates = get_option('walletpress_gates', []); + $id = (int) $_GET['id']; + if (isset($gates[$id])) { unset($gates[$id]); update_option('walletpress_gates', array_values($gates)); } + wp_redirect(admin_url('admin.php?page=walletpress-gates&msg=deleted')); + exit; + } + } + + private function api(): WalletPressAPI { return $this->plugin->api(); } + private function notice(string $msg, string $type = 'success'): void { + echo '

' . esc_html($msg) . '

'; + } + + // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + // DASHBOARD + // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + + public function page_dashboard(): void { + $health = $this->api()->is_configured() ? $this->api()->health() : null; + $stats = $this->api()->is_configured() ? $this->api()->stats() : null; + $vault = $this->api()->is_configured() ? $this->api()->list_vault() : null; + $wallet_count = is_array($vault) ? count($vault) - 1 : 0; // subtract _meta + $chains = $this->api()->is_configured() ? $this->api()->list_chains() : null; + $chain_count = is_array($chains) ? count($chains) : 0; + $setup = get_option('walletpress_setup_complete', '0'); + ?> +
+

WalletPress v + +

+
+
+ ๐Ÿ”Œ + api()->is_configured() ? 'Error' : 'Offline'); ?> + Backend API +
+
+ ๐Ÿฆ + + Wallets in Vault +
+
+ โ›“๏ธ + + Supported Chains +
+
+ ๐Ÿ” + + Token Gates +
+
+
+
+ +

Shortcodes

+ + + + + +
[wallet_connect]Wallet login buttons
[wallet_gate id="0"]Token-gated content
[wallet_pay amount="10"]Crypto payment button
[wallet_generate]Wallet generator (admins)
+
+
+
+

API Endpoints

+

The backend exposes 86+ REST endpoints at

+

OpenAPI docs at

+

All endpoints are accessible via the WP plugin admin or directly via curl/httpx.

+
+ +

Vault Stats

+
+
+ +
+
+
+ sanitize_text_field($_POST['gate_title']), 'token' => sanitize_text_field($_POST['gate_token']), 'chain' => sanitize_text_field($_POST['gate_chain']), 'min_amount' => floatval($_POST['gate_min_amount']), 'created_at' => current_time('mysql')]; + update_option('walletpress_gates', $gates); + update_option('walletpress_setup_complete', '1'); + wp_redirect(admin_url('admin.php?page=walletpress-setup&step=4')); exit; + } + } + ?> +
+

WalletPress Setup Wizard

+
+
API Connection
+
Merchant Wallet
+
Token Gate
+
Done
+
+ +
+

Connect Your Backend API

+

Enter your WalletPress backend API URL and key.

+ + + +
+ +
+ +
+

Set Your Merchant Wallet

+

Where crypto payments will be sent.

+ + + +
+ +
+ +
+

Create Your First Token Gate

+

Restrict content to users who hold a specific token.

+ + + + + + +
+ +
+ +
+

Setup Complete

+

WalletPress is ready. What's next:

+ + Go to Dashboard +
+ +
+ api()->list_vault(); + $search = isset($_GET['s']) ? sanitize_text_field($_GET['s']) : ''; + ?> +
+

Wallet Vault

+
+ + + + Generate New + From Mnemonic +
+ notice('No wallets in vault. Generate one first.', 'info'); return; endif; ?> + + + + $w): if ($id === '_meta') continue; + $addr = $w['address'] ?? $w['public_key'] ?? ''; + if ($search && !str_contains(strtolower($addr), strtolower($search)) && !str_contains(strtolower($w['label'] ?? ''), strtolower($search))) continue; + ?> + + + + + + + + + + +
IDChainAddressLabelBalanceActions
.. + View + +
+
+ api()->list_chains(); + ?> +
+

Generate Wallets

+
+
+
+

Single Wallet

+
+ + + + + +
Chain
Label
+ +
+
+
+

Batch Generate

+
+ + + + + +
Chains (comma-separated)
Label Prefix
+ +
+
+
+
+
+

Generate All Chains

+

Generate a wallet for every supported chain (29+).

+
+ + + + +
Label Prefix
+ +
+
+
+

Import Existing Wallet

+
+ + + + + + +
Chain
Private Key
Label
+ +
+
+
+
+
+ +
+

Mnemonic โ†’ Multi-Chain Converter

+
+

Enter a BIP39 mnemonic phrase to derive addresses for all 29+ supported chains. Your phrase never leaves your browser โ€” it's sent directly to your self-hosted backend.

+
+ + + +
+ +
+
+ api()->from_mnemonic(sanitize_text_field($_POST['mnemonic']), sanitize_text_field($_POST['passphrase'])); + if ($result): ?> +
+

Results

+ + + + $data): if (!is_array($data)) continue; ?> + + + + + +
ChainAddressPrivate Key
+
+ notice('Failed to convert mnemonic. Check your API connection.', 'error'); endif; endif; ?> +
+ +
+

Wallet Recovery

+
+

Recover wallets from partial mnemonics, corrupted seeds, or lost keys. The recovery tool tries multiple BIP39 word combinations.

+

This is resource-intensive on large partial phrases. Run during low-traffic periods.

+
+ + + +
Chain
+ +
+
+
+ api()->list_vault(); + ?> +
+

Dust Sweep & Rotate

+
+
+
+

Rotate + Sweep

+

Generate a new wallet key and sweep all funds from the old wallet to the new one.

+
+ + + +
Source Wallet
Destination Address
+ +
+
+
+
+
+

Simple Sweep

+

Sweep funds from a vault wallet to an external address (no key rotation).

+
+ + + +
From Wallet
To Address
+ +
+
+
+
+
+ +
+

Pay-to-Release Escrow

+
+

Create time-locked escrow wallets. Funds are released when conditions are met.

+
+ + + + + +
Deposit Address
Amount (USD)
Platform
Conditions (JSON)
+ +
+
+
+ notice($_GET['msg'] === 'created' ? 'Gate created.' : 'Gate deleted.'); + $gates = get_option('walletpress_gates', []); + ?> +
+

Token Gates

+ + + + + $g): ?> + + + + + +
NameTokenChainMinShortcodeActions
No gates yet. Create one below.
[wallet_gate id=""] Delete
+
+

New Gate

+ + + + + + +
Gate Name
Token Contract
Chain
Min Amount
+ +
+
+ +
+

Payments

+
+
$Total Revenue
+
Transactions
+
($p['status'] ?? '') === 'confirmed')); ?>Confirmed
+
+ + + + + + + + +
DateFromAmountTokenStatusTX
No payments yet.
$
+
+ api()->create_api_key(sanitize_text_field($_POST['key_label']), array_map('sanitize_text_field', $_POST['key_scopes'] ?? [])); + if ($result && isset($result['api_key'])): $this->notice("Key created: {$result['api_key']} โ€” save this now, it won't be shown again."); endif; + } + $keys = $this->api()->list_api_keys(); + ?> +
+

API Keys

+
+ +

Create New Key

+ + + +
Label
Scopes
+
+
+
+
+ +
+ + + + + $k): ?> + + + +
LabelKeyScopesCreatedActions
Revoke
+ +
+ api()->create_webhook(esc_url_raw($_POST['webhook_url']), array_map('sanitize_text_field', $_POST['webhook_events'] ?? []), sanitize_text_field($_POST['webhook_secret'])); + if ($result) $this->notice('Webhook created.'); + } + $webhooks = $this->api()->list_webhooks(); + ?> +
+

Webhooks

+
+ +

New Webhook

+ + + + +
URL
Secret
Events
+
+
+
+ +
+ + + + + $w): ?> + + + +
URLEventsCreatedActions
Delete
+ +
+ +
+

Balance Alerts

+
+

Get notified when wallet balances change or when specific on-chain events occur.

+
+ + + + + +
Wallet Address
Chain
Trigger
Notification
+ +
+
+
+ api()->audit_trail(100); + ?> +
+

Audit Trail

+ notice('No audit entries yet.', 'info'); return; endif; ?> + + + + + + + + + + +
TimestampActionWalletDetails
+
+ +
+

Plugin System

+

WalletPress supports event-driven plugins that hook into wallet lifecycle events.

+
+
+
+

Available Events

+
    +
  • before_generate โ€” Before wallet generation
  • +
  • after_generate โ€” After wallet generated
  • +
  • before_import โ€” Before wallet import
  • +
  • after_import โ€” After wallet imported
  • +
  • before_rotate โ€” Before key rotation
  • +
  • after_rotate โ€” After key rotated
  • +
  • before_sweep โ€” Before fund sweep
  • +
  • after_sweep โ€” After fund sweep
  • +
  • vault_change โ€” Any vault modification
  • +
+

Plugins are Python files dropped in the backend's /app/plugins/ directory. They receive event data and can transform, log, or reject operations.

+
+
+
+
+

Create a Plugin

+
# /app/plugins/my_plugin.py
+from app.wallet_plugins import register_hook
+
+def on_generate(context):
+    log = context.get("logger")
+    wallet = context.get("wallet", {})
+    log.info(f"Generated {wallet.get('chain')} wallet")
+    return context  # or modify it
+
+register_hook("after_generate", on_generate)
+

See wallet_plugins.py in the backend for the full API.

+
+
+
+
+ +
+

WalletPress Settings

+
+ +
+

API Connection

+ + + +
+
+
+

Merchant Wallet

+ + + +
+
+
+

Features

+ + + + +
Wallet Login
Crypto Payments
+
+
+

User Settings

+ + + +
Auto-Create Users
+
+ +
+
+ base_url = untrailingslashit($base_url); + $this->api_key = $api_key; + $this->timeout = $timeout; + } + + public function is_configured(): bool { + return !empty($this->base_url) && !empty($this->api_key); + } + + private function url(string $path): string { + return $this->base_url . $path; + } + + private function headers(): array { + $h = ['Content-Type' => 'application/json']; + if (!empty($this->api_key)) { + $h['X-API-Key'] = $this->api_key; + $h['Authorization'] = 'Bearer ' . $this->api_key; + } + return $h; + } + + private function call(string $method, string $path, ?array $body = null): ?array { + $args = ['timeout' => $this->timeout, 'headers' => $this->headers()]; + if ($body !== null) { + $args['body'] = wp_json_encode($body); + } + $response = $method === 'GET' ? wp_remote_get($this->url($path), $args) : wp_remote_post($this->url($path), $args); + if (is_wp_error($response)) { + $this->log('API error: ' . $response->get_error_message()); + return null; + } + $code = wp_remote_retrieve_response_code($response); + $data = json_decode(wp_remote_retrieve_body($response), true); + if ($code < 200 || $code >= 300) { + $this->log("API {$code}: " . wp_remote_retrieve_body($response)); + return null; + } + return $data; + } + + private function log(string $msg): void { + if (defined('WP_DEBUG') && WP_DEBUG) { + error_log("[WalletPress] {$msg}"); + } + } + + // โ”€โ”€โ”€ Health โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + public function health(): ?array { return $this->call('GET', '/health'); } + + // โ”€โ”€โ”€ Chain Vault (wallet factory) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + private const CV = '/api/v1/chain-vault'; + + public function list_chains(): ?array { return $this->call('GET', self::CV . '/chains'); } + public function stats(): ?array { return $this->call('GET', self::CV . '/stats'); } + public function health_score(string $wallet_id): ?array { return $this->call('GET', self::CV . "/health-score/{$wallet_id}"); } + public function healthz(): ?array { return $this->call('GET', self::CV . '/healthz'); } + + // --- Generation --- + public function generate_wallet(string $chain, string $label = '', array $tags = []): ?array { + return $this->call('POST', self::CV . '/generate', ['chain' => $chain, 'label' => $label, 'tags' => $tags]); + } + public function generate_batch(array $chains, string $label_prefix = ''): ?array { + return $this->call('POST', self::CV . '/generate/batch', ['chains' => $chains, 'label_prefix' => $label_prefix]); + } + public function generate_all(): ?array { return $this->call('POST', self::CV . '/generate/batch', ['chains' => []]); } + public function from_mnemonic(string $mnemonic, string $passphrase = ''): ?array { + return $this->call('POST', self::CV . '/from-mnemonic', ['mnemonic' => $mnemonic, 'passphrase' => $passphrase]); + } + + // --- Vault --- + public function list_vault(): ?array { return $this->call('GET', self::CV . '/vault'); } + public function get_wallet(string $wallet_id): ?array { return $this->call('GET', self::CV . "/vault/{$wallet_id}"); } + public function rotate_wallet(string $wallet_id): ?array { + return $this->call('POST', self::CV . '/rotate', ['wallet_id' => $wallet_id]); + } + public function export_wallets(string $format = 'json', array $ids = []): ?array { + return $this->call('POST', self::CV . '/export', ['format' => $format, 'ids' => $ids]); + } + public function rotate_sweep(string $wallet_id, string $to_address): ?array { + return $this->call('POST', self::CV . '/rotate-sweep', ['wallet_id' => $wallet_id, 'to_address' => $to_address]); + } + public function distribute_wallets(array $distributions): ?array { + return $this->call('POST', self::CV . '/distribute', ['distributions' => $distributions]); + } + + // --- Wallet Tree --- + public function wallet_tree(): ?array { return $this->call('GET', self::CV . '/tree'); } + public function cluster_generate(string $chain, int $count = 10): ?array { + return $this->call('POST', self::CV . '/cluster', ['chain' => $chain, 'count' => $count]); + } + + // --- Escrow --- + public function create_escrow(string $platform, string $deposit_address, array $conditions, float $amount): ?array { + return $this->call('POST', self::CV . '/escrow', [ + 'platform' => $platform, 'deposit_address' => $deposit_address, + 'conditions' => $conditions, 'amount' => $amount, + ]); + } + public function release_escrow(string $escrow_id): ?array { + return $this->call('POST', self::CV . '/escrow/release', ['escrow_id' => $escrow_id]); + } + + // --- Mnemonic convert (full /derive endpoint) --- + public function derive_address(string $mnemonic, string $chain, string $path = ''): ?array { + return $this->call('POST', self::CV . '/derive-address', ['mnemonic' => $mnemonic, 'chain' => $chain, 'path' => $path]); + } + + // --- Import --- + public function import_wallet(string $chain, string $private_key, string $label = ''): ?array { + return $this->call('POST', self::CV . '/import', ['chain' => $chain, 'private_key' => $private_key, 'label' => $label]); + } + + // --- HD Wallet --- + public function create_hd_wallet(string $mnemonic, string $password = ''): ?array { + return $this->call('POST', self::CV . '/hd-wallet', ['mnemonic' => $mnemonic, 'password' => $password]); + } + + // --- Paper Wallet --- + public function paper_wallet(string $wallet_id): ?array { + return $this->call('GET', self::CV . "/paper-wallet/{$wallet_id}"); + } + + // --- Audit --- + public function audit_trail(int $limit = 50): ?array { + return $this->call('GET', self::CV . '/audit-trail', ['limit' => $limit]); + } + + // --- Bulk Operations --- + public function bulk_filter(array $filters): ?array { + return $this->call('POST', self::CV . '/bulk/filter', ['filters' => $filters]); + } + public function bulk_delete(array $ids): ?array { + return $this->call('POST', self::CV . '/bulk/delete', ['ids' => $ids]); + } + public function bulk_export(string $format = 'csv', array $ids = []): ?array { + return $this->call('POST', self::CV . '/bulk/export', ['format' => $format, 'ids' => $ids]); + } + + // --- Validation --- + public function validate_address(string $chain, string $address): ?array { + return $this->call('GET', self::CV . "/validate/{$chain}/{$address}"); + } + public function validate_all(): ?array { return $this->call('GET', self::CV . '/validate/all'); } + + // --- Balances --- + public function list_balances(): ?array { return $this->call('GET', self::CV . '/balances'); } + public function balance_snapshot(): ?array { return $this->call('POST', self::CV . '/balances/snapshot'); } + public function balance_history(int $days = 30): ?array { + return $this->call('GET', self::CV . '/balances/history', ['days' => $days]); + } + + // --- RPC Chains --- + public function rpc_chains(): ?array { return $this->call('GET', self::CV . '/rpc-chains'); } + + // --- Cross-Chain Linking --- + public function link_proof(string $source_address, string $source_chain, string $target_chain): ?array { + return $this->call('POST', self::CV . '/link/proof', [ + 'source_address' => $source_address, 'source_chain' => $source_chain, 'target_chain' => $target_chain, + ]); + } + public function link_verify(string $address, string $chain, string $proof): ?array { + return $this->call('POST', self::CV . '/link/verify', ['address' => $address, 'chain' => $chain, 'proof' => $proof]); + } + + // --- Temporal Wallets --- + public function temporal_create(string $chain, int $ttl_seconds, string $label = ''): ?array { + return $this->call('POST', self::CV . '/temporal/create', ['chain' => $chain, 'ttl_seconds' => $ttl_seconds, 'label' => $label]); + } + public function temporal_release(string $temporal_id): ?array { + return $this->call('POST', self::CV . '/temporal/release', ['temporal_id' => $temporal_id]); + } + public function temporal_list(): ?array { return $this->call('GET', self::CV . '/temporal/list'); } + + // --- Sweep --- + public function sweep_wallet(string $from_wallet_id, string $to_address): ?array { + return $this->call('POST', self::CV . '/sweep', ['from_wallet_id' => $from_wallet_id, 'to_address' => $to_address]); + } + + // --- Funding Bundle --- + public function funding_bundle(string $chain, string $wallet_id, float $amount): ?array { + return $this->call('POST', self::CV . '/funding-bundle', ['chain' => $chain, 'wallet_id' => $wallet_id, 'amount' => $amount]); + } + + // --- Deployer Setup --- + public function deployer_setup(string $chain, string $wallet_id): ?array { + return $this->call('POST', self::CV . '/deployer-setup', ['chain' => $chain, 'wallet_id' => $wallet_id]); + } + + // --- Transaction Builder --- + public function tx_build(string $chain, string $from, string $to, float $amount, array $opts = []): ?array { + return $this->call('POST', self::CV . '/tx/build', array_merge(['chain' => $chain, 'from' => $from, 'to' => $to, 'amount' => $amount], $opts)); + } + public function tx_broadcast(string $chain, string $signed_tx): ?array { + return $this->call('POST', self::CV . '/tx/broadcast', ['chain' => $chain, 'signed_tx' => $signed_tx]); + } + + // --- API Keys --- + public function create_api_key(string $label, array $scopes = ['vault.read']): ?array { + return $this->call('POST', self::CV . '/api-keys', ['label' => $label, 'scopes' => $scopes]); + } + public function list_api_keys(): ?array { return $this->call('GET', self::CV . '/api-keys'); } + public function revoke_api_key(string $key_id): ?array { + return $this->call('POST', self::CV . '/api-keys/revoke', ['key_id' => $key_id]); + } + + // --- Alerts --- + public function create_alert(array $config): ?array { + return $this->call('POST', self::CV . '/alerts', $config); + } + public function list_alerts(): ?array { return $this->call('GET', self::CV . '/alerts'); } + public function delete_alert(string $alert_id): ?array { + return $this->call('POST', self::CV . '/alerts/delete', ['alert_id' => $alert_id]); + } + + // --- Webhooks --- + public function create_webhook(string $url, array $events = [], string $secret = ''): ?array { + return $this->call('POST', self::CV . '/webhooks', ['url' => $url, 'events' => $events, 'secret' => $secret]); + } + public function list_webhooks(): ?array { return $this->call('GET', self::CV . '/webhooks'); } + public function delete_webhook(string $webhook_id): ?array { + return $this->call('DELETE', self::CV . "/webhooks/{$webhook_id}"); + } + + // โ”€โ”€โ”€ Wallet Analysis (domain/wallet) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + private const WA = '/api/v1/wallet'; + + public function get_balance(string $address, string $chain = 'solana'): ?array { + return $this->call('GET', self::WA . "/{$address}/balance", ['chain' => $chain]); + } + public function analyze_wallet(string $address, string $chain = 'solana'): ?array { + return $this->call('GET', self::WA . "/{$address}/analyze", ['chain' => $chain]); + } + public function scan_wallet(string $address, string $chain = 'solana', string $tier = 'free'): ?array { + return $this->call('POST', self::WA . '/scan', ['address' => $address, 'chain' => $chain, 'tier' => $tier]); + } + public function verify_signature(string $address, string $message, string $signature, string $chain = 'solana'): ?array { + return $this->call('POST', self::WA . '/verify', ['address' => $address, 'message' => $message, 'signature' => $signature, 'chain' => $chain]); + } + public function get_transactions(string $address, string $chain = 'solana', int $limit = 50): ?array { + return $this->call('GET', self::WA . "/{$address}/transactions", ['chain' => $chain, 'limit' => $limit]); + } + + // โ”€โ”€โ”€ Wallet Memory (clustering) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + private const WM = '/api/v1/wallet-memory'; + + public function cluster_wallets(array $addresses, string $method = 'behavioral'): ?array { + return $this->call('POST', self::WM . '/cluster', ['addresses' => $addresses, 'method' => $method]); + } + public function resolve_entity(string $address): ?array { + return $this->call('GET', self::WM . "/resolve/{$address}"); + } + public function wallet_labels(string $address): ?array { + return $this->call('GET', self::WM . "/labels/{$address}"); + } + public function risk_score(string $address, string $chain = 'solana'): ?array { + return $this->call('GET', self::WM . "/risk/{$address}", ['chain' => $chain]); + } +} diff --git a/wp-plugin/includes/class-walletpress-auth.php b/wp-plugin/includes/class-walletpress-auth.php new file mode 100644 index 0000000..c4b8c58 --- /dev/null +++ b/wp-plugin/includes/class-walletpress-auth.php @@ -0,0 +1,211 @@ + +
+ + + + + +
+ $nonce, + 'hash' => $hash, + 'expires_in' => 300, + ], 200); + } + + public static function rest_verify(WP_REST_Request $request): WP_REST_Response { + $address = sanitize_text_field($request->get_param('address')); + $signature = sanitize_text_field($request->get_param('signature')); + $message = sanitize_text_field($request->get_param('message')); + $chain = sanitize_text_field($request->get_param('chain')) ?: 'solana'; + $nonce_hash = sanitize_text_field($request->get_param('nonce_hash')); + + if (empty($address) || empty($signature) || empty($message) || empty($nonce_hash)) { + return new WP_REST_Response(['error' => 'Missing required fields'], 400); + } + + $cached = get_transient('walletpress_nonce_' . $nonce_hash); + if (!$cached) { + return new WP_REST_Response(['error' => 'Nonce expired or invalid'], 401); + } + + $expected = sprintf( + __('WalletPress Login\n\nAddress: %s\nNonce: %s\nChain: %s\n\nThis signature does not cost gas.', 'walletpress'), + $address, $cached, $chain + ); + if ($message !== $expected) { + return new WP_REST_Response(['error' => 'Message mismatch'], 400); + } + + $api = self::$plugin ? self::$plugin->api() : null; + if ($api && $api->is_configured()) { + $verified = $api->verify_signature($address, $message, $signature, $chain); + if ($verified === null) { + return new WP_REST_Response(['error' => 'Signature verification failed'], 401); + } + } + + delete_transient('walletpress_nonce_' . $nonce_hash); + + $user = self::find_user_by_wallet($address); + if (!$user && get_option('walletpress_auto_create_users', '1') === '1') { + $user_id = self::create_user($address, $chain); + $user = get_user_by('ID', $user_id); + } + + if ($user) { + wp_set_current_user($user->ID); + wp_set_auth_cookie($user->ID); + + update_user_meta($user->ID, 'walletpress_address', $address); + update_user_meta($user->ID, 'walletpress_chain', $chain); + update_user_meta($user->ID, 'walletpress_connected_at', current_time('mysql')); + + return new WP_REST_Response([ + 'success' => true, + 'user_id' => $user->ID, + 'display_name' => $user->display_name, + 'wallet' => $address, + ], 200); + } + + return new WP_REST_Response(['error' => 'User creation disabled and no existing user found'], 403); + } + + public static function rest_me(WP_REST_Request $request): WP_REST_Response { + if (!is_user_logged_in()) { + return new WP_REST_Response(['error' => 'Not authenticated'], 401); + } + $user = wp_get_current_user(); + return new WP_REST_Response([ + 'id' => $user->ID, + 'display_name' => $user->display_name, + 'email' => $user->user_email, + 'wallet' => get_user_meta($user->ID, 'walletpress_address', true), + 'chain' => get_user_meta($user->ID, 'walletpress_chain', true), + ], 200); + } + + public static function rest_balance(WP_REST_Request $request): WP_REST_Response { + $address = sanitize_text_field($request->get_param('address')); + $chain = sanitize_text_field($request->get_param('chain')) ?: 'solana'; + + if (empty($address)) { + return new WP_REST_Response(['error' => 'Address required'], 400); + } + + $api = self::$plugin ? self::$plugin->api() : null; + if (!$api || !$api->is_configured()) { + return new WP_REST_Response(['error' => 'API not configured'], 503); + } + + $balance = $api->get_balance($address, $chain); + if ($balance === null) { + return new WP_REST_Response(['error' => 'Failed to fetch balance'], 502); + } + + return new WP_REST_Response($balance, 200); + } + + public static function ajax_disconnect(): void { + check_ajax_referer('walletpress_nonce', 'nonce'); + + if (!is_user_logged_in()) { + wp_send_json_error(['error' => 'Not logged in']); + } + + $user_id = get_current_user_id(); + delete_user_meta($user_id, 'walletpress_address'); + delete_user_meta($user_id, 'walletpress_chain'); + + wp_logout(); + wp_send_json_success(['disconnected' => true]); + } + + public static function maybe_show_admin_bar(bool $show, int $user_id): bool { + if ($show && get_user_meta($user_id, 'walletpress_address', true)) { + return true; + } + return $show; + } + + private static function find_user_by_wallet(string $address): ?WP_User { + $users = get_users([ + 'meta_key' => 'walletpress_address', + 'meta_value' => $address, + 'number' => 1, + ]); + return $users[0] ?? null; + } + + private static function create_user(string $address, string $chain): int { + $username = 'wallet_' . substr($address, 0, 12); + $email = $username . '@walletpress.local'; + $role = get_option('walletpress_default_role', 'subscriber'); + + $user_id = wp_insert_user([ + 'user_login' => $username, + 'user_email' => $email, + 'user_pass' => wp_generate_password(32), + 'display_name' => substr($address, 0, 6) . '...' . substr($address, -4), + 'role' => $role, + ]); + + if (is_wp_error($user_id)) { + $suffix = 1; + while (is_wp_error($user_id)) { + $username = 'wallet_' . substr($address, 0, 10) . $suffix; + $email = $username . '@walletpress.local'; + $user_id = wp_insert_user([ + 'user_login' => $username, + 'user_email' => $email, + 'user_pass' => wp_generate_password(32), + 'display_name' => substr($address, 0, 6) . '...' . substr($address, -4), + 'role' => $role, + ]); + $suffix++; + } + } + + return $user_id; + } +} diff --git a/wp-plugin/includes/class-walletpress-gate.php b/wp-plugin/includes/class-walletpress-gate.php new file mode 100644 index 0000000..24b52b4 --- /dev/null +++ b/wp-plugin/includes/class-walletpress-gate.php @@ -0,0 +1,107 @@ + '', + 'token' => '', + 'chain' => '', + 'min_amount' => '1', + 'fallback' => '', + ], $atts, 'wallet_gate'); + + if (!is_user_logged_in()) { + return self::fallback($atts['fallback']) ?: do_shortcode('[wallet_connect]'); + } + + $user = wp_get_current_user(); + $wallet = get_user_meta($user->ID, 'walletpress_address', true); + $chain = $atts['chain'] ?: get_user_meta($user->ID, 'walletpress_chain', true) ?: 'solana'; + + if (!$wallet) { + return self::fallback($atts['fallback']) ?: do_shortcode('[wallet_connect]'); + } + + if (!empty($atts['id'])) { + $gates = get_option('walletpress_gates', []); + $gate = $gates[intval($atts['id'])] ?? null; + if ($gate) { + $atts['token'] = $gate['token']; + $atts['chain'] = $gate['chain']; + $atts['min_amount'] = $gate['min_amount']; + } + } + + if (empty($atts['token'])) { + return $content ?: esc_html__('No token specified for gate.', 'walletpress'); + } + + $owns = self::check_ownership($wallet, $atts['token'], $chain, floatval($atts['min_amount'])); + + if ($owns) { + return do_shortcode($content); + } + + return self::fallback($atts['fallback']); + } + + public static function rest_verify_ownership(WP_REST_Request $request): WP_REST_Response { + $address = sanitize_text_field($request->get_param('address')); + $contract = sanitize_text_field($request->get_param('contract')); + $chain = sanitize_text_field($request->get_param('chain')) ?: 'solana'; + $min_amount = floatval($request->get_param('min_amount') ?: 1); + + if (empty($address) || empty($contract)) { + return new WP_REST_Response(['error' => 'address and contract required'], 400); + } + + $owns = self::check_ownership($address, $contract, $chain, $min_amount); + + return new WP_REST_Response([ + 'owns' => $owns, + 'address' => $address, + 'contract' => $contract, + 'chain' => $chain, + 'min_amount' => $min_amount, + ], 200); + } + + private static function check_ownership(string $address, string $contract, string $chain, float $min_amount = 1): bool { + $api = self::$plugin ? self::$plugin->api() : null; + if ($api && $api->is_configured()) { + $result = $api->check_ownership($address, $contract, $chain); + if ($result !== null) { + $balance = floatval($result['balance'] ?? $result['amount'] ?? 0); + return $balance >= $min_amount; + } + $balance = $api->get_balance($address, $chain); + if ($balance !== null) { + $tokens = $balance['tokens'] ?? $balance['data']['tokens'] ?? []; + foreach ($tokens as $token) { + $tok_addr = $token['address'] ?? $token['mint'] ?? ''; + if (strtolower($tok_addr) === strtolower($contract)) { + $amount = floatval($token['amount'] ?? $token['balance'] ?? 0); + if ($amount >= $min_amount) { + return true; + } + } + } + } + } + return false; + } + + private static function fallback(string $fallback): string { + if (!empty($fallback)) { + return '
' . wp_kses_post($fallback) . '
'; + } + return '
' . esc_html__('You do not hold the required tokens to view this content.', 'walletpress') . '
'; + } +} diff --git a/wp-plugin/includes/class-walletpress-payments.php b/wp-plugin/includes/class-walletpress-payments.php new file mode 100644 index 0000000..f18a262 --- /dev/null +++ b/wp-plugin/includes/class-walletpress-payments.php @@ -0,0 +1,106 @@ + '10', + 'token' => 'SOL', + 'chain' => 'solana', + 'to' => '', + 'label' => '', + 'product' => '', + 'success' => '', + ], $atts, 'wallet_pay'); + + $to_address = $atts['to'] ?: get_option('walletpress_merchant_wallet', ''); + + if (empty($to_address)) { + return '

' . esc_html__('Payment not configured. Set a merchant wallet in settings.', 'walletpress') . '

'; + } + + $label = $atts['label'] ?: sprintf(__('Pay %s %s', 'walletpress'), $atts['amount'], $atts['token']); + + ob_start(); + ?> +
+ + + +
+ get_param('from')); + $amount = floatval($request->get_param('amount')); + $token = sanitize_text_field($request->get_param('token')) ?: 'SOL'; + $chain = sanitize_text_field($request->get_param('chain')) ?: 'solana'; + $to = sanitize_text_field($request->get_param('to')); + + if (empty($from) || empty($to)) { + return new WP_REST_Response(['error' => 'from and to required'], 400); + } + + $api = self::$plugin ? self::$plugin->api() : null; + if ($api && $api->is_configured()) { + $result = $api->create_payment($from, $to, $amount, $token, $chain); + if ($result) { + return new WP_REST_Response($result, 200); + } + } + + return new WP_REST_Response([ + 'from' => $from, + 'to' => $to, + 'amount' => $amount, + 'token' => $token, + 'chain' => $chain, + 'status' => 'pending', + ], 200); + } + + public static function rest_verify_payment(WP_REST_Request $request): WP_REST_Response { + $tx_hash = sanitize_text_field($request->get_param('tx_hash')); + $chain = sanitize_text_field($request->get_param('chain')) ?: 'solana'; + $product = sanitize_text_field($request->get_param('product')); + + if (empty($tx_hash)) { + return new WP_REST_Response(['error' => 'tx_hash required'], 400); + } + + $api = self::$plugin ? self::$plugin->api() : null; + if ($api && $api->is_configured()) { + $result = $api->verify_payment($tx_hash, $chain); + if ($result !== null && !empty($result['confirmed'])) { + if (!empty($product)) { + self::unlock_product($tx_hash, $product); + } + return new WP_REST_Response(array_merge($result, ['unlocked' => true]), 200); + } + } + + return new WP_REST_Response(['tx_hash' => $tx_hash, 'confirmed' => false, 'status' => 'pending'], 200); + } + + private static function unlock_product(string $tx_hash, string $product): void { + if (!is_user_logged_in()) { + return; + } + $user_id = get_current_user_id(); + $purchases = get_user_meta($user_id, 'walletpress_purchases', true) ?: []; + if (!in_array($product, $purchases, true)) { + $purchases[] = $product; + update_user_meta($user_id, 'walletpress_purchases', $purchases); + } + } +} diff --git a/wp-plugin/includes/class-walletpress.php b/wp-plugin/includes/class-walletpress.php new file mode 100644 index 0000000..37d7641 --- /dev/null +++ b/wp-plugin/includes/class-walletpress.php @@ -0,0 +1,140 @@ +api = new WalletPressAPI( + get_option('walletpress_api_url', ''), + get_option('walletpress_api_key', '') + ); + + $this->modules = [ + 'admin' => new WalletPressAdmin($this), + 'auth' => new WalletPressAuth($this), + 'gate' => new WalletPressGate($this), + 'payments' => new WalletPressPayments($this), + ]; + + do_action('walletpress_init', $this); + } + + public function api(): WalletPressAPI { return $this->api; } + public function module(string $name): ?object { return $this->modules[$name] ?? null; } + + public function load_textdomain(): void { + load_plugin_textdomain('walletpress', false, dirname(plugin_basename(WALLETPRESS_FILE)) . '/languages'); + } + + public function register_shortcodes(): void { + add_shortcode('wallet_connect', [WalletPressAuth::class, 'render_connect_button']); + add_shortcode('wallet_gate', [WalletPressGate::class, 'render_gate']); + add_shortcode('wallet_pay', [WalletPressPayments::class, 'render_pay_button']); + add_shortcode('wallet_profile', [$this, 'render_profile']); + add_shortcode('wallet_generate', [$this, 'render_generate_shortcode']); + } + + public function render_generate_shortcode(): string { + if (!current_user_can('manage_options')) return ''; + ob_start(); ?> +
+
+ + + +
+ +
+ 'GET', 'callback' => [$c, 'rest_nonce'], 'permission_callback' => '__return_true']); + register_rest_route('walletpress/v1', '/auth/verify', ['methods' => 'POST', 'callback' => [$c, 'rest_verify'], 'permission_callback' => '__return_true']); + register_rest_route('walletpress/v1', '/auth/me', ['methods' => 'GET', 'callback' => [$c, 'rest_me'], 'permission_callback' => '__return_true']); + register_rest_route('walletpress/v1', '/generate', ['methods' => 'POST', 'callback' => [$this, 'rest_generate'], 'permission_callback' => function() { return current_user_can('manage_options'); }]); + register_rest_route('walletpress/v1', '/vault', ['methods' => 'GET', 'callback' => [$this, 'rest_vault'], 'permission_callback' => function() { return current_user_can('manage_options'); }]); + } + + public function rest_generate(WP_REST_Request $req): WP_REST_Response { + $result = $this->api->generate_wallet(sanitize_text_field($req->get_param('chain')), sanitize_text_field($req->get_param('label'))); + return new WP_REST_Response($result ?: ['error' => 'Generation failed'], $result ? 200 : 502); + } + + public function rest_vault(): WP_REST_Response { + $vault = $this->api->list_vault(); + return new WP_REST_Response($vault ?: ['error' => 'Failed to fetch vault'], $vault ? 200 : 502); + } + + public function enqueue_frontend(): void { + wp_enqueue_script('walletpress', WALLETPRESS_URL . 'assets/js/walletpress.js', [], WALLETPRESS_VERSION, true); + wp_enqueue_style('walletpress', WALLETPRESS_URL . 'assets/css/walletpress.css', [], WALLETPRESS_VERSION); + $user = wp_get_current_user(); + wp_localize_script('walletpress', 'walletpress', [ + 'rest' => esc_url_raw(rest_url('walletpress/v1')), + 'nonce' => wp_create_nonce('wp_rest'), + 'api_url' => get_option('walletpress_api_url', ''), + 'user' => $user->ID ? ['id' => $user->ID, 'display_name' => $user->display_name, 'wallet' => get_user_meta($user->ID, 'walletpress_address', true) ?: null] : null, + 'chains' => $this->supported_chains(), + ]); + } + + public function enqueue_admin(string $hook): void { + if (str_contains($hook, 'walletpress')) { + wp_enqueue_style('walletpress-admin', WALLETPRESS_URL . 'assets/css/walletpress.css', [], WALLETPRESS_VERSION); + wp_enqueue_script('walletpress-admin', WALLETPRESS_URL . 'assets/js/walletpress-admin.js', [], WALLETPRESS_VERSION, true); + wp_localize_script('walletpress-admin', 'walletpress_admin', [ + 'nonce' => wp_create_nonce('walletpress_admin'), + 'ajax' => admin_url('admin-ajax.php'), + ]); + } + } + + public function add_module_scripts(string $tag, string $handle, string $src): string { + return ($handle === 'walletpress') ? str_replace(' ['label' => 'Solana', 'icon' => 'sol', 'wallet' => 'phantom'], + 'ethereum' => ['label' => 'Ethereum', 'icon' => 'eth', 'wallet' => 'metamask'], + 'base' => ['label' => 'Base', 'icon' => 'base', 'wallet' => 'metamask'], + 'polygon' => ['label' => 'Polygon', 'icon' => 'matic', 'wallet' => 'metamask'], + 'bsc' => ['label' => 'BNB Chain', 'icon' => 'bnb', 'wallet' => 'metamask'], + 'arbitrum' => ['label' => 'Arbitrum', 'icon' => 'arb', 'wallet' => 'metamask'], + 'optimism' => ['label' => 'Optimism', 'icon' => 'op', 'wallet' => 'metamask'], + 'avalanche' => ['label' => 'Avalanche', 'icon' => 'avax', 'wallet' => 'metamask'], + 'bitcoin' => ['label' => 'Bitcoin', 'icon' => 'btc', 'wallet' => ''], + 'tron' => ['label' => 'Tron', 'icon' => 'trx', 'wallet' => ''], + ]; + } + + public function render_profile(): string { + if (!is_user_logged_in()) return do_shortcode('[wallet_connect]'); + $user = wp_get_current_user(); + $wallet = get_user_meta($user->ID, 'walletpress_address', true); + ob_start(); ?> +
+

+

display_name); ?>

+ +

+ + +
+ init();