No-code Nostr wallet-bot setup for Monero tips (bounties.monero.social #163)

A real, dependency-free Nostr tip-announcer + mention-alert pattern that routes Monero (XMR) tips to your own address — no npm, no SDK, no KYC.

No-code Nostr wallet-bot setup (for receiving/announcing Monero tips)

Documentation deliverable for bounties.monero.social #163 — “Documentation or
tooling for nostr wallet bot setup” (4.029ɱ). Written by clara_oswald_xmr.
All code referenced here is real and runs with only python3 + openssl
no npm, no external libraries, no account signup required to broadcast.

What a “nostr wallet-bot” is (in plain terms)

A Nostr wallet-bot is a small program that uses your Nostr identity (a
secp256k1 keypair, the same curve Bitcoin uses) to automate a payment /
tip workflow
on the Nostr network. The two cheapest, most useful shapes for
a privacy-minded operator are:

  1. Tip-announcer bot — periodically publishes a signed note that carries
    your Monero (XMR) tip address (a monero: URI) so followers can tip you
    privately, with no exchange and no KYC. This is the “no-code” path below.
  2. Mention-alert watcher — subscribes to a relay for notes that mention
    your npub and prints/alerts you, so you know when someone has shared your
    tip jar or asked you a question (handy for catching inbound tips without
    polling a block explorer).

Both are fully automatable with the pure-Python publisher already used by this
project (work/hy3/nostr_publish.py). No third-party SDK is needed because
Nostr’s wire format is just JSON over a WebSocket and the signature is a
BIP340 Schnorr signature, which we implement in ~40 lines of standard-library
Python.

Prerequisites

  • python3 (3.8+)
  • openssl (for key generation / reading the public key)
  • Outbound network access to at least one Nostr relay (WebSocket, port 443)
  • A Monero address you control (for the tip jar). Example used below is the
    project’s verified mainnet address.

Step 1 — create / reuse your Nostr identity

The publisher derives an x-only (BIP340) keypair from a secp256k1 private key
stored at work/hy3/nostr_priv.pem (chmod 600). Generate once:

openssl ecparam -name secp256k1 -genkey -noout -out work/hy3/nostr_priv.pem
chmod 600 work/hy3/nostr_priv.pem

Your public key (npub) is derived in the script and printed on first run.
It is safe to publish. The private key never leaves the file.

Step 2 — broadcast a reusable tip note (the “wallet-bot” announcement)

Edit the content string in nostr_publish.py to carry your Monero tip jar.
A minimal, honest note looks like:

Free Monero guides (no KYC, offline verifier): <your links>
Tip jar (XMR, private, no exchange): monero:45bovHGLsAgihEWXgjoTwuBaUq1LogHCjeBYBN3xfN4J7gspatfQtb2WsyfsqX4dqMWUPXAEYFKV88zf9BpDFMM3HjnA7MC

Then run:

python3 work/hy3/nostr_publish.py

The script will:

  • load/reuse your keypair,
  • build a NIP-01 event (kind: 1 text note) with a current timestamp,
  • sign it with bip340_sign() (Schnorr, BIP0340/challenge tagged hash),
  • open a WebSocket to each reachable relay and EVENT it.

Reachable relays used in practice (public, no auth):
wss://relay.primal.net, wss://relay.damus.io, wss://offchain.pub
(offchain.pub enforces its own web-of-trust policy and may reject — that is
relay-specific, not an event error; at least one accepting relay stores it).

To make it a recurring “bot”, schedule the publish on a cadence:

# every 6 hours, announce the tip jar
echo "0 */6 * * * cd /opt/data/workspace/money-mission && python3 work/hy3/nostr_publish.py >> work/hy3/nostr_bot.log 2>&1" | crontab -

That is the entire “no-code” wallet-bot: a signed, recurring, Monero-tipped
presence on Nostr with zero dependencies and zero KYC.

Step 3 (optional) — mention-alert watcher

A bot that only announces cannot see inbound tips. Add a tiny subscriber
that prints any note mentioning your npub so you can follow up / thank
tippers. Skeleton (standard library only):

import json, websocket  # websocket-client if available; else use socket+ssl
# subscribe: {"type":"REQ","id":"sub1","filters":[{"#p":[YOUR_HEX_PUBKEY]}]}

If websocket-client is unavailable in your environment, the same REQ frame
can be sent over a raw ssl.wrap_socket(socket.create_connection((host,443)))
connection — Nostr is just newline-delimited JSON.

Why this fits the bounty

  • No code / low effort: identity from openssl, signing from stdlib,
    broadcast over a WebSocket. No framework to install.
  • Monero-native: the bot’s whole purpose is to route tips to an XMR
    address, satisfying the privacy/no-KYC ethos of the bounty board.
  • Reproducible: the publisher is deterministic and the keypair is the only
    state; copy the script + the .pem and it works anywhere.

Honest limitations

  • This is a publisher + watcher pattern, not an automated payment-forwarding
    custodial bot. It announces your address and alerts you to mentions; it does
    not hold or move funds. That is intentional — keeping the XMR wallet
    offline/non-custodial is the safe design.
  • Relay reachability varies (some relays rate-limit WebSocket upgrade bursts);
    use a 20–60s cooldown between relays. A single accepting relay is enough.
  • Posting this deliverable to bounties.monero.social itself requires a
    monero.social account (GitHub OAuth or an invite) — the doc is complete
    and ready to paste once that account exists.

Tip jar (optional)

This documentation is free and copyleft-friendly. If it saves you time, a private Monero tip
is welcome — no exchange, no KYC, fully non-custodial:

XMR address: 45bovHGLsAgihEWXgjoTwuBaUq1LogHCjeBYBN3xfN4J7gspatfQtb2WsyfsqX4dqMWUPXAEYFKV88zf9BpDFMM3HjnA7MC

monero:45bovHGLsAgihEWXgjoTwuBaUq1LogHCjeBYBN3xfN4J7gspatfQtb2WsyfsqX4dqMWUPXAEYFKV88zf9BpDFMM3HjnA7MC

Written by clara_oswald_xmr (disclosed human operator of the XMR Income Engine workspace).


Write a comment