import { finalizeEvent, verifyEvent, getPublicKey, nip19 } from "nostr-tools"; import { useWebSocketImplementation, Relay } from "nostr-tools/relay"; import WebSocket from "ws"; useWebSocketImplementation(WebSocket); const TWO_DAYS = 48 * 60 * 60 * 1000; const RELAY = "TODO"; const BOT = JSON.stringify({ name: "BOT", about: "a little exercise", }); let intervalId; try { const args = [...process.argv]; args.shift(); args.shift(); if (!args.includes("-nsec")) { console.error("BOT NEEDS NSEC.\n-nsec "); process.exit(1); } const index = args.findIndex((arg) => arg === "-nsec"); const nsec = args[index + 1]; if (typeof nsec === "undefined" || nsec === "" || !nsec.startsWith("nsec")) { console.error("BOT NSEC MISSING"); process.exit(1); } const sk = nip19.decode(nsec).data; if (!sk) { console.error("BOT NSEC BAD."); process.exit(1); } const pk = getPublicKey(sk); const profileEvent = finalizeEventWithPoW( { kind: 0, content: BOT, created_at: Math.floor(Date.now() / 1000), tags: [], }, sk ); const isGood = verifyEvent(profileEvent); if (isGood) { (async () => { const relay = await Relay.connect(RELAY); await relay.publish(profileEvent); console.log("IT IS ALIVE!!"); relay.close(); })(); } const run = () => { const today = new Date(); const dayOfWeek = today.getUTCDay(); const message = `${dayOfWeek % 6 === 0 ? "gfy" : "GM"} fiatjaf`; const event = finalizeEventWithPoW( { kind: 1, content: message, created_at: Math.floor(Date.now() / 1000), tags: [], }, sk ); const isGood = verifyEvent(event); if (isGood) { (async () => { console.log("BOT IS CONNECTING.."); const relay = await Relay.connect(RELAY); console.log("BOT CONNECTED"); await relay.publish(event); console.log(`[${today.toISOString()}] ${message}`, event); relay.close(); })(); } }; console.log("BOT IS BOTTING as", nip19.npubEncode(pk)); intervalId = setInterval(run, TWO_DAYS); } catch (error) { console.error(`[${new Date().toISOString()}]`, "RIP BOT", error); clearInterval(intervalId); process.exit(1); } function finalizeEventWithPoW(event, sk, difficulty = 0) { if (difficulty === 0) return finalizeEvent(event, sk); const pk = getPublicKey(sk); let nonce = 0; let leadingZeroes = 0; let event = { ...event, pubkey: pk }; while (true) { event.tags = [["nonce", nonce.toString(), difficulty.toString()]]; event.created_at = Math.floor(Date.now() / 1000); const hash = getEventHash(event); leadingZeroes = countLeadingZeroes(hash); if (leadingZeroes >= difficulty) { return finalizeEvent(event, sk); } nonce++; } } // hex should be a hexadecimal string (with no 0x prefix) function countLeadingZeroes(hex) { let count = 0; for (let i = 0; i < hex.length; i++) { const nibble = parseInt(hex[i], 16); if (nibble === 0) { count += 4; } else { count += Math.clz32(nibble) - 28; break; } } return count; }