pull down to refresh

I've been building monostr for a few weeks: an Android Nostr client where the "zap" is a Monero tip. No Lightning, no custodian, no KYC wallet in the middle.

How it works: you register your primary address and private view key with a watcher (the same trust model as stasher.news, which is where I took the idea from). The watcher sees incoming payments, never spends, and publishes a signed tip receipt on Nostr, so any client can show the tip under the note. Paying is a plain monero: link: tap ɱ under a note or on a profile, pick an amount, and Cake, Monerujo, Feather or whatever wallet you use opens with the payment. Likes stay free. Tips can be anonymous (default).

What's there today: feed with separate Posts/Replies tabs, threads, profiles, quotes, reposts, likes and emoji reactions (undo included), tips on notes and profiles (XMR or mXMR), NIP-17 DMs, picture upload to our own Blossom server, mutes, private bookmarks, search, optional proof of work, Amber (NIP-55) or key login, light/dark/OLED black, 8 languages. Own relay at relay.monostr.com. AGPL, everything in one repo (app, watcher, relay, media server), reproducible release builds.

What it is not: no iOS, no embedded wallet, one watcher running (the protocol is federated, the watcher URL lives in your profile, but mine is the only public one so far). Expect beta bugs; releases come every few days.

I'd like feedback from people who actually tip in XMR: does the flow make sense, what's missing before you'd use it daily?

Get it: Zapstore (zapstore.dev/apps/com.monostr.app), GitHub releases (also works with Obtainium); F-Droid is in review. Site: monostr.com · Source: github.com/schmidt1024/monostr

Nice work, I was also thinking about integrating Monero in Nostr recently. Your protocol document also looks very interesting, though I needed a translation since it's only in German. Here's my feedback:


General

I think you're assuming Watchers to be big centralised services that run on their own internet domains (probably alongside their own Nostr relay infrastructure).
I'm not against lightweight wallet service itself, but the specification should leave out some room for individual users to be able to become self-custodial.

In my opinion, watcher should be able to run on any computer that is always online; ideally, even smartphones could become a watcher and sync the wallet periodically (e.g. every 1 hour) and watch for tips. This way users can avoid giving out private view keys to big watcher providers with minimal friction.

Payment-Info (kind 10037)

  • Again, the watcher tag expects its own internet domain as the first argument. Your 'Watcher HTTP API' section implies all watchers must expose an HTTP server. This is just too big of a burden. The HTTP API can be replaced with encrypted messages on Nostr, if such an interaction is absolutely required.
  • Why not have ["watcher", "<watcher-hex-pubkey>", "<optional-relay>"]? This way, if relay is not specified, it would imply payer can send tip intent events to any inbox relay of the tip recipient.
  • Maybe the watcher tag itself can be optional, in this case it would mean the tip recipient can watch and sign payment receipts using her own pubkey.

Tip-Intent (kind 9738)

  • Payer unilaterally deciding the payment ID looks fine, although I concern some security implications. I once thought payment IDs could be derived in somewhat more deterministically random process, something like HMAC-SHA256("<payer-pubkey>", "<recipient-pubkey>:<note-id>:<nonce>"), but I don't think it is worth complicating the specification. Simply mentioning clients should generate payment IDs using a secure pseudorandom algorithm would be sufficient.
  • The current way has some advantages over alternatives, e.g. asking recipient to generate a subaddress or payment ID; other methods would require the process to go through more steps (payer publishes tip intent → recipient gives an address → payer pays XMR (outside Nostr) → recipient or watcher confirms receipt), which means more problems (How do recipients manage subaddresses? Should the address be sent encrypted to payer? etc.). So I'm okay with keeping with the current proposal.

Tip-Receipt (kind 9739)

  • I also think not containing txid in the receipt is the way to go. This does place some trust on the watcher, and there is some hypothetical issue of watchers manipulating fake tip receipts. But such dishonesty can be discovered by other means, and it is also discouraged by social incentives (it hurts watcher's reputation, whether or not it's a big central service or just a recipient running her own watcher).
  • It also appears on Tip-Intent event, but I don't know what the type tag is for. Maybe omission can be the default, and the tag can be optionally set to indicate other modes of payment?

Sorry for being a bit harsh (maybe too toxic), but that is what went through my mind when reading the proposal. Further criticism and discussion are welcome :)

reply

Your idea made it into 0.17: the watcher can now be addressed by its pubkey and relays instead of a domain. It runs on your own machine without a node or domain; the app sets it up from an nprofile. https://github.com/schmidt1024/monostr/blob/main/watcher/SELFHOST.md

reply

Thanks, this is exactly the kind of review I was hoping for; not harsh at all.

pid: agreed. The app already uses a CSPRNG. It is now a MUST. The watcher accepts only the first intent per (recipient, pid) so a predictable pid would let someone front-run an intent and claim another person's payment. I kept random pids rather than HMAC derivation, since the intent is public anyway and fresh randomness is the simplest thing to get right.

type tag: it's display-only, so clients can count a tip that was coupled to a like or repost on that button instead of listing it as a separate tip. A missing tag now means tip. App and watcher still always write it, so older versions don't break.

Both changes are done (spec v0.3) and will ship with the next release.

Personal watchers / pubkey instead of domain: this is the strongest point and I think you're right. Running a watcher shouldn't need a domain, TLS and an HTTP API. ["watcher", "<pubkey>", "<relay>"] plus encrypted Nostr messages for registration would let anyone run one on a home box and an optional tag fits that model too. That's a bigger change to spec, watcher and app, so it won't be in the next release. I want to design it properly first, but it's now at the top of the protocol list.

No txid: glad we agree.

reply

Nice work. The flow makes sense for someone who already tips in XMR. One thing worth saying louder, for Stashers and monostr users both -- the watcher does not only see tips. A view key on the primary address sees every incoming payment to it. The receipt then publishes the tip amount on Nostr, so the amount privacy Monero gave you is gone on the social side. Fine if that address is only for tips. Less fine if it is the one you actually use.

reply

Update: both points are addressed now. 0.17: a personal watcher runs on your own machine, so the view key never leaves you. 0.18: tip amounts are hidden by default, intent and receipt no longer carry the amount. Guide: https://github.com/schmidt1024/monostr/blob/main/watcher/SELFHOST.md

reply

that's why setup tells you to use a separate wallet just for tips and offers to create a fresh one right there. The watcher sees every incoming payment to that wallet (!) and the receipt makes amount + recipient public by design (that's what makes tips visible under notes, like zaps). Senders can stay anonymous; amounts can't. If you want zero exposure, run your own watcher.

reply

Awesome. Just downloaded it and checking it out.

FWIW: I run a paid Monero relay. 0.007 XMR to have write access forever. Just a way to tailor content to Monero users and fight spam.

https://xmr.ithurtswhenip.ee
wss://xmr.ithurtswhenip.ee

reply

Been using this for a couple days and I really like it. It's the first client that I've used that's managed to replace Primal for me, which I knew I had to leave, but didn't have a good option to go to

reply

Update: Since this post, monostr got two changes that answer the main concerns raised here:

  • Your view key can stay with you (0.17). A personal watcher runs on a Raspberry Pi, a NAS or any small server. It needs no Monero node, no domain and no open port. It scans through public nodes, and a payment counts only when two independent nodes report it. Tutorial: https://monostr.com/watcher/personal/
  • Tip amounts are hidden by default (0.18). Receipts show that someone tipped, not how much. Showing amounts is opt-in.

If you'd rather run a full watcher with your own node, for yourself or for others: https://monostr.com/watcher/self-host/

Feedback welcome, here or on Nostr.

reply

we need more desktop clients

i'm slowly getting rid of smartphone for good

reply