Documentation
Back to Website

TokenFlow Documentation

TokenFlow (TFLO) is an Ethereum-mainnet ERC20 with a single on-chain community 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 rotates through a team-curated basket via a deterministic round-robin queue and burns TFLO on every profitable sale.

The whole protocol in one sentence. Trades pay a 4% pool fee → 80% accrues to the treasury, 20% to the team → once the treasury holds ≥ 0.5 ETH, anyone can trigger the next buy → tranches sell when their 30-minute TWAP gain clears 10% → all ETH from sales buys TFLO and burns it.

At a glance

TokenTFLO — ERC20 with burn, 1,000,000,000 total supply
ChainEthereum mainnet only (chainId 1)
PoolUniswap V4, TFLO / WETH, 4% fee
Fee split80% → treasury, 20% → team wallet
Buy triggerTreasury ≥ 0.5 ETH (configurable 0.1–10)
Sell triggerTranche 30-min TWAP gain ≥ 10% (configurable 2%–50%)
Sale proceeds100% buy & burn TFLO — supply only shrinks
Eligible listTeam-curated, capped at 50 tokens
Admin surface4 owner functions, hard-coded bounds, no withdraw / pause / upgrade / mint

How it works

Fee flow

Every TFLO swap on the Uniswap V4 pool pays a 4% 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 TFLO portion to ETH through the same TWAP-guarded router used everywhere else, and routes the result:

The LP NFT is permanently owned by the harvester contract. There is no transferNFT, no permit, no path that ever extracts the liquidity itself.

Round-robin buys

The treasury holds ETH and tracks a single integer — a public round-robin cursor — that determines the next eligible token to buy. The decision is mechanical: nextBuyIndex % eligibleTokens.length at the moment of the call. There is no oracle, no off-chain selection, no caller-supplied target.

Once the treasury balance crosses the buy threshold (0.5 ETH by default), anyone can call triggerBuy() in a single transaction. The contract picks the cursor's current target, swaps ETH for that token through a Uniswap router with a TWAP-bounded slippage check, records a tranche for what was bought, and advances the cursor by exactly one.

Why a fixed order? A public, deterministic queue gives every eligible token equal treatment, leaves no room for the team to favour or punish any token, and removes the usual front-running games — because the next buy is already common knowledge.

Cursor walk-through

Eligible list [A, B, C, D], cursor starting at 0:

CallIndex usedToken boughtCursor after
#10A1
#21B2
#32C3
#43D4
#54 % 4 = 0A again5

Each full rotation buys every eligible token exactly once. Allocation across the basket converges to equality.

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, and MEV exposure is bounded by both the cap and the 150 bps TWAP guard on the swap itself.

Tranches & sells

Each successful buy is recorded as an immutable tranche: the token bought, the amount received, the ETH spent, the timestamp, and a sold flag. Tranches are append-only — they're never compacted, reordered, or deleted.

A tranche becomes sellable once its 30-minute TWAP price clears the sell-gain threshold (10% over basis by default). Anyone can call executeSell(token, trancheIndex) on any tranche that's eligible. There is no FIFO ordering — older tranches don't have to sell first, and the caller picks which tranche to act on. Each tranche can be sold at most once; the contract flips sold = true before any external interaction.

Sells don't touch the buy cursor. The next triggerBuy() proceeds against whatever the cursor points at, independent of what just sold.

Buyback & burn

Every ETH proceed from a sell is hard-wired to a single destination: a dedicated buyback contract that swaps ETH for TFLO through the V4 pool (with the same TWAP guard) and calls burn() on the received TFLO.

Supply only ever shrinks. There is no path — owner or otherwise — that routes sell proceeds anywhere except to buy and burn TFLO. The treasury cannot be withdrawn, and the buyback cannot be bypassed.

Parameters

Immutable constants

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

ParameterValue
TFLO total supply1,000,000,000 TFLO
Pool fee4% (40,000 in V4 fee units)
Treasury share of fees80%
Team share of fees20%
TWAP window30 minutes (1,800 seconds)
Max price impact vs TWAP per swap150 bps (1.5%)
Max eligible tokens50
Max ETH per buy2 × buy threshold

Configurable bounds

Two parameters can be tuned by the owner — but only within hard-coded ranges that are themselves immutable. The setters revert on any value outside these limits.

ParameterDefaultMinMax
Buy threshold (ETH)0.50.110
Sell gain (% over basis)10%2%50%

Widening either 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.

Eligible tokens

How tokens get added

The eligible list 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/transfer-tax signals, deepest pool across Uniswap V2/V3/V4, and minimum TVL so a buy stays inside the 150 bps TWAP guard.
  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 simply appends it to the eligible array; the buy cursor doesn't move. The new token is first reached when the cursor naturally rotates past its slot — meaning a freshly added token gets its first buy on its turn, not immediately.

Removing a token disables future buys of it. The token is taken out of the eligible array, but the contract intentionally never clears the data needed to unwind existing holdings: the pool kind, the canonical pool address, and all existing tranches stay on-chain forever. Already-bought tranches of a removed token remain sellable indefinitely, against the same TWAP gain threshold, with proceeds still routing to buyback & burn.

The team can stop the protocol from buying a token, but they cannot trap funds inside one.

The 50-token cap

The eligible list is hard-capped at 50 entries. addEligibleToken reverts when the array is full and when the token is already present. The cap exists to keep removal lookups bounded and to keep view-function enumeration cheap; it is set as an immutable constant.

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 eligible list — nothing more.

Propose & vote rules

Security

Guarantees

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

  1. Narrow admin surface. The owner has exactly four state-changing functions on the treasury: tune the buy threshold (inside [0.1, 10] ETH), tune the sell gain (inside [2%, 50%]), add an eligible token, remove an eligible token. There is no pause, no withdraw, no upgrade, no mint, no admin escape.
  2. LP non-extractable. The contract that owns the Uniswap V4 LP position exposes only harvest(). There is no path that withdraws principal liquidity — only fees on top of it.
  3. TWAP enforcement on every swap. Every router call computes minimum output from the 30-minute TWAP, passes it to Uniswap, and re-checks the executed price after the swap. Anything outside ±150 bps of TWAP reverts.
  4. TWAP freshness. Swaps and sells revert if the 30-minute window can't be observed (insufficient V3/V4 history, or an idle V2 pair).
  5. Deterministic round-robin. The next buy target is fixed by an integer cursor read at the moment of the call. No caller input influences which token is bought, and the per-buy ETH cap (2× the trigger) bounds the worst-case MEV exposure.
  6. Eligible-token cap. Hard limit of 50 tokens in the eligible array, enforced on every add.
  7. Reentrancy guards on buy and sell. ETH transfers are explicit, checked calls.
  8. No double-sell. Each tranche flips to sold = true before the buyback runs. A tranche can be sold at most once.
  9. Removed-token sells remain possible. Removing a token never clears the per-token state that executeSell reads. Historical holdings can always be unwound.
  10. No external price oracles. Uniswap TWAP is the only price source for trade-decision logic. No Chainlink, no off-chain feeds.
  11. No selfdestruct, no delegatecall to user-controlled addresses, no unvetted inline assembly.
  12. Immutable external addresses. Uniswap routers, V4 PoolManager, and WETH are constructor params that can never be changed.
  13. Bounded work per buy. triggerBuy() is O(1) in the eligible-list length. No loop over the basket, no scan of tranches.
  14. Buyback non-bypassable. All ETH proceeds from sells go directly to buyback & burn. No withdraw, including to the owner.

The v1 trade-off

v1 ships with the deployer as the sole owner — not a multisig, not a timelock. This is an intentional trade-off, and it's bounded by the rest of the design.

A compromised owner key can do exactly four things:

What a compromised key cannot do: withdraw treasury funds, mint TFLO, pause the protocol, upgrade any contract, extract the LP, bypass the buyback, or sell a tranche outside the TWAP gain rule.

Ownership is transferable through the standard OpenZeppelin transferOwnership path. Moving to a multisig — and later to a timelock — requires no contract changes. The blast radius of a key compromise is bounded enough that operating with a single key while the protocol is small is an acceptable trade for being able to iterate on the eligible list.

Reference

Contracts

All contracts are Solidity 0.8.28 with OpenZeppelin Contracts 5.x. Sources are verified on Etherscan at deploy.

ContractPurpose
TokenFlowThe TFLO ERC20. Burnable. 1B supply minted in the constructor for LP seeding. No mint after construction.
LaunchpadV4One-shot launch helper. Initializes the V4 pool, mints the full-range LP NFT, hands the NFT to the fee harvester.
FeeHarvesterPermanent owner of the LP NFT. Only callable path is harvest() — collects fees, swaps to ETH, splits 80/20 to treasury and team.
TreasuryHolds ETH and tracks holdings as tranches. Maintains the eligible list and round-robin cursor. Hosts the four owner functions.
SwapRouterStateless wrapper around Uniswap's Universal Router with TWAP slippage checks before and after each swap.
PriceGuard30-minute TWAP abstraction across Uniswap V2 / V3 / V4. Reverts if the window can't be observed.
BasisLedgerLibrary. The tranche data structure and the gain-vs-basis math used by sells.
TFLOBuybackThe only destination for sell proceeds. Swaps ETH for TFLO and burns it.

External addresses

Mainnet dependencies, to be pinned in the contracts at deploy time.

NameAddress
WETH90xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Uniswap V4 PoolManagerPinned at deploy
Uniswap V4 PositionManagerPinned at deploy
Uniswap Universal Router (v2.5)0x66a9893cC07D91D95644AEDD05D03f95e1dBA8Af
Uniswap V2 Factory0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f
Uniswap V3 Factory0x1F98431c8aD98523631AE4a59f267346ea31F984
TFLOPublished at launch
TreasuryPublished at launch

Glossary

For questions: Telegram · X (Twitter)