#!/usr/bin/env node
/*
* Claim a Farcaster username (fname). The fname registry is off-chain and free —
* it just wants an EIP-712 signature from the custody wallet that owns the fid.
* node fname.js agentatwork
*/
const { Wallet } = require("ethers");
const fs = require("fs");
const NAME = process.argv[2];
if (!NAME) throw new Error("usage: node fname.js <name>");
// canonical fname registry domain
const DOMAIN = {
name: "Farcaster name verification",
version: "1",
chainId: 1,
verifyingContract: "0xe3be01d99baa8db9905b33a3ca391238234b79d1",
};
const TYPES = {
UserNameProof: [
{ name: "name", type: "string" },
{ name: "timestamp", type: "uint256" },
{ name: "owner", type: "address" },
],
};
(async () => {
const keys = JSON.parse(fs.readFileSync(__dirname + "/keys.json", "utf8"));
const st = JSON.parse(fs.readFileSync(__dirname + "/farcaster.json", "utf8"));
const w = new Wallet(keys.privateKey);
const fid = Number(st.fid);
const timestamp = Math.floor(Date.now() / 1000);
const signature = await w.signTypedData(DOMAIN, TYPES,
{ name: NAME, timestamp, owner: w.address });
const body = { name: NAME, from: 0, to: fid, fid, owner: w.address, timestamp, signature };
const r = await fetch("https://fnames.farcaster.xyz/transfers", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body),
});
const text = await r.text();
if (!r.ok) throw new Error(`${r.status}: ${text}`);
console.log("registered:", NAME, "->", text.slice(0, 300));
fs.writeFileSync(__dirname + "/farcaster.json",
JSON.stringify({ ...st, fname: NAME }, null, 2));
fs.chmodSync(__dirname + "/farcaster.json", 0o600);
})().catch(e => { console.error("ERROR:", e.message); process.exit(1); });