
Kakunin
Projects publish their team on ENSv2. Anyone checks in 1s if a recruiter is really a member.
Demo
About
Fake recruiters are how crypto teams get hacked: someone poses as a project member on Telegram, X or LinkedIn and gets a developer to run malware or sign a transaction. Takedown tools chase an endless list of fakes. Kakunin certifies the real ones instead: a short list each project publishes on ENSv2. Project side, self-serve. Any project can create its organisation at kakunin.xyz/create in about two and a half minutes (12 Sepolia transactions, gas sponsored on testnet): it picks an ENS name and the wallet that will own it. Kakunin registers <name>.eth to that wallet, not to Kakunin, deploys its org and team registries and resolvers, and gives a limited operator key just enough Enhanced Access Control roles to run the team. The owner signs in with a wallet signature (no gas) to add and revoke members; the operator can never touch the project's root name, and the owner can remove it on-chain at any time. Every member is a subname of team.<name>.eth, and the project's own ENS name is the attester. Member side. HR sends a one-time Telegram link (or QR). The member opens it from their own account, and their numeric Telegram ID (never the mutable @username) is attested on ENS. No wallet needed. Everyone else. Forward a suspicious message to the bot, use the web check, open the Telegram Mini App, or call the free public API. Answers: verified (with a proof anyone can re-check without trusting Kakunin), former member (revocation date read from ENSv2 events), lookalike (homoglyphs, typos) or unknown. Every failed check alerts the impersonated project. When HR revokes someone on-chain, every answer changes within seconds. Reporting. Anyone can report an account that impersonates a project, or an official member account that looks compromised (web check page, Mini App, bot /report and /compromised, API). A report only lands in the project's queue and alerts its admins on Telegram; nothing becomes public until an admin decides with a wallet signature. A confirmed impersonator is then answered as a reported impersonator by every check. For a compromised official account the admin's action writes org.status = compromised on the member's ENS name and revokes it, so every check answers "compromised account", recorded and dated on-chain. AI agents. The same check is sold per call over x402. The buying agent screens the destination with the live Intercepta API before it signs: a clean address is paid, a flagged one is refused, with the reason on record.
How it's made
- ENSv2 (Sepolia), central to the product. Org and team registries are UserRegistry proxies deployed through the VerifiableFactory (kakunin-demo.eth -> team.kakunin-demo.eth -> member). HR gets ROLE_REGISTRAR | ROLE_UNREGISTER | ROLE_RENEW on the team registry root and ROLE_SET_TEXT on a separate team PermissionedResolver only; the dashboard reads the role bitmaps live to prove what HR cannot do. All reads go through UniversalResolverV2. An unregistered name leaves registry state, so "former member since..." is rebuilt from LabelRegistered / LabelUnregistered events and block timestamps. - Self-serve multi-org provisioning. A resumable 7-task state machine (packages/core/src/provision.ts) registers <name>.eth to the owner's wallet via commit-reveal, deploys org and team UserRegistry proxies and two PermissionedResolvers through the VerifiableFactory, and grants a least-privilege operator that drops its setup rights on the org root at the end. The browser advances it one bounded step at a time to fit serverless limits, and tx hashes are saved before waiting so retries never double-send. Operator keys are sealed with AES-256-GCM. Verified live on kakunin.xyz: an organisation created through the public API in 155 s, then 24 end-to-end checks including a real attestation written from signed Telegram initData. - Attestations. Implemented from the draft ENSIP "Text Record Attestations" (PR #85): DAG-CBOR payload, EIP-191 over keccak256, envelope Tag(0x61747374), stored as attestations[org.telegram.id][<org>.eth]. The verifier also accepts the deployed atst.me layout, and a test reproduces a real mainnet attestation byte for byte. Any change to the record, the owner or the attester key invalidates it. - Telegram. grammY bot running as a webhook, plus a Mini App whose server validates Telegram's signed initData (HMAC-SHA256, replay window) on every request, so the account opening the app is authenticated and a member card cannot be requested for someone else. The bot's native contact picker returns the real numeric ID even when forwards are hidden. - Lookalike detection. NFKC normalisation, a confusables map and Levenshtein distance against the org's own registry. - x402 + Intercepta. An @x402/next seller (the real endpoint and a fake clone whose payTo is a flagged address) and an @x402/fetch buyer with an onBeforePaymentCreation hook that calls the live Intercepta quick-scan API before signing. The policy refuses lookalike tokens, enforces spending limits, asks a human on medium risk and fails closed if screening errors. Payments run on Base Sepolia against real mainnet addresses. - Stack. TypeScript pnpm monorepo, viem, Next.js 15 on Vercel, Upstash Redis, public API v1 with OpenAPI 3.1, 100+ unit tests, an HTTP end-to-end test, a security review with live attack tests (docs/SECURITY.md), and a one-command production check (pnpm cloud:check). - Hacky bit worth mentioning: text records survive unregister while the name stops resolving through the Universal Resolver, so member history is reconstructed from registry events rather than state.