Protocol specificationKing of the HillA Uniswap v4 hook protocol. One wallet at a time holds the throne. While enthroned, that wallet receives 2% in ETH from every swap of the KOTH/ETH pair. Any larger buy replaces them. This document describes the parameters and the lifecycle.
Token
KOTH is an ERC-20 with a fixed maximum supply of 1,000,000 tokens. The full supply is minted once at deploy. The contract has no live admin slot after deploy completes: the deploy script calls renounceAdmin() and zeroes the privileged address.
The token is paired with native ETH in a single Uniswap v4 pool. The pool LP fee is 0%; all fee logic lives in the hook attached to this pool.
Per-buy fees: 2% of the ETH input goes to the current king (or to treasury when the throne is vacant). 1% of the KOTH output is burned.
Per-sell fees: 1% of the KOTH input is burned. 2% of the ETH output goes to the current king. Round-trip (buy then immediate sell) costs approximately 6% of the input under negligible slippage.
Coronation
A buy crowns its sender if the gross ETH amount exceeds the dethrone threshold. The threshold is derived from the previous king's purchase amount (the record) with linear decay.
Threshold: decayedRecord × 1.03. A buyer must pay 3% above the decayed record to take the throne.
Decay: the record decays linearly to zero over 3,600 blocks (~12 h at 12 s per block) from the last coronation block. Once the record reaches zero, any non-zero buy crowns the buyer.
Attribution: when the buy is routed through the project router KOTHRouter, the buyer's address is read from the hook data. For any other route (Universal Router, 1inch, etc.) the hook falls back to tx.origin. Smart-contract wallets should use KOTHRouter to ensure the crown is recorded against the intended address.
On a successful coronation the previous king is dethroned (see Section IV), the new king's address replaces currentKing, the buy's gross ETH amount becomes the new record, and the decay clock resets to the current block.
The king's yield
While reigning, the king accrues 2% of every swap's ETH side into a per-address balance held by the hook. The balance is withdrawable at any time by calling claim(). There is no staking transaction, no claim window, and no schedule.
The yield settles atomically inside the swap that produced it. The king has no pending state to manage between trades.
DUMP (Section IV) — the sell still executes, but the throne becomes vacant in the same transaction.Dethrone reasons
Each dethrone emits a KingDethroned event with a reason tag. Three reasons exist.
Another wallet bought above the threshold. The previous king receives the 2% fee from this overthrowing buy before the crown change is applied, then loses the throne to the new king.
The reigning king sold KOTH. The sell executes, the king is dethroned at the same block, and the throne becomes vacant until the next coronation.
The dethroned king did not claim their accumulated ETH within the 12-hour reclaim window. A keeper can then call forfeit() and trigger the buyback path (Section V). FORFEIT is the tag on the secondary lifecycle event, not on the original dethrone.
At every dethrone the hook records a Reign struct with the king's address, start and end blocks, ETH earned, the record high, and the reason. The Reign struct is the data layer for the Soul and Scroll NFTs (Section VI).
Forfeit and buyback
A dethroned king has 12 hours (3,600 blocks) to call claim() and withdraw their coffer. After this window, any wallet may call forfeit(king). The coffer is then split:
3% is paid to the caller of forfeit() as a keeper bounty.
97% is used to buy KOTH from the pool inside the same transaction, and the bought KOTH is sent to burnFromHook() for permanent destruction.
The buyback uses poolManager.unlock() with an in-swap price limit of 50 bps on the square-root price (approximately 1% on the spot price). If the limit clamps the swap, the unused ETH is credited to treasury so the hook's internal accounting remains balanced.
For coffers below 0.001 ETH the entire amount goes to the keeper (the dust path). At that scale a buyback would round down to zero KOTH and produce no burn.
Chronicle NFTs
On each dethrone, two NFTs are minted to the deposed king. Both encode the same Reign data on chain; the SVG render and transferability differ.
Soulbound: transferFrom, approve, and setApprovalForAll all revert. The Soul is held by the original king permanently. Intended as the historical archive and a snapshot anchor for any future airdrop.
Tradeable: standard ERC-721 with ERC-2981 royalty (5% to treasury). Records the same Reign data plus an immutable originalMintee field — the address it was first minted to. The Scroll grants its current holder a buff in throne PvP (Section VII).
The Soul and Scroll for a given reign share a token id (the reign number) but live in separate ERC-721 contracts.
Scroll utility
When buying KOTH through KOTHRouter, the caller may attach up to three Scrolls they own. The hook validates each Scroll, sums the discount, and lowers the dethrone threshold for that specific purchase only.
Crown score (0..1.0): a Scroll's strength is the average of two normalized factors of its underlying reign.
durationScore = min(reignBlocks / 3600, 1.0) // cap at 12 h
buyScore = min(recordHigh / 1.5 ether, 1.0) // cap at 1.5 ETH
crownScore = (durationScore + buyScore) / 2Discount per Scroll: crownScore × 250 bps, between 0 and 2.5%.
Tier (display only): Squire [0, 0.2) · Knight [0.2, 0.4) · Baron [0.4, 0.6) · Duke [0.6, 0.8) · Sovereign [0.8, 1.0].
Stack rules: up to 3 Scrolls per buy. Sum of valid discounts is capped at 7.5%. If the total exceeds 3% the effective threshold drops below the current record; the new record then equals the actual buy amount, so records can decrease.
Anti-self-buff: if a Scroll's originalMintee equals the current holder, the Scroll is silently ignored. The buff only activates after the Scroll has changed hands.
Burn on use: Scrolls in a stack are burned only on a successful coronation. A failed attempt leaves them in the buyer's wallet.
Invalid Scrolls in the stack (not owned, already burned, duplicate id, self-buff) are silently skipped with a ScrollIgnored event. The buy itself never reverts because of Scroll logic.
Scroll marketplace
The protocol ships a minimal escrow marketplace for Scrolls. Payment is in KOTH only; ETH listings are not supported.
list(tokenId, priceKoth): the seller transfers the Scroll into the marketplace contract and sets a KOTH price.
cancel(tokenId): the original seller withdraws the Scroll at any time before it sells.
buy(tokenId): the caller pays the listed price in KOTH. The Scroll transfers to the caller. The KOTH splits in the same transaction:
toSeller = priceKoth × 90% → seller's wallet
toBurn = priceKoth × 5% → koth.burn()
toTreasury = priceKoth × 5% → treasury (also ERC-2981 royalty)The marketplace has no admin functions, no fee setters, and no upgrade path; behavior is fixed at deploy. The marketplace address is included in KOTHToken's anti-snipe exemption list at construction so listings above 1% of supply settle during the initial 175-block window.
Anti-snipe
For the first 175 blocks (~35 minutes) after token deployment, any non-exempt wallet is capped at 1% of total supply (10,000 KOTH). Transfers that would push a wallet above this limit revert with AntiSniperLimit.
The exemption set is fixed at construction: deployer wallet, Uniswap v4 PoolManager, Uniswap v4 PositionManager, the hook contract, and the marketplace. After 175 blocks the cap lifts permanently; no admin call is required.
Why Uniswap v4
The fee and crown logic above runs inside each swap, not on the token's transfer(). Three v4 primitives make this possible:
beforeSwap / afterSwap hooks observe every swap against the pair and adjust deltas atomically.
BEFORE_SWAP_RETURNS_DELTA and AFTER_SWAP_RETURNS_DELTA (encoded in the hook address bits 0xCC) let fees settle in the swap's own currency without a separate transfer.
poolManager.unlock(): the hook itself can open a buyback swap inside the same locked context, so the forfeit path never leaves the AMM boundary.
function beforeSwap(address, PoolKey calldata k, SwapParams calldata p, bytes calldata)
external returns (bytes4, BeforeSwapDelta, uint24)
{
uint256 amt = uint256(-p.amountSpecified);
uint256 fee;
if (p.zeroForOne) { // ETH -> KOTH
fee = amt * 200 / 10_000; // 2% to king
poolManager.take(k.currency0, address(this), fee);
kingBalances[currentKing] += fee;
} else { // KOTH -> ETH
fee = amt * 100 / 10_000; // 1% burned
poolManager.take(k.currency1, address(this), fee);
koth.burnFromHook(fee);
}
return (
IHooks.beforeSwap.selector,
toBeforeSwapDelta(int128(int256(fee)), 0),
0
);
}An equivalent protocol on Uniswap v2 or v3, on a Curve-style AMM, or on a wrapper token would require an external taxing mechanism at the token's transfer layer, which traders can route around. v4's hook surface keeps the logic at the pool boundary, where every swap is observable.
Constants
All numerical parameters are compiled into contract bytecode and cannot be changed after deploy. There is no governance mechanism.
Total supply: 1,000,000 KOTH · Anti-snipe window: 175 blocks · Anti-snipe wallet cap: 1% of supply
Pool LP fee: 0% · Tick spacing: 60 · Tick range: full (−887,220 … +887,220)
Threshold multiplier: 1.03× decayed record · Decay window: 3,600 blocks (~12 h) · King fee per swap: 2% of ETH side · Burn per swap: 1% of KOTH side
Reclaim window: 3,600 blocks (~12 h) · Keeper bounty: 3% · Burn portion: 97% · Buyback price-impact cap: 50 bps on sqrt price · Dust path threshold: 0.001 ETH (below which 100% goes to keeper)
Per-Scroll discount cap: 2.5% (250 bps) · Stack size limit: 3 · Stack discount cap: 7.5% (750 bps) · Duration cap for score: 3,600 blocks · Record-high cap for score: 1.5 ETH · Tier thresholds: 0.2 / 0.4 / 0.6 / 0.8 of crown score
Payment token: KOTH only · Split: 90% seller / 5% burn / 5% treasury · ERC-2981 royalty: 5% to treasury (matched by the marketplace's own split)
Out of scope
The protocol does not implement:
Token vesting, emissions, or staking rewards.
Multi-pair routing or wrapped variants of KOTH.
Governance, voting, parameter changes, or admin overrides. All admin slots are zeroed by the deploy script.
Off-chain components other than the public frontend at kothprotocol.xyz. The frontend reads on-chain state via public RPC and has no privileged access; it can be replaced or forked.
The Soul mapping is preserved on chain for potential future applications (airdrops, gated drops, leaderboards). This document does not commit to any specific use.