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
| Token | FLOW — ERC20, 1,000,000,000 fixed supply, no mint after construction |
| Chain | Robinhood Chain (chainId 4663), an Ethereum L2 |
| Pool | Uniswap V4, FLOW / native ETH, 5% fee |
| Fee split | 80% → treasury, 20% → team wallet (4% / 1% of each trade) |
| Buy trigger | Treasury ≥ 0.5 ETH (configurable 0.1–10) |
| Buy allocation | Split equally 1:1 across every basket token, one leg each |
| Rewards | Streamed to stakers over 7 days per buy; claimed, never airdropped |
| Lock tiers | 1.00x flexible · 1.25x 30d · 1.60x 90d · 2.10x 180d · 2.50x 365d |
| Basket | Team-curated, capped at 10 tokens |
| Admin surface | Staking 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:
- 80% → on-chain treasury, which buys reward tokens for stakers
- 20% → team wallet, paid pull-only so a reverting team wallet can never block a harvest
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.
| Tier | Lock | Multiplier |
|---|---|---|
| Flexible | None | 1.00x |
| 30 days | 30 days | 1.25x |
| 90 days | 90 days | 1.60x |
| 180 days | 180 days | 2.10x |
| 365 days | 365 days | 2.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.
| Parameter | Value |
|---|---|
| FLOW total supply | 1,000,000,000 FLOW |
| Pool fee | 5% (50,000 in V4 fee units) |
| Treasury share of fees | 80% |
| Team share of fees | 20% |
| Reward stream duration | 7 days per buy |
| Lock tier multipliers | 1.00x / 1.25x / 1.60x / 2.10x / 2.50x |
| Max basket tokens | 10 |
| Max reward tokens over contract life | 50 |
| Max ETH per buy | 2 × 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.
| Parameter | Default | Min | Max |
|---|---|---|---|
| Buy threshold (ETH) | 0.5 | 0.1 | 10 |
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.
- Community proposes. Anyone signed in with X can propose any ERC20 address and vote on existing proposals. The leaderboard is public.
- 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.
- 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
- Propose any ERC20 address. Idempotent — proposing an address that already exists is a no-op.
- Vote for any proposed token. One vote per X account per token; clicking again toggles it off. No proposal bond, no vote weight, no quadratic anything.
- Audit badge. Each proposal shows the team's audit status (passed / flagged / not yet audited) so voters know what's been reviewed.
Security
Guarantees
These properties hold by code, not by promise. They form the audit checklist for the contracts.
- 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.
- 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.
- 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.
- No mint. The full supply is minted once at construction.
TokenFlowexposes no mint function to anyone. - Per-leg slippage bounds. Every swap leg carries its own minimum-output check and reverts if the route cannot fill it.
- 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.
- Bounded buys. A single
triggerBuy()spends at most 2× the threshold and performs at most 10 legs. - Pull-only team payout. The team's 20% is claimed, not pushed, so a reverting team wallet can never block a harvest.
- 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.
- Principal is segregated. FLOW is never a reward token, so no reward accounting path can ever pay out staked principal.
- Reentrancy guards on staking entry and exit. ETH transfers are explicit, checked calls.
- No
selfdestruct, nodelegatecallto user-controlled addresses, no unvetted inline assembly. - 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:
- Move the buy threshold inside [0.1, 10] ETH
- Add a token to the basket (up to the cap of 10)
- Remove a token from the basket
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.
| Contract | Purpose |
|---|---|
| TokenFlow | The FLOW ERC20. 1B supply minted in the constructor for LP seeding. No mint after construction. |
| LaunchpadV4 | One-shot launch helper. Initializes the V4 pool, mints the LP position, hands it to the fee harvester. |
| FeeHarvester | Permanent owner of the LP position. Only callable path is harvest() — collects fees, swaps to ETH, splits 80/20 to treasury and team. |
| Treasury | Holds ETH, maintains the basket, and executes reward buys. Forwards every token bought straight to staking. |
| Staking | FLOW staking in five lock tiers. Streams reward tokens over 7 days, pro rata to weight. No owner, no admin surface. |
| SwapRouter | Stateless wrapper around Uniswap's Universal Router, with per-leg minimum-output checks. |
| V4Direct | Direct 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.
| Name | Address |
|---|---|
| Uniswap V4 PoolManager | 0x8366a39CC670B4001A1121B8F6A443A643e40951 |
| Uniswap V4 PositionManager | 0x58daec3116aae6D93017bAAea7749052E8a04fA7 |
| Uniswap Universal Router | 0x06AfBA43Fd06227fA663b0DAecF536f6EaA6bf99 |
| Uniswap V2 Factory | 0x8bcEaA40B9AcdfAedF85AdF4FF01F5Ad6517937f |
| Uniswap V3 Factory | 0x1f7d7550B1b028f7571E69A784071F0205FD2EfA |
| Permit2 | 0x000000000022D473030F116dDEE9F6B43aC78BA3 |
| USDG (routing stable) | 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168 |
| FLOW | Published at launch |
| Treasury | Published at launch |
| Staking | Published at launch |
Glossary
- FLOW — TokenFlow's ERC20 token. Robinhood Chain, 1B fixed supply.
- Treasury — The on-chain contract that holds ETH from pool fees and executes reward buys. It never keeps the tokens it buys.
- Basket — The team-curated list of tokens the treasury buys for stakers. Capped at 10. Called reward tokens in the app.
- Reward buy — One
triggerBuy(). Splits the treasury's ETH equally across every basket token and forwards the results to staking. - Stream — The 7-day window over which a bought token is paid out to stakers.
- Weight — A position's staked amount times its lock multiplier. Your share of a stream is your weight over total weight.
- Lock tier — One of five staking terms, from Flexible at 1.00x to 365 days at 2.50x. Fixed when the position opens.
- Claim — Taking accrued rewards. Available once the position's lock has ended; rewards are never airdropped.
- Kick — A public call that drops an expired position back to the 1.00x Flexible multiplier.
- Buy threshold — Treasury ETH balance required before
triggerBuy()can fire. Default 0.5, owner-tunable inside [0.1, 10]. - Community leaderboard — Off-chain X-OAuth UI for proposing and voting on tokens. Purely advisory; never moves funds.
For questions: X (Twitter)