Back to Blog

How Doppler Locks Liquidity: Inside the beforeRemoveLiquidity Hook

Onuora Amobi·July 14, 2026
liquidity locks
uniswap V4
Doppler
token launches
DeFi security
How Doppler Locks Liquidity: Inside the beforeRemoveLiquidity Hook

TL;DR: Doppler, the token launch protocol built by Whetstone Research on Uniswap v4, doesn't lock liquidity the way traditional lockers do. Instead, its hook contract owns all of the pool's liquidity and uses Uniswap v4's guarded liquidity callbacks — beforeAddLiquidity and beforeRemoveLiquidity — to revert any attempt by an outside address to add or remove positions.

During the auction, nobody (including the token deployer) can pull liquidity. What happens after the auction depends entirely on the launch's migration configuration, which is why every Doppler token still needs to be verified individually.

If you've been researching a token launched through Doppler and hit terms like beforeRemoveLiquidity, DopplerHookInitializer, or DERC20, this guide explains what each piece actually does, where the lock is enforced in code, and how to check it yourself on-chain.

What is Doppler?

Doppler is a liquidity bootstrapping and token launch protocol developed by Whetstone Research, built directly on top of Uniswap v4. Rather than seeding a pool at a fixed price and hoping the market sorts it out, Doppler runs a Dutch-auction-style price discovery process inside a Uniswap v4 pool, then migrates the resulting liquidity to a long-lived venue once the auction completes.

The reason Doppler can do this — and the reason it couldn't have existed on Uniswap v2 or v3 — is Uniswap v4's hook system. Hooks are external contracts that the Uniswap v4 PoolManager calls at defined points in a pool's lifecycle: before and after initialization, before and after each swap, and before and after any liquidity is added or removed. A hook can inspect these operations, modify their behavior, or reject them outright by reverting.

Doppler uses that last capability aggressively. As the protocol's own documentation puts it, Doppler "abstracts the challenges associated with Uniswap v4 integrations by executing the entire liquidity bootstrapping auction inside of the hook contract." The hook isn't an accessory to the pool — it is the market maker.

Where the liquidity lock actually lives

In a conventional token launch, liquidity sits in positions owned by the team or early LPs, and a "lock" means transferring those LP tokens or position NFTs into a third-party time-lock contract. Doppler inverts this model: there are no external liquidity providers at all.

During a Doppler auction, four hook callbacks do the structural work:

  • afterInitialize places the initial liquidity positions when the pool is created.
  • beforeSwap triggers the bonding-curve rebalance at the start of each epoch.
  • afterSwap updates the auction's accounting — tracking totalTokensSold and the proceeds accumulated, net of LP and protocol fees.
  • beforeAddLiquidity reverts any external attempt to supply liquidity to the pool. The protocol's docs are explicit that it "doesn't want any external liquidity providers" — every unit of liquidity in the pool is created and managed by the hook itself.

The beforeRemoveLiquidity callback is the mirror image of that last guard, and it's the piece most people searching this topic are trying to understand. Because the hook contract is the sole owner of the pool's positions, and because Uniswap v4 routes every modifyLiquidity call through the hook's guarded callbacks, an outside address that tries to withdraw liquidity from a Doppler pool has its transaction reverted before it touches a position. There is no LP token to unstake, no position NFT to transfer, no admin withdrawal function. The lock isn't a promise layered on top of the pool — it's a structural property of who owns the liquidity and what the hook permits.

This is a meaningfully stronger guarantee during the auction than a conventional time-lock, because there's nothing to rug: the deployer never holds the liquidity in the first place.

How the auction manages that locked liquidity

While outsiders are locked out, the hook is constantly reshaping the liquidity it owns. Doppler organizes positions into what it calls slugs:

  • A lower slug sits below the current price and holds the auction's accumulated proceeds, guaranteeing that buyers can always sell back into the pool.
  • An upper slug sits above the current price and supplies the tokens expected to sell in the current epoch.
  • Price discovery slugs stack above the upper slug, staging inventory for future epochs.

Time is divided into epochs, and at each epoch boundary the beforeSwap callback rebalances the curve. If sales are lagging, a max Dutch auction walks the curve downward by a fixed step — the distance between the ending and starting tick divided by the total number of epochs. If the auction is merely undersold, a relative Dutch auction shifts the curve down proportionally to the shortfall. If demand is running hot and the token is oversold, the curve moves up based on the gap between the current and expected tick. All of these adjustments accumulate in a tickAccumulator, and the effective curve position is simply the starting tick plus that accumulator.

None of this matters much for a casual buyer, but it matters for trust: the rebalancing logic is deterministic, on-chain, and executed by the same hook that enforces the lock. Price discovery and liquidity custody are the same contract.

DERC20 and the hook initializer — what each piece does

Two other names come up constantly in searches about Doppler locks, so it's worth being precise about them.

DERC20 (you'll also see it written DopplerERC20) is Doppler's token standard — the ERC-20 implementation that launches through the protocol mint. It carries launch-relevant features that a vanilla ERC-20 doesn't:

  • Built-in vesting. Allocations can be configured with a duration and cliffDuration; recipients claim via a release() function once the cliff passes. Team tokens vesting on-chain in the token contract itself, rather than through a side agreement, is a verifiable commitment.
  • Controlled inflation. An optional yearlyMintRate defines programmatic minting, visible to anyone reading the contract. Zero means fixed supply; anything else is disclosed by construction.
  • Pool lock awareness. The contract tracks whether its pool has been unlocked, exposed through a getIsPoolUnlocked() view — a one-call check on lock status.

The hook initializer (the DopplerHookInitializer that appears in so many of these searches) is part of Doppler's deployment plumbing. Uniswap v4 hooks can't just be deployed anywhere — a hook's address must encode permission flags that tell the PoolManager which callbacks it implements, which requires deterministic deployment. Doppler wraps this in its Airlock contract: a unified entry point that takes the launch parameters and orchestrates the token factory, the pool/hook initializer, the migrator, and the governance factory in one flow. The initializer's job is to deploy the hook with the correct flags — including the liquidity guards — and initialize the pool bound to it. You don't interact with it as a trader; its significance is that the lock-enforcing callbacks are wired in at deployment, not enabled later by an admin.

What happens when the auction ends — and where the caveats start

Here is the part that deserves the most attention, because "Doppler locks liquidity" is true during the auction and conditional after it.

When an auction completes, the bootstrapped liquidity migrates out of the auction pool into a long-lived venue, and the destination is chosen per-launch by the deployer:

  • Migration to Uniswap v2 or v3. The proceeds and tokens form a standard pool. In this configuration, Doppler's own docs describe no built-in lock or fee streaming — once migrated, that liquidity is ordinary pool liquidity unless the team locks it separately.
  • Migration to Uniswap v4 with the StreamableFeesLocker. This is the restrictive path: migrated liquidity is held by a locker contract for a configurable lockDuration (a year, for example, is 365 * 24 * 60 * 60 seconds), while trading fees stream to named beneficiaries who claim through collectFees(). The protocol requires that the Airlock owner receive at least 5% of streamed fees.
  • No-op migration. For some auction types (multicurve, and "lockable" v3 static auctions), liquidity simply stays where it is and the pool remains in Locked status. Some configurations split ongoing fees across asset buybacks, numeraire buybacks, beneficiary streams, and LPs by fixed percentages.

Governance at migration is similarly configurable — from a standard OpenZeppelin Governor, to custom parameters, to no-op governance with no on-chain voting at all.

The practical consequence: two tokens can both truthfully say "launched on Doppler" and have completely different liquidity guarantees after graduation. One migrated to v4 with a 365-day StreamableFeesLocker; another migrated to v2 with nothing. The protocol enforces the auction-phase lock for everyone; the post-migration lock is a per-launch choice.

How to verify a Doppler lock on-chain

Five checks, in order of effort:

  1. Confirm the hook. Find the token's Uniswap v4 pool and read its pool key — the hook address is part of it. Check that the hook contract's source is verified on the block explorer and matches an official Doppler deployment listed in the Doppler docs. An unverified look-alike hook with a Doppler-ish name is the impersonation risk here.
  2. Check pool lock status. Call getIsPoolUnlocked() on the DERC20 token contract. During the auction phase it should report locked.
  3. Identify the migration configuration. Determine where liquidity went (or will go) at graduation: v2, v3, v4-with-locker, or no-op. If it's the v4 path, read the StreamableFeesLocker position — the lockDuration, its start, and the beneficiary list are all on-chain.
  4. Read the token's economics. Check yearlyMintRate (any inflation?) and the vesting schedule (how much is cliffed, for how long, releasable by whom?).
  5. Check governance. No-op governance means no token-holder control post-launch; a Governor deployment means proposals and voting exist. Neither is automatically good or bad, but it changes who can decide things later.

If you only have time for one thing, do #3. The auction lock takes care of itself; the migration config is where launches differ.

How this compares to a traditional liquidity locker

Doppler's approach and third-party lockers like Team Finance solve overlapping but distinct problems.

A protocol-enforced lock like Doppler's is structural: during the auction there is simply no path for anyone to withdraw. Its limits are temporal — it covers the bootstrapping phase, and post-migration protection depends on per-launch configuration.

A dedicated locker is custodial and explicit: a team deposits LP tokens or position NFTs into an audited time-lock, receives a public lock entry anyone can look up, and the lock covers whatever venue the liquidity actually lives in — v2, v3, v4, or a non-Uniswap DEX across any of the 26+ supported chains. It also produces a simple, legible artifact ("locked until this date, verifiable here") that most retail participants can check in ten seconds, without reading hook callbacks.

The two compose naturally: a token can bootstrap through Doppler's auction and then lock its migrated v2/v3 liquidity in a conventional locker, closing exactly the gap the migration step opens. If you're evaluating any token's lock — Doppler-launched or not — the general methodology in our locked liquidity guide applies.

FAQ

Does beforeRemoveLiquidity mean liquidity can never be removed? No. It means removal attempts that don't originate from the protocol's own flow revert. The hook itself rebalances liquidity every epoch, and at graduation the migration process moves it. "Locked" here means locked against external and deployer withdrawal during the auction, not frozen forever.

Is a Doppler launch automatically rug-proof? The auction phase is structurally protected. After migration, it depends on the launch's configuration — v4 migration with a fee locker and a meaningful lockDuration is strong; a bare v2 migration with no subsequent lock is only as safe as the team's behavior.

What's the difference between DERC20 and a normal ERC-20? DERC20 adds on-chain vesting (cliff + duration with release()), optional programmatic inflation via yearlyMintRate, and pool-lock status via getIsPoolUnlocked() — governance-relevant properties made readable by anyone.

Sources: Doppler documentation · whetstoneresearch/doppler on GitHub · Uniswap v4 liquidity hooks

This article is for informational purposes and is not financial advice. Contract behavior described here reflects Doppler's public documentation at the time of writing; always verify the specific deployment you're evaluating.

Share
Back to Blog