etherflow.fun
mechanism7 min read

The launch transaction

Everything happens in one call to Etherflow.launch. Five steps, in order, and then the contract stops touching your coin forever.

  1. 1Deploy the tokenA FlowToken is constructed with your name, ticker, supply and metadata. The entire supply is minted to the launchpad, which is holding it only for the next few steps.
  2. 2Register the fee termsThe launchpad tells the hook the beneficiary, the fee in basis points and the split, keyed by the pool id. The hook rejects a second registration for the same pool, so these terms are written exactly once.
  3. 3Open the poolpoolManager.initialize is called with a price derived from your supply and your ETH. The hook's beforeInitialize runs here and reverts if the pool was not registered in step two, so no unregistered pool can exist with this hook attached.
  4. 4Mint the positionInside an unlock callback, the launchpad adds liquidity across the full tick range and settles both sides: native ETH by value, the coin by transfer. The position is keyed to the launchpad itself.
  5. 5Record and stopThe launch is written to the registry, the Launched event is emitted, dust is swept, and the launchpad never interacts with that pool again.

Why ETH is always currency0

Uniswap v4 sorts the two currencies of a pool numerically, and native ETH is address(0). A deployed contract address is always greater than zero, so in every Etherflow pool ETH is currency0 and the coin is currency1, without exception.

That is not trivia. It is what lets the hook charge one fixed side of the trade without branching on which currency is which, which in turn is what makes the fee logic short enough to read in one sitting.

The opening price

For a position spanning the whole curve, the price at which your supply and your ETH clear against each other is the square root of one over the other. The contract computes it with 512 bit intermediate math so it does not overflow on large supplies.

src/Etherflow.sol
function _openingPrice(uint256 ethAmount, uint256 supply)
    internal pure returns (uint160 sqrtPriceX96)
{
    uint256 ratioX192 = FullMath.mulDiv(supply, 1 << 192, ethAmount);
    uint256 root = Math.sqrt(ratioX192);
    if (root < TickMath.MIN_SQRT_PRICE || root >= TickMath.MAX_SQRT_PRICE) {
        revert PriceOutOfRange();
    }
    sqrtPriceX96 = uint160(root);
}

What happens to the rounding

Computing liquidity from two amounts leaves a few thousand wei of each side unused. The coins are burned to the dead address so the circulating supply still matches what is in the pool, and the leftover ETH goes back to you in the same transaction.

Why the launchpad holds the position directly

The obvious route would be Uniswap's PositionManager, which mints the position as an ERC-721. We call poolManager.modifyLiquidity from the launchpad's own unlock callback instead. That skips Permit2 and the NFT entirely, and it means the position is not a transferable object that could be sold or stolen. It is a balance inside the pool manager keyed to a contract with no code path that reduces it.

The lock is the absence of a function

There is no unlock timestamp, no third party vault and no LP token sent to a burn address, because v4 has no LP tokens. Read Etherflow.sol and search for a negative liquidityDelta. There is not one.

What the launchpad keeps

A registry: the token address, creator, beneficiary, timestamp, fee terms, seeded ETH, supply and pool id. That is what the board reads. It has no bearing on the pool and removing it would change nothing about how the coin trades.