#!/bin/bash # Colors for output GREEN='\033[0;32m' BLUE='\033[0;34m' CYAN='\033[0;36m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' # No Color # Configuration CONFIG_FILE="config.json" DELAY=10 # Default 10 second delay show_usage() { echo "Superball Test Thrower" echo "" echo "Usage:" echo " $0 [options]" echo "" echo "Options:" echo " -c, --config Config file path (default: config.json)" echo " -d, --delay Delay in seconds (default: 10)" echo " -m, --message Message to send (default: 'Test superball')" echo " -h, --help Show this help message" echo "" echo "Creates a Superball routing event and throws it to the thrower." } # Default message includes timestamp MESSAGE="Test superball - $(date '+%Y-%m-%d %H:%M:%S %Z')" while [[ $# -gt 0 ]]; do case $1 in -c|--config) CONFIG_FILE="$2" shift 2 ;; -d|--delay) DELAY="$2" shift 2 ;; -m|--message) MESSAGE="$2" shift 2 ;; -h|--help) show_usage exit 0 ;; *) echo "Unknown option: $1" show_usage exit 1 ;; esac done # Check if nak is installed if ! command -v nak &> /dev/null; then echo -e "${RED}Error: 'nak' command not found${NC}" echo "Please install nak: https://github.com/fiatjaf/nak" exit 1 fi # Check if jq is installed if ! command -v jq &> /dev/null; then echo -e "${RED}Error: 'jq' command not found${NC}" exit 1 fi # Load config.json if [[ ! -f "$CONFIG_FILE" ]]; then echo -e "${RED}Error: Config file not found: $CONFIG_FILE${NC}" exit 1 fi echo -e "${BLUE}Loading configuration from $CONFIG_FILE...${NC}" # Extract thrower pubkey from config THROWER_PRIVKEY=$(jq -r '.thrower.privateKey // empty' "$CONFIG_FILE") if [[ -z "$THROWER_PRIVKEY" ]]; then echo -e "${RED}Error: Could not find thrower.privateKey in config${NC}" exit 1 fi THROWER_PUBKEY=$(echo "$THROWER_PRIVKEY" | nak key public) if [[ -z "$THROWER_PUBKEY" ]]; then echo -e "${RED}Error: Could not derive thrower pubkey${NC}" exit 1 fi echo -e "${GREEN}✓ Thrower pubkey: ${THROWER_PUBKEY:0:16}...${NC}" # Get relays from config mapfile -t RELAYS < <(jq -r '.relays[].url' "$CONFIG_FILE") if [[ ${#RELAYS[@]} -eq 0 ]]; then echo -e "${RED}Error: No relays found in config${NC}" exit 1 fi echo -e "${GREEN}✓ Loaded ${#RELAYS[@]} relay(s)${NC}" # Generate ephemeral keypair for this superball echo -e "${BLUE}Generating ephemeral keypair...${NC}" EPHEMERAL_PRIVKEY=$(nak key generate) EPHEMERAL_PUBKEY=$(echo "$EPHEMERAL_PRIVKEY" | nak key public) echo -e "${GREEN}✓ Ephemeral pubkey: ${EPHEMERAL_PUBKEY:0:16}...${NC}" # Generate audit tag (random 32-byte hex) AUDIT_TAG=$(openssl rand -hex 32) echo -e "${GREEN}✓ Audit tag: ${AUDIT_TAG:0:16}...${NC}" # Create a simple kind 1 note as the inner event echo -e "${BLUE}Creating inner event (kind 1 note)...${NC}" INNER_EVENT=$(nak event -c "$MESSAGE" --kind 1 --sec "$EPHEMERAL_PRIVKEY") echo -e "${GREEN}✓ Inner event created${NC}" # Build the routing payload ROUTING_PAYLOAD=$(jq -n \ --argjson event "$INNER_EVENT" \ --arg relays "$(printf '%s\n' "${RELAYS[@]}" | jq -R . | jq -s .)" \ --argjson delay "$DELAY" \ --arg audit "$AUDIT_TAG" \ '{ event: $event, routing: { relays: ($relays | fromjson), delay: $delay, padding: "+0", audit: $audit } }') echo -e "${CYAN}Routing payload:${NC}" echo "$ROUTING_PAYLOAD" | jq '.' # Encrypt the payload with NIP-44 using thrower's pubkey echo -e "${BLUE}Encrypting payload with NIP-44...${NC}" ENCRYPTED_CONTENT=$(nak encrypt --sec "$EPHEMERAL_PRIVKEY" --recipient-pubkey "$THROWER_PUBKEY" "$ROUTING_PAYLOAD") if [[ -z "$ENCRYPTED_CONTENT" ]]; then echo -e "${RED}Error: Failed to encrypt payload${NC}" exit 1 fi echo -e "${GREEN}✓ Payload encrypted (length: ${#ENCRYPTED_CONTENT})${NC}" # Create the routing event (kind 22222) echo -e "${BLUE}Creating routing event (kind 22222)...${NC}" # Build tags array TAGS=$(jq -n \ --arg thrower "$THROWER_PUBKEY" \ --arg audit "$AUDIT_TAG" \ '[ ["p", $thrower], ["p", $audit] ]') # Create the event ROUTING_EVENT=$(nak event \ --kind 22222 \ --sec "$EPHEMERAL_PRIVKEY" \ -c "$ENCRYPTED_CONTENT" \ -t "p=$THROWER_PUBKEY" \ -t "p=$AUDIT_TAG") if [[ -z "$ROUTING_EVENT" ]]; then echo -e "${RED}Error: Failed to create routing event${NC}" exit 1 fi echo -e "${GREEN}✓ Routing event created${NC}" echo -e "${CYAN}Full routing event JSON:${NC}" echo "$ROUTING_EVENT" | jq '.' # Publish to all relays echo "" echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${YELLOW}Throwing Superball to relays...${NC}" echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" for relay in "${RELAYS[@]}"; do echo -e "${BLUE}Publishing to: $relay${NC}" RESPONSE=$(echo "$ROUTING_EVENT" | nak event "$relay" 2>&1) echo "$RESPONSE" echo "" done echo "" echo -e "${GREEN}✓ Superball thrown!${NC}" echo "" echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "${YELLOW}Monitoring for audit tag appearance...${NC}" echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" echo -e "Audit tag: ${GREEN}$AUDIT_TAG${NC}" echo -e "Expected delay: ${GREEN}${DELAY}s${NC}" echo -e "Watch with: ${BLUE}nak req -k 22222 --stream '#p=$AUDIT_TAG' ${RELAYS[0]}${NC}" echo ""