aboutsummaryrefslogtreecommitdiffstats
path: root/src/nostr.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-07-06 00:08:34 -0700
committerAdam Soltys <[email protected]>2026-07-06 00:08:34 -0700
commit8e2ff4976db3d7586d7b9c993a94cf9bea071a12 (patch)
tree47a1bf687ef7bbbc3545f81f060edb782c056b5f /src/nostr.js
parenta3783d7e7f53709a8f8352494b9e89583e46f85b (diff)
downloadcoinosv3-8e2ff4976db3d7586d7b9c993a94cf9bea071a12.tar.gz
coinosv3-8e2ff4976db3d7586d7b9c993a94cf9bea071a12.zip
Ark zaps PoC — a NIP-61-shaped zap protocol over arkoor
Lightning zaps are welded to LNURL+bolt11; nutzaps (NIP-61) proved the alternative shape, and ark fits it better than Cashu because delivery already exists (the mailbox). Draft protocol, kinds provisional: kind 10037 (replaceable) announces the wallet's ark address+network; the zap itself is a plain instant arkoor send; kind 9737 is the sender-signed receipt tagging recipient, amount, comment, and the delivered vtxo id — so the receipt is checkable against the actual payment, unlike a bare attestation. UX: paste an npub into Send and hal offers the zap (needs both the ark and sync features; npub decoding is inline bech32 so ark-only builds stay lean). The nostr layer gains generic publishEvent/fetchEvents, exposed through the sync seam as wallet.nostrPublish/nostrFetch. Proven on regtest against a mini NIP-01 relay: announce, resolve, zap 1,000 sats with a comment, instant receipt+delivery, vtxo match. Co-Authored-By: Claude Fable 5 <[email protected]>
Diffstat (limited to 'src/nostr.js')
-rw-r--r--src/nostr.js17
1 files changed, 17 insertions, 0 deletions
diff --git a/src/nostr.js b/src/nostr.js
index ccb797d..d0df2fb 100644
--- a/src/nostr.js
+++ b/src/nostr.js
@@ -161,6 +161,23 @@ export class NostrSync {
return res.some((x) => x.status === 'fulfilled');
}
+ // Publish an arbitrary event (finalized here with our key) to the relays.
+ // Used by features that speak their own event kinds (e.g. ark zaps).
+ async publishEvent(partial) {
+ if (!this.sk) return null;
+ let evt;
+ try {
+ evt = finalizeEvent({ created_at: Math.floor(Date.now() / 1000), tags: [], content: '', ...partial }, this.sk);
+ } catch { return null; }
+ await Promise.allSettled(pool.publish(this.relays, evt));
+ return evt;
+ }
+
+ // Fetch events matching a filter from the relays (best-effort).
+ async fetchEvents(filter, maxWait = 5000) {
+ try { return await pool.querySync(this.relays, filter, { maxWait }); } catch { return []; }
+ }
+
// Fetch the newest decrypted state across relays, or null.
async fetch() {
if (!this.sk) return null;