Anti Hunter — Staking & Token Distribution Service Spec (Base)

Version 0.9 • Draft for implementation • Date: 2026-02-13 • Network: Base Mainnet

Purpose

Design a production-grade staking and token distribution system for $ANTIHUNTER on Base that enforces current tokenomics: fixed lock terms (30/60/90/120d), weighted rewards, 25% early-exit penalty to rewards pool, optional rollover boost, and transparent accounting.

1) Goals, Constraints, and Product Principles

Goals

Non-goals (v1)

2) Onchain Architecture (Recommended)

  1. AntiHunterStakingV1 — lock positions, claim, early exit, rollover.
  2. RewardsVaultV1 — reward inventory + cumulative reward-per-weight accounting.
  3. FeeRouterV1 — routes protocol fees + penalties into rewards vault.
  4. BuybackExecutorV1 (optional v1.1) — deterministic PnL→buyback logic.

Contract trust model

3) Position Model (Per-Deposit)

Each stake creates an independent position record (optionally mapped to NFT token IDs later).

struct Position {
  address owner;
  uint256 principal;           // amount staked
  uint64  lockStart;
  uint32  lockDurationDays;    // 30/60/90/120
  uint32  baseWeightBps;       // 10000/14000/19000/25000
  uint32  rolloverBoostBps;    // +2000 max, capped by total 30000
  uint64  unlockAt;
  uint256 rewardDebt;          // standard accRewardPerWeight debt model
  bool    closed;
}

4) Tokenomics Rules (Encoded)

Lock TermWeightNotes
30 days1.0x (10,000 bps)Base weight
60 days1.4x (14,000 bps)Mid-term preference
90 days1.9x (19,000 bps)Strong conviction
120 days2.5x (25,000 bps)Max base weight

5) Reward Accounting Design

Use standard cumulative accounting to avoid O(n) loops:

accRewardPerWeight (scaled 1e18)
positionPending = (positionEffectiveWeight * accRewardPerWeight / 1e18) - rewardDebt

6) Core Function Surface (v1)

// staking
stake(uint256 amount, uint32 lockDurationDays)
rollover(uint256 positionId, uint32 newLockDurationDays)
claim(uint256 positionId)
claimAll(uint256[] positionIds)
exitEarly(uint256 positionId)          // principal - 25% penalty
withdrawMatured(uint256 positionId)

// views
pendingRewards(uint256 positionId) view returns (uint256)
positionInfo(uint256 positionId) view returns (Position)
totalEffectiveWeight() view returns (uint256)

// vault/admin
notifyReward(uint256 amount)
routePenalty(uint256 amount)
pause() / unpause()

7) Event Schema (Must-Have for Indexing)

event Staked(address indexed user, uint256 indexed positionId, uint256 amount, uint32 lockDays, uint32 weightBps);
event Rollover(address indexed user, uint256 indexed oldPositionId, uint256 indexed newPositionId, uint32 lockDays, uint32 boostBps);
event Claimed(address indexed user, uint256 indexed positionId, uint256 amount);
event EarlyExit(address indexed user, uint256 indexed positionId, uint256 principalReturned, uint256 penaltyRouted);
event MatureWithdraw(address indexed user, uint256 indexed positionId, uint256 principal);
event RewardNotified(uint256 amount, uint256 newAccRewardPerWeight);
event PenaltyRouted(uint256 amount);
event Paused(address by);
event Unpaused(address by);

8) Security Controls & Invariants

Controls

Invariants (for property tests)

9) Offchain System (Do Not Overbuild)

10) API + Frontend Requirements

Read API

UI copy guardrails

11) Launch Plan

Phase 0 — Spec freeze (2–4 days)

Phase 1 — Build + test (1–2 weeks)

Phase 2 — Security hardening (1–2 weeks)

Phase 3 — Mainnet guarded launch

12) Open Decisions (Need Product Call)

  1. Single reward token forever vs future multi-reward extension?
  2. Should matured positions auto-roll by default (opt-in) or always manual?
  3. Upgradeability preference: immutable core vs timelocked upgrades?
  4. Do we expose position NFTs publicly in v1 or keep internal IDs?

13) Recommended Default Decisions

14) Implementation Checklist

Prepared for Anti Hunter / Anti Fund product + engineering planning.