| Language | Solidity 0.8.26, via-ir, optimizer at 44,444,444 runs to match v4-core |
|---|
| Dependencies | Uniswap v4-core and v4-periphery, OpenZeppelin Contracts v5.4.0, solmate |
|---|
| Tests | 26 Foundry tests, including a full rehearsal of the deploy path |
|---|
| Audit | None |
|---|
FlowToken
OpenZeppelin ERC20 plus two metadata strings. No mint, no owner, no pause, no transfer hook, no blocklist. Deployed fresh for every launch.
| constructor(name, symbol, supply, mintTo, image, bio) | Mints the entire supply to mintTo, which is always the launchpad. |
|---|
| launchpad() → address | Immutable. Provenance only, it confers no rights. |
|---|
| image() → string | Creator supplied. Usually a data: URI written at launch, so the coin renders with no external host. |
|---|
| bio() → string | Creator supplied, up to 280 characters through the UI. |
|---|
| banner(), website(), x(), telegram(), discord() | The rest of the metadata, all optional, all set once at construction. |
|---|
| meta() → Meta | All seven strings in one call, which is what the front end reads. |
|---|
FlowHook
One singleton hook serving every Etherflow pool, deployed at a CREATE2 address whose low 14 bits encode its permissions: beforeInitialize, beforeSwap, afterSwap, and the return-delta flag for each swap hook.
| MAX_FEE_BPS = 200 | 2%, the hard ceiling on any pool's fee. Checked at registration, no way around it. |
|---|
| BPS = 10000 | Denominator. |
|---|
| poolManager | Immutable. The v4 PoolManager this hook is bound to. |
|---|
| launchpad | Settable once, by admin, right after deployment. The only address allowed to register pools. |
|---|
| treasury | Receives the platform share. Movable by admin, which never affects balances already credited. |
|---|
| admin | May set the launchpad once, move the treasury, and hand the role on. Nothing else. |
|---|
| earned(address) → uint256 | Claimable ETH per address. |
|---|
| feesByPool(PoolId) → uint256 | Lifetime fee taken by one pool. |
|---|
| feesTotal() → uint256 | Lifetime fee across every pool. |
|---|
| register(key, beneficiary, feeBps, shareBps) | Launchpad only. Writes a pool's terms. Reverts if that pool is already registered, so terms are written exactly once. |
|---|
| configOf(PoolId) → PoolConfig | The beneficiary, fee and split for a pool. |
|---|
| claim(address to) → uint256 | Sends the caller's whole balance to to. Reverts if the balance is zero or the transfer fails. |
|---|
| beforeInitialize(...) | Pool manager only. Reverts unless the pool was registered first. |
|---|
| beforeSwap(...) | Pool manager only. Charges the ETH leg when ETH is the named currency. |
|---|
| afterSwap(...) | Pool manager only. Charges the ETH leg when it is not. |
|---|
| setLaunchpad / setTreasury / setAdmin | Admin only. Cannot touch pools, terms, or balances. |
|---|
event PoolRegistered(PoolId indexed id, address indexed beneficiary,
uint16 feeBps, uint16 beneficiaryShareBps);
event FeeTaken(PoolId indexed id, address indexed beneficiary,
uint256 toBeneficiary, uint256 toTreasury);
event Claimed(address indexed account, address indexed to, uint256 amount);
Etherflow
The launchpad. Holds every launch position and the registry.
| POOL_FEE = 10000 | 1% LP fee on every Etherflow pool. |
|---|
| TICK_SPACING = 200 | Tick spacing on every Etherflow pool. |
|---|
| MIN_LIQUIDITY = 0.005 ether | Floor on the ETH seeded at launch. |
|---|
| BURN = 0x…dEaD | Where rounding dust goes. |
|---|
struct LaunchParams {
string name; // 1 to 64 characters
string symbol; // 1 to 16 characters
uint256 supply; // in wei, 18 decimals
address beneficiary; // receives the fee share
uint16 feeBps; // 1 to 200
uint16 beneficiaryShareBps; // 0 to 10000
string image;
string bio;
}
function launch(LaunchParams calldata p)
external payable
returns (address token, PoolId poolId);
// msg.value = launchFee + liquidity, and liquidity >= MIN_LIQUIDITY
| tokensCount() → uint256 | How many coins have launched. |
|---|
| recent(offset, limit) → address[] | Newest first, so page zero is the front page. |
|---|
| launchOf(address) → Launch | Creator, beneficiary, timestamp, fee terms, seeded ETH, supply, pool id. |
|---|
| tokensOf(address) → address[] | Everything one creator has launched. |
|---|
| allTokens(uint256) → address | Raw registry access, oldest first. |
|---|
| setLaunchFee(uint256) | Changes the flat fee for future launches. Cannot touch a launch that already happened. |
|---|
| setTreasury(address) | Where future launch fees go. |
|---|
| setAdmin(address) | Hands the role on. |
|---|
What is not there
No function that decreases liquidity. No function that transfers a position. No function that changes a pool's fee, split or beneficiary. No pause. No upgrade path or proxy. Search the file yourself.
Deploying your own
The repository is a Foundry project. ./install.sh pins every dependency to the commit this was built against, then forge test runs the suite. script/Preflight.s.sol checks the target chain read-only before you spend anything, and script/Deploy.s.sol mines the hook salt, ships a CREATE2 deployer if the chain lacks the canonical one, deploys both contracts and wires them.
terminal
cd contracts
./install.sh
forge test
cp .env.example .env # POOL_MANAGER, ADMIN, TREASURY
forge script script/Preflight.s.sol --rpc-url robinhood
forge script script/Deploy.s.sol --rpc-url robinhood --broadcast --verify
Full source on GitHub.