Documentation
Back to Website

TokenFlow Documentation

TokenFlow (FLOW) is an ERC20 on Robinhood Chain with a single on-chain treasury. 100% of the supply is seeded into one Uniswap V4 pool at launch — no presale, no team allocation, no vesting. Pool fees fund the treasury, which buys a team-curated basket of stock tokens and memecoins in a perfectly balanced 1:1 proportion and streams every token it buys to FLOW stakers.

The whole protocol in one sentence. Trades pay a 5% pool fee → 80% of what is harvested accrues to the treasury, 20% to the team → once the treasury holds ≥ 0.5 ETH, anyone can trigger a buy that splits the ETH equally across every basket token → each token bought streams to stakers over 7 days, pro rata to stake × lock multiplier.

At a glance

TokenFLOW — ERC20, 1,000,000,000 fixed supply, no mint after construction
ChainRobinhood Chain (chainId 4663), an Ethereum L2
PoolUniswap V4, FLOW / native ETH, 5% fee
Fee split80% → treasury, 20% → team wallet (4% / 1% of each trade)
Buy triggerTreasury ≥ 0.5 ETH (configurable 0.1–10)
Buy allocationSplit equally 1:1 across every basket token, one leg each
RewardsStreamed to stakers over 7 days per buy; claimed, never airdropped
Lock tiers1.00x flexible · 1.25x 30d · 1.60x 90d · 2.10x 180d · 2.50x 365d
BasketTeam-curated, capped at 10 tokens
Admin surfaceStaking has no owner. Treasury owner has bounded setters — no withdraw / pause / upgrade / mint

How it works

Fee flow

Every FLOW swap on the Uniswap V4 pool pays a 5% pool fee. Those fees accumulate inside the pool position as the protocol's reward for providing the LP. A dedicated contract holds the LP NFT and exposes a single function — harvest() — that anyone can call at any time.

When harvest() fires, it collects accrued fees (and only fees — the principal liquidity is unreachable by anyone, including the team), swaps the FLOW portion to ETH, and routes the result:

Measured against the trade itself, that is 4% to stakers and 1% to the team. The LP NFT is permanently owned by the harvester contract, which can only decrease liquidity by zero — fees come out, principal never does. There is no transferNFT, no permit, no path that ever extracts the liquidity itself.

Reward buys

The treasury holds ETH. Once its balance crosses the buy threshold (0.5 ETH by default), anyone can call triggerBuy() in a single transaction. The contract spends min(balance, 2 × threshold) and splits that ETH equally across every token in the basket — one swap leg per token, each with its own minimum-output check. Routes go over Uniswap V2, V3 or V4, bridged through USDG or WETH where no direct pair exists.

Why an equal split? Allocation is not a decision anyone gets to make. The team curates which tokens are in the basket; the contract fixes how much each one receives at exactly one equal share. There is no cursor to game, no ordering to front-run, and no way to quietly favour one token over another.

Per-buy spend cap

A single triggerBuy() spends at most 2× the buy threshold in ETH, even if the treasury holds more. No single call can drain the treasury.

The treasury never holds the basket

Each leg's output is forwarded to the staking contract in the same transaction. The treasury is a conduit for ETH, not a fund that accumulates tokens: it has no sell logic, no profit-taking, and no way to hold a bought token back from stakers.

Streaming

Every amount handed to the staking contract begins a 7-day stream for that token. Stakers accrue continuously, pro rata to their weight — the staked amount multiplied by the position's lock multiplier — against the total weight of all positions.

If a second buy of the same token lands while a stream is still running, the remainder is folded in and the 7-day window restarts. Streams pause whenever nothing is staked, so rewards are never stranded or paid to nobody.

FLOW is never a reward token. Staked principal and streamed rewards are entirely separate balances. The protocol pays stakers in basket tokens only, so a reward stream can never dilute or touch the FLOW anyone has staked.

Staking

Lock tiers

Staking is the only way to earn from the protocol. Five tiers are available, fixed as contract constants — the multiplier is set when the position opens and determines its share of every subsequent reward buy.

TierLockMultiplier
FlexibleNone1.00x
30 days30 days1.25x
90 days90 days1.60x
180 days180 days2.10x
365 days365 days2.50x

The curve plateaus deliberately: doubling the lock from 180 to 365 days adds far less than the first commitment did. A position's weight is amount × multiplier, and your share of any stream is your weight over the total weight staked.

Claiming & withdrawing

Rewards are claimed, never airdropped. A position's rewards and its principal both unlock at lockEnd; claim and withdraw revert before that point. There is no early exit — no penalty path, no fee to buy your way out.

Once a lock expires the position does not stop earning: it drops back to the Flexible 1.00x multiplier and keeps accruing until withdrawn. The drop is applied by claim, withdraw, or kick — a public function anyone can call, which the protocol's cron calls automatically so an expired position never keeps a multiplier it is no longer entitled to.

Parameters

Immutable constants

Set in the contracts and never changeable. Modifying any of these requires a new deployment.

ParameterValue
FLOW total supply1,000,000,000 FLOW
Pool fee5% (50,000 in V4 fee units)
Treasury share of fees80%
Team share of fees20%
Reward stream duration7 days per buy
Lock tier multipliers1.00x / 1.25x / 1.60x / 2.10x / 2.50x
Max basket tokens10
Max reward tokens over contract life50
Max ETH per buy2 × buy threshold

Configurable bounds

The buy threshold can be tuned by the treasury owner — but only within a hard-coded range that is itself immutable. The setter reverts on any value outside these limits.

ParameterDefaultMinMax
Buy threshold (ETH)0.50.110

Widening the range — for instance, allowing a 20-ETH buy threshold — would require a v2 deployment, since the bounds themselves are coded as immutable constants and cannot be changed by any function. The staking contract has no configurable parameters at all: the tiers, multipliers and stream duration are constants.

Reward tokens

How tokens get added

The basket is curated entirely by the team. The community surfaces candidates through an off-chain leaderboard, but no chain action ever happens automatically.

  1. Community proposes. Anyone signed in with X can propose any ERC20 address and vote on existing proposals. The leaderboard is public.
  2. Team audits. Before adding anything on-chain, the team runs an audit pass on the candidate — checking honeypot and transfer-tax signals, and the depth of its pools across Uniswap V2/V3/V4 so a buy leg can execute without excessive price impact.
  3. Owner adds. If the audit passes, the owner calls addEligibleToken(address, kind, pool) directly. There is no on-chain proposal contract, no proposal bond, and no automatic promotion from the leaderboard.

Add / remove behavior

Adding a token appends it to the basket. From the next buy onward, the ETH is split across the larger set — every token, including the new one, still receives exactly one equal share.

Removing a token stops future buys of it. What it cannot do is strand rewards: any amount already streaming continues to stream to the end of its 7-day window, and anything stakers have accrued stays claimable indefinitely. Removal takes a token out of future allocation; it never claws back what stakers have already earned.

The team can stop the protocol from buying a token, but they cannot take back what stakers have already been paid.

The 10-token cap

The basket is hard-capped at 10 entries. addEligibleToken reverts when the basket is full and when the token is already present. The cap keeps a single triggerBuy() bounded — every buy performs one swap leg per basket token, so the cap is what keeps that transaction affordable and its gas predictable. Separately, the staking contract will track at most 50 distinct reward tokens over its lifetime.

Community leaderboard

X sign-in

The leaderboard is an off-chain product hosted alongside the dApp. Authentication is via X (Twitter) OAuth — sign in with X and you can propose tokens and vote. The protocol stores only the X handle, name, avatar, and a session cookie; nothing else is collected.

The leaderboard is purely advisory. It does not move funds. It does not auto-promote any token on-chain. It is a public signal that the team uses when curating the basket — nothing more.

Propose & vote rules

Security

Guarantees

These properties hold by code, not by promise. They form the audit checklist for the contracts.

  1. Staking has no admin. The staking contract has no owner, no roles, and no privileged functions whatsoever. Nobody can pause it, upgrade it, change a multiplier, or move a staker's principal.
  2. Narrow treasury admin. The owner can tune the buy threshold inside [0.1, 10] ETH and add or remove basket tokens. There is no pause, no withdraw, no upgrade, no mint, no admin escape.
  3. LP non-extractable. The contract that owns the Uniswap V4 LP position can only ever collect fees on it. There is no path that withdraws principal liquidity.
  4. No mint. The full supply is minted once at construction. TokenFlow exposes no mint function to anyone.
  5. Per-leg slippage bounds. Every swap leg carries its own minimum-output check and reverts if the route cannot fill it.
  6. Equal allocation. The ETH split across basket tokens is computed by the contract, not supplied by the caller. No caller input influences how much any token receives.
  7. Bounded buys. A single triggerBuy() spends at most 2× the threshold and performs at most 10 legs.
  8. Pull-only team payout. The team's 20% is claimed, not pushed, so a reverting team wallet can never block a harvest.
  9. Rewards cannot be stranded. Streams pause when nothing is staked, and removing a token never stops an in-flight stream or blocks a pending claim.
  10. Principal is segregated. FLOW is never a reward token, so no reward accounting path can ever pay out staked principal.
  11. Reentrancy guards on staking entry and exit. ETH transfers are explicit, checked calls.
  12. No selfdestruct, no delegatecall to user-controlled addresses, no unvetted inline assembly.
  13. Immutable external addresses. Routers, the V4 PoolManager and the FLOW address are constructor params that can never be changed.

The v1 trade-off

v1 ships with the deployer as the sole owner of the treasury and fee harvester — not a multisig, not a timelock. This is an intentional trade-off, and it's bounded by the rest of the design. The staking contract is unowned, so nothing below touches staked funds or accrued rewards.

A compromised owner key can do exactly three things:

What a compromised key cannot do: withdraw treasury funds, mint FLOW, pause the protocol, upgrade any contract, extract the LP, touch staked principal, stop an in-flight reward stream, or block a staker's claim.

Ownership is transferable through the standard OpenZeppelin transferOwnership path. Moving to a multisig — and later to a timelock — requires no contract changes.

Reference

Contracts

All contracts are Solidity 0.8.35 with OpenZeppelin Contracts 5.x. Sources are verified on Blockscout at deploy.

ContractPurpose
TokenFlowThe FLOW ERC20. 1B supply minted in the constructor for LP seeding. No mint after construction.
LaunchpadV4One-shot launch helper. Initializes the V4 pool, mints the LP position, hands it to the fee harvester.
FeeHarvesterPermanent owner of the LP position. Only callable path is harvest() — collects fees, swaps to ETH, splits 80/20 to treasury and team.
TreasuryHolds ETH, maintains the basket, and executes reward buys. Forwards every token bought straight to staking.
StakingFLOW staking in five lock tiers. Streams reward tokens over 7 days, pro rata to weight. No owner, no admin surface.
SwapRouterStateless wrapper around Uniswap's Universal Router, with per-leg minimum-output checks.
V4DirectDirect Uniswap V4 swap path used where a V4 pool is the best route.

External addresses

Robinhood Chain dependencies, pinned in the contracts at deploy time.

NameAddress
Uniswap V4 PoolManager0x8366a39CC670B4001A1121B8F6A443A643e40951
Uniswap V4 PositionManager0x58daec3116aae6D93017bAAea7749052E8a04fA7
Uniswap Universal Router0x06AfBA43Fd06227fA663b0DAecF536f6EaA6bf99
Uniswap V2 Factory0x8bcEaA40B9AcdfAedF85AdF4FF01F5Ad6517937f
Uniswap V3 Factory0x1f7d7550B1b028f7571E69A784071F0205FD2EfA
Permit20x000000000022D473030F116dDEE9F6B43aC78BA3
USDG (routing stable)0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168
FLOWPublished at launch
TreasuryPublished at launch
StakingPublished at launch

Glossary

For questions: X (Twitter)