from feed to feed.
A technical specification for turning the six loudest voices on crypto Twitter into an on-chain, verifiable feed of PnL cards — funded by trading fees on $KF.
Contents
§01 · Thesis
Thesis & design goals
Crypto Twitter runs on unverifiable claims. Screenshots of wins. Deleted losses. Sub-tweets. The market pays attention anyway, because the alternative — reading raw wallet activity — is too slow to trade on.
thekol.farm proposes a different primitive: a permissioned index of six wallets (nominative fair-use, publicly linked) whose realized PnL is snapshotted every 60 seconds and minted as on-chain NFTs. The card exists whether the KOL wanted it or not. The feed becomes the feed.
Four design goals govern every choice in this document:
- Verifiability — every card must be reconstructible from public Solana state.
- Idempotency — the pipeline can crash mid-tick and resume without minting duplicates.
- No custody of KOL funds — the protocol only reads wallets, never signs on their behalf.
- Fee alignment — mint costs are covered by $KF trading fees, never external subsidy.
§02 · Architecture
System architecture
Six services, one queue, one treasury. Every arrow in the diagram is a Solana RPC call, a Redis push, or a signed transaction. No off-chain magic.
The system is deliberately boring: Python workers, PostgreSQL for state, Redis for the tick queue, a single hot wallet for mint signing, and a cold multisig for the treasury. All of it is horizontally shardable per KOL if the tick rate ever needs to drop below 60s.
§03 · Ingestion
Ingestion — the Kolscan reader
The reader pulls the six tracked wallets (the "Six Head of the Stable") and hydrates each with the last 60 seconds of confirmed transactions. Wallet handles map to Solana pubkeys in a versioned registry; changing the registry is a governance event.
# kolscan.py — one tick, six wallets, ~40 RPC calls async def tick(kols: list[Wallet], rpc: HeliusClient) -> Tick: slot = await rpc.get_slot(commitment="confirmed") fills = [] for k in kols: sigs = await rpc.signatures_for(k.pubkey, until=k.cursor) for sig in sigs: tx = await rpc.parsed_tx(sig) fill = parse_swap(tx, k.pubkey) # Jupiter, Raydium, Pump AMM if fill: fills.append(fill) k.cursor = sigs[0].signature if sigs else k.cursor return Tick(slot=slot, fills=fills, ts=now_utc())
The parser understands Jupiter v6, Raydium AMM v4 & CLMM, pump.fun bonding-curve, and pump.fun AMM (graduated). Other routes are stored as "unknown swap" and excluded from PnL until a decoder ships. Fills carry `route`, `mint_in`, `mint_out`, `amount_in`, `amount_out`, `price_usd_at_slot`, and the source signature — enough for a third party to reproduce the number.
§04 · Accounting
Snapshotter — realized PnL per tick
For each KOL and each SPL mint they touch, the engine keeps a FIFO lot book. Buys open lots; sells close the oldest lots first and emit realized PnL in USD at the slot's swap-implied price. Unrealized PnL is computed for the dashboard but never minted — cards are always realized.
# pnl_engine.py — FIFO realization def realize(book: LotBook, fill: Fill) -> Decimal: if fill.side == "BUY": book.open_lot(fill.qty, fill.price_usd, fill.slot) return Decimal(0) # SELL — walk oldest lots until qty consumed remaining, pnl = fill.qty, Decimal(0) while remaining > 0 and book.lots: lot = book.lots[0] take = min(lot.qty, remaining) pnl += take * (fill.price_usd - lot.cost_basis) lot.qty -= take remaining -= take if lot.qty == 0: book.lots.popleft() return pnl.quantize(Decimal("0.01"))
Every 60s the engine emits a Snapshot: { kol_id, slot, pnl_24h, pnl_lifetime, win_rate, hold_median, volume_24h, mint_root }. The mint_root is a Merkle root over all fills that fed the snapshot — anyone can reconstruct the same number from raw chain data.
| Field | Type | Purpose |
|---|---|---|
| kol_id | u8 | Registry index (0–5) |
| slot | u64 | Solana slot at snapshot |
| pnl_24h | i64 (USDC-6) | Realized PnL, rolling 24h |
| win_rate | u16 (bps) | Closed positions in profit / total |
| hold_median | u32 (sec) | Median holding time, closed lots |
| volume_24h | u64 (USDC-6) | Sum of fill notionals, 24h |
| mint_root | [u8; 32] | Merkle root over source fills |
§05 · Mint
Card mint — Metaplex Core NFTs
A card is a Metaplex Core Asset. One asset per snapshot per KOL. Metaplex Core (not Token Metadata) is chosen for three reasons: single-account layout (lower rent), native plugins, and lower CU cost per mint (~40% cheaper than legacy pNFT flows in current benchmarks).
// mint_worker.ts — one card, one signature const asset = generateSigner(umi); await create(umi, { asset, name: `${kol.handle} · §${snap.slot}`, uri: arweaveUri, // JSON metadata + Merkle proof plugins: [ { type: 'Attributes', attributeList: [ { key: 'pnl_24h', value: snap.pnl_24h.toString() }, { key: 'win_rate_bps', value: snap.win_rate.toString() }, { key: 'volume_24h', value: snap.volume_24h.toString() }, { key: 'mint_root', value: bs58.encode(snap.mint_root) }, { key: 'slot', value: snap.slot.toString() }, ]}, { type: 'PermanentFreezeDelegate', frozen: false }, { type: 'Royalties', basisPoints: 250, creators: [treasury] }, ], }).sendAndConfirm(umi);
Metadata JSON on Arweave carries: the Merkle proof for each source fill, a rendered PNG of the card, the KOL registry entry, and a canonical link back to thekol.farm/card/<asset>. Rendering is deterministic — same snapshot input, same PNG bytes, verifiable by any client.
§06 · Treasury
Treasury guardrails
The treasury is a Squads v4 multisig holding fees swept from $KF trading. The mint hot wallet is a separate signer, funded only in just-in-time drips. If the hot wallet drains, mints halt; the pipeline never overdrafts.
- Mint precondition — hot balance ≥ (rent + priority fee + safety) for the tick.
- Cap — 60 cards total lifetime supply (10 per KOL). Once hit, minting is permanently disabled at the program level.
- Fee sweep — every 6 hours, PumpSwap fee accounts flush to treasury via a keeper.
- Emergency pause — a 2-of-3 signature can freeze mints for up to 72h; longer requires token-holder vote.
§07 · Dispatch
The Notice — dispatch layer
Every mint fires "The Notice": a fan-out to Twitter (image + card link), a push topic subscribers can opt into, and a WebSocket message on wss://thekol.farm/notice. The Notice is side-effectful but not authoritative — the card exists on chain whether or not the tweet lands.
# notice_bus.py — post once, retry with jitter async def notice(card: MintedCard): body = render_notice(card) await gather( twitter.post(body.text, media=body.png), # v2 API push.publish("notice", body.json), # APNs / FCM ws.broadcast("/notice", body.json), # dashboard return_exceptions=True, ) log_notice(card.asset, body.hash)
Rate limits: at most one Notice per KOL per 5 minutes. Batching kicks in during rip periods — instead of 6 back-to-back tweets, the bus consolidates into a single "§rip" post with all six cards.
§08 · Token
$KF tokenomics
$KF launches on pump.fun and graduates to PumpSwap. Trading fees route to the treasury multisig. There is no pre-mine, no allocation, no team unlock schedule — the token is fair-launched and the treasury only exists because the market feeds it.
The card index leg is optional: once all 60 cards mint, holders can vote to airdrop a $INDEX token 1:1 to $KF wallets, backed by the card collection held in treasury. This turns the cards into a tradeable basket rather than 60 disconnected NFTs. The vote is non-binding until quorum (>15% supply) is reached.
§09 · Verify
Verifiability & open data
Nothing on thekol.farm should require trust in this document. Every claim above resolves to a public artifact:
| Artifact | Where | How to verify |
|---|---|---|
| Token mint | vLbn…pump | Solana Explorer |
| KOL registry | /api/registry.json | Diff against Kolscan |
| Live ticks | /api/tick/latest | Replay from Helius signatures |
| Card assets | Metaplex Core, Arweave | Fetch → recompute Merkle root |
| Treasury balance | Squads v4 multisig | Solana Explorer |
| Source of numbers | Merkle-rooted per snapshot | Reproduce PnL from raw fills |
§10 · Forward
Roadmap & risks
Roadmap
- Phase 0 · Now — site, registry, whitepaper, $KF launched on pump.fun.
- Phase 1 · Ingestion — Kolscan reader live for the four linked wallets; unlinked KOLs remain "—" until pubkeys are attested.
- Phase 2 · Snapshotter — FIFO engine, Merkle roots, public /api/tick/latest replay endpoint.
- Phase 3 · Mint pipeline — Metaplex Core deploy, first card minted at token graduation.
- Phase 4 · The Notice — Twitter + push + WS fan-out enabled.
- Phase 5 · Index leg — holder vote on $INDEX airdrop after the 60th card.
Risks & mitigations
- KOL wallet spoofing — mitigated by requiring on-chain attestation (signed message) before a wallet enters the registry.
- Price-oracle attack on PnL — swap-implied prices are taken from the fill itself, not an external oracle; a KOL routing through a manipulated pool poisons only their own card.
- RPC availability — reader is multi-provider (Helius primary, Shyft fallback, Triton backup). A 3-provider quorum protects against silent forks.
- Hot wallet compromise — mint program checks a treasury-controlled PDA; a stolen hot key cannot mint past its just-in-time drip balance.
- Legal / nominative fair use — the six handles are used descriptively, not as endorsements. KOLs may request removal; a governance vote decides whether to honor the request or fork the registry.