1
0
forked from enes/fiatjafbuzz
fiatjafbuzz/index.js

150 lines
3.4 KiB
JavaScript

import {
finalizeEvent,
verifyEvent,
getPublicKey,
nip19,
getEventHash,
} 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 <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 () => {
try {
const relay = await Relay.connect(RELAY);
await relay.publish(profileEvent);
console.log("IT IS ALIVE!!");
relay.close();
} catch (error) {
exit(error);
}
})();
}
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 () => {
try {
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();
} catch (error) {
exit(error);
}
})();
}
};
console.log("BOT IS BOTTING as", nip19.npubEncode(pk));
intervalId = setInterval(run, TWO_DAYS);
} catch (error) {
exit(error);
}
function exit(error) {
console.error(`[${new Date().toISOString()}]`, "RIP BOT", error);
clearInterval(intervalId);
process.exit(1);
}
function finalizeEventWithPoW(event, sk, difficulty = 0) {
if (!difficulty) return finalizeEvent(event, sk);
const pk = getPublicKey(sk);
let nonce = 0;
let leadingZeroes = 0;
let unsignedEvent = { ...event, pubkey: pk };
while (true) {
unsignedEvent.tags = [["nonce", nonce.toString(), difficulty.toString()]];
unsignedEvent.created_at = Math.floor(Date.now() / 1000);
const hash = getEventHash(unsignedEvent);
leadingZeroes = countLeadingZeroes(hash);
if (leadingZeroes >= difficulty) {
return finalizeEvent(unsignedEvent, 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;
}