Documentation
HELIX is a single immutable Uniswap v4 hook on Robinhood Chain that lets anyone provide ETH/HLX liquidity with leverage, at zero interest, and earn the pool's trading fees on the whole position. This page explains what the protocol does, the numbers behind it, every function, and where the risks are.
In plain words
You put ETH and HLX into a Uniswap pool through HELIX. HELIX adds more liquidity on top of yours, from a pool it owns called the seed. Up to five times what you put in.
The extra liquidity is a loan with no interest. What you owe is written down once, as an amount of ETH and an amount of HLX. It never grows.
While your position is open, it earns the pool's trading fees. Bigger position, bigger share. A small slice of every swap, 0.20%, goes to a treasury that buys HLX and burns half of it.
When you close, HELIX takes back what you owe and gives you the rest. If the price moves so far that 90% of your position is worth less than your debt, anyone can close it for you. They keep 5% of what is left. You get the rest.
Two things to remember. Leverage makes fees bigger and also makes price swings hurt more. And HELIX never trusts the live pool price: it uses its own slow-moving price, so nobody can trick it in one transaction.
Introduction
A normal liquidity position on Uniswap earns trading fees in proportion to its size. HELIX lets you make that position larger than your deposit. You bring ETH and HLX, choose a multiplier between 1.1x and 5x, and the hook adds the difference from a pool of liquidity it owns itself, called the seed. What you owe is written down once, as a fixed number of ETH and HLX, and never grows. While the position is open it earns the pool's 0.30% trading fee on all of its liquidity, the borrowed part included.
There is no lender, no interest rate, no governance and no admin. The whole HLX supply is minted into the hook at deploy. The deployer can do two things: launch once, and renounce. Every other rule is fixed in the constructor.
Three ideas make this safe to run against a live pool:
- A reference price the market cannot rush. The hook keeps its own price that follows the pool at most about 2.4% per block. Debt is priced at it, health is measured at it, and any action is refused while the live price is more than about 2% away from it.
- Fees are harvested before principal moves. Accrued trading fees are split and credited before any position is opened, closed, repaid or liquidated, so nobody can collect a share earned by someone else's liquidity.
- Insurance before the seed. When a closing or liquidated position returns fewer tokens than the seed needs at the current price, a reserve funded by entry fees and the unseeded supply tops it up first.
Leverage here makes your fees bigger and your price risk bigger. It is not a bet that HLX goes up. Read what leverage does to your result before going above 2x.
Key numbers
| What | Value | Notes |
|---|---|---|
| Leverage range | 1.1x to 5x | Chosen per position, in steps of 0.01%. Fixed for the life of the position; repaying lowers it. |
| Interest | 0% | Debt is a fixed token amount. |
| Entry fee | 2% of both tokens, once | ETH part to insurance. HLX part half to insurance, half burned. |
| Pool fee | 0.50% per swap on HLX | Paid by traders. 0.30% split by liquidity between positions and the seed, 0.20% to the treasury. Launched coins add their creator fee. |
| Liquidation line | 90% of position value | Liquidatable when 0.9 * V < D at the reference price. |
| Liquidation bonus | 5% of residual equity | To the liquidator. Never from the seed or insurance. |
| Reference price speed limit | 240 ticks per block, about 2.4% | Frozen within a block. |
| Spot guard | 200 ticks, about 2% | Actions revert while the pool is further than this from the reference. |
| Minimum hold | 5 blocks | L1 blocks, about one minute. Repay and collect are allowed during the hold. |
| Minimum deposit | 0.05 ETH and 10 HLX | Keeps liquidations worth the gas. |
| Supply | 1,000,000 HLX, fixed | All minted to the hook. Burns only reduce it. |
| Launch protection | 2% of supply per wallet for 3 minutes | Applies to buys from the pool only. Lifts itself. |
| Admin functions after launch | one | renounceOwnership. No pause, no fee switch, no withdrawal. |
Concepts
The pool
One Uniswap v4 pool: native ETH as currency0, HLX as currency1, 0.30% fee, tick spacing 60, with HELIX as its hook. Anyone can swap in it. Only the hook can add or remove liquidity, so the hook is the pool's only liquidity provider and every position inside HELIX is a slice of that one full-range position.
The seed
The liquidity the hook owns outright. It is created at launch from the ETH the deployer sends plus part of the HLX supply, and it grows when fees are folded in, when positions repay, and when anyone donates through seed(). When you open a position, the borrowed part is relabeled from the seed to you; when you close, it is relabeled back. Nothing can withdraw the seed. There is no function for it.
Positions, equity and borrowed liquidity
A position is a record of how much liquidity is yours (liquidity), how much of it came from the seed (borrowed), and what you owe for it (debt0 in ETH, debt1 in HLX). The part you funded yourself is your equity liquidity. Leverage is simply liquidity / equity liquidity.
Fixed debt
At open, the borrowed liquidity is converted into token amounts at the reference price, rounded up, and stored. Those two numbers are your debt. They never change unless you repay. There is no interest, no funding rate and no rebasing.
Health
The ratio between what your liquidity is worth and what you owe, both measured in ETH at the reference price, scaled by the 90% liquidation line. Health of 1.35 means your position is worth 1.35 / 0.9 = 1.5 times its debt. Below 1, anyone may liquidate. Because your debt is a fixed basket of ETH and HLX and your liquidity is a full-range LP position, health falls when HLX moves far in either direction.
The reference price
A tick stored by the hook that moves toward the live pool price at most 240 ticks per block and is frozen within a block. Everything economic is priced at it. The live price only matters for one thing: if it strays more than 200 ticks from the reference, actions wait.
Insurance
Two balances held by the hook: reserve0 in ETH and reserve1 in HLX. Funded by the unseeded supply at launch, by entry fees, and by leftovers. Spent only to rebuild the seed when a position comes back short on one token.
Pending fees and fold
The seed's share of harvested trading fees waits in pending0 and pending1. Anyone can call fold() to add it to the seed as liquidity and keep a tip of at most 5%. This is how the seed grows without anyone funding it.
The receipt
Each position is an ERC-6909 token minted to the opener. It is soulbound: transfer, transferFrom, approve and setOperator all revert. The position belongs to the address that opened it until it is closed or liquidated.
A worked example
The pool trades at 90,000 HLX per ETH. You send 1 ETH and 90,000 HLX and choose 3x. The liquidity unit used below is the one Uniswap uses: for a full-range position, L = ETH * sqrt(P), and the square root of 90,000 is 300.
- Entry fee. 2% of each token: 0.02 ETH goes to the ETH insurance reserve. 1,800 HLX is split: 900 to the HLX reserve, 900 burned. You have 0.98 ETH and 88,200 HLX left.
- Equity liquidity. 0.98 * 300 = 294 units. The pool ratio is met exactly, so nothing is refunded. If you had sent 95,000 HLX, the extra 6,800 would come back in the same transaction.
- Borrow. At 3x the hook relabels 2 * 294 = 588 units from the seed to you. Your position is 882 units.
- Debt. 588 units at the reference price of 90,000: 588 / 300 = 1.96 ETH and 588 * 300 = 176,400 HLX. Written down once.
- What you hold. 882 units at 90,000 is 2.94 ETH and 264,600 HLX, worth 5.88 ETH. Your debt is worth 1.96 + 176,400 / 90,000 = 3.92 ETH. Your equity is 1.96 ETH, which is what you put in after the fee. Health is 0.9 * 5.88 / 3.92 = 1.35.
- Earning. If the pool has 30,000 units of liquidity in total, your 882 units earn 2.94% of every swap fee. On your own money alone you would have earned 0.98%.
- Liquidation prices. Solving health = 1 gives 17,670 and 458,400 HLX per ETH. HLX would have to rise 5.1x or fall 80% from here.
- Closing. Suppose nothing moved and you collected 0.0042 ETH and 391 HLX of fees along the way. Closing removes 882 units, returns 2.94 ETH and 264,600 HLX, keeps 1.96 ETH and 176,400 HLX as your debt, and pays you the rest: 0.98 ETH and 88,200 HLX, plus any fees not yet collected. The 588 units are rebuilt into the seed.
This is the position shown on the overview page.
What leverage does to your result
A leveraged LP position is a leveraged LP position, not a leveraged long. Three things move your equity:
- Trading fees, which scale with leverage and are always positive.
- Impermanent loss, which every LP position carries and which also scales with leverage, because your debt is a fixed basket of tokens while your liquidity rebalances with the price.
- The 2% entry fee, once.
The table shows the value of your equity after a price move, before fees, starting from the example above. "Plain LP" is the same 1.96 ETH of equity provided without leverage. "Hold" is keeping the two tokens in a wallet.
| HLX price | Hold | Plain LP | 2x | 3x | 5x |
|---|---|---|---|---|---|
| x 0.5 | -25% | -29% | -34% | -38% | -46% |
| x 0.8 | -10% | -11% | -11% | -12% | -13% |
| x 1.0 | 0 | 0 | 0 | 0 | 0 |
| x 1.2 | +10% | +9% | +9% | +9% | +8% |
| x 2.0 | +50% | +41% | +33% | +24% | +7% |
The formula behind the table: with leverage m and an HLX price multiple r, your equity multiple before fees is m * sqrt(r) - (m - 1) * (1 + r) / 2. The first term is the LP position, which grows with the square root of the price. The second is the debt basket, half of which is HLX and moves one-for-one. Leverage stretches the gap between them.
What this means in practice:
- Leverage is a bet that fee income beats impermanent loss over your holding period. In a busy pool that is a good bet. In a quiet pool with a trending price it is not.
- The closer the price stays to your entry, the better leverage looks. Sideways markets are where leveraged LP earns most.
- Liquidation is not a wipeout. It happens while 10% of position value is still yours, so a 5x position liquidated on a crash returns about 29% of its initial equity to the owner, and one liquidated on a rally about 78%. Details in the next section.
Fees and yield
Where fees come from
Every swap in the HLX pool pays 0.50% of its input to the pool's liquidity provider (launched coins add their creator fee on top). Because the hook is the only liquidity provider, all of it lands on the hook's single full-range position, where Uniswap tracks it per unit of liquidity. Of that, 0.20% of volume is the protocol share and goes to the treasury; the remaining 0.30% is what positions and the seed earn, exactly as described below.
Harvesting
Before any principal changes (open, close, repay, liquidate, fold) and whenever someone collects, the hook harvests: it pokes the pool position with a zero-liquidity update, receives every fee accrued since the last harvest, and splits the two token amounts by liquidity.
f = f - t - creator share
positions' share u = f * totalUserLiquidity / (seedLiquidity + totalUserLiquidity)
feeGrowthX128 += u * 2^128 / totalUserLiquidity
seed's share f - u, kept as pending until someone folds it
Each position stores the value of feeGrowthX128 at the moment it opened or last collected. What it is owed at any time is liquidity * (feeGrowthX128 - snapshot) / 2^128, per token. A position therefore earns from the block after it opens, on its whole liquidity, and never on fees that accrued before it existed.
Collecting
collectFees(id) pays the owner what is owed and moves the snapshot forward. Closing and liquidation pay it too, always to the owner; a liquidator never receives the owner's fees. pendingFees(id) shows the harvested part; fees that accrued in the pool since the last harvest by anyone are added the next time any action runs.
Yield
Call the pool's fee rate rate: fees earned per day by one unit of liquidity, divided by that unit's value. A position at leverage m earns m * rate on its equity, with no borrowing cost to subtract.
| Pool value | Daily volume | Daily fees | Plain LP | 2.5x | 5x |
|---|---|---|---|---|---|
| 100 ETH | 5 ETH | 0.015 ETH | 5.5% a year | 14% | 27% |
| 100 ETH | 20 ETH | 0.06 ETH | 22% | 55% | 110% |
| 100 ETH | 50 ETH | 0.15 ETH | 55% | 137% | 274% |
These are gross numbers, before the 2% entry fee and before any price move. The app measures the real rate from the pool's own fee counters over the time the page has been open and shows the projection for the leverage you pick.
The entry fee
fee1 = ceil(amount1 * 2%), half to reserve1 (HLX insurance), half burned
It is the only charge the protocol makes. There is no exit fee, no performance fee and no interest.
Fold
The seed's share of the fees accumulates in pending0 and pending1. fold(tipBps) pays the caller up to 5% of that bucket and adds the rest to the seed as liquidity at the current pool ratio. A deeper seed means larger positions can be opened, which generates more fees, which folds into a deeper seed. Nobody has to run this; anyone who wants the tip will.
Health and liquidation
Liquidity and value
ETH held = L / sqrt(P) HLX held = L * sqrt(P)
Value in ETH: V(P) = 2 * L / sqrt(P)
Health
D = debt0 + debt1 / P_ref
health = 0.9 * V / D liquidatable when health < 1
At the opening price, V is m times your equity and D is m - 1 times it, so health at open is 0.9 * m / (m - 1). That is the buffer you start with:
| Leverage | Health at open | Liquidated if HLX falls by | Liquidated if HLX rises to |
|---|---|---|---|
| 1.5x | 2.70 | 96% | 27x |
| 2x | 1.80 | 91% | 10.9x |
| 3x | 1.35 | 80% | 5.1x |
| 4x | 1.20 | 71% | 3.5x |
| 5x | 1.125 | 63% | 2.7x |
Both liquidation prices, in closed form
Setting health = 1 and solving for the square root of P gives a quadratic with two roots. The app computes both for every position.
P_low = x_low^2 P_high = x_high^2 (HLX per ETH; liquidatable outside the band)
What happens at liquidation
- Anyone calls
liquidate(id, receiver). It reverts unless health is below 1 at the reference price, unless the live price is within the guard band, and unless no other liquidation happened in this block. - Fees are harvested. The position's liquidity is removed from the pool.
- Per token: the debt amount is kept; of what remains, 5% goes to
receiverand 95% to the position owner. The owner also receives every trading fee the position earned. - The kept debt tokens, topped up from insurance if one side is short, are rebuilt into the seed.
- The receipt is burned.
Because liquidation triggers when 10% of position value is still equity, the owner of a liquidated position typically receives a meaningful remainder, not zero. In the 3x example a crash liquidation returns about 13% of the initial equity, a rally liquidation about 68%; at 5x the figures are about 29% and 78%.
Repay
repay(id, amount0, amount1) sends ETH and HLX in the pool ratio, turns them into liquidity, returns that liquidity to the seed and reduces your debt by exactly the tokens used. Your own liquidity is untouched, so health rises and both liquidation prices move away from the current price. Repaying is allowed at any time, including during the minimum hold. Excess is refunded.
Insurance and the seed
What flows in
- At launch, every HLX not placed in the seed becomes
reserve1, and any ETH above what the ratio used becomesreserve0. - Every entry fee: the ETH part and half of the HLX part.
- Rounding leftovers from folds and reseats.
What flows out
Only one thing: rebuilding borrowed liquidity when a position closes or is liquidated. The debt tokens the position returns were sized at the opening price. At a different price the same liquidity needs a different mix of ETH and HLX, so one side is short and the other is in surplus.
avail_i = min(got_i, debt_i) + reserve_i
reLiq = min(borrowed, liquidityFor(avail0, avail1)), added back into the seed
reserve_i = avail_i - cost_i
The whole reserve of the scarce token is available for the rebuild, and the surplus of the other token is parked back in its reserve. No value leaves the protocol; it changes shape. If a reserve is fully drained, the seed is rebuilt with whatever liquidity the tokens support and comes back slightly smaller in liquidity units, while holding the surplus token in reserve for the next time.
The asymmetry to know about
The HLX reserve is deep from day one, because the unseeded supply is large. The ETH reserve starts near zero and grows only from entry fees. A strong HLX rally makes ETH the scarce side of every rebuild, so early in the protocol's life a rally can leave the seed temporarily smaller in liquidity units, with the excess HLX sitting in reserve. Every entry fee and every fold shrinks that gap.
Per-token settlement
Payouts are computed per token: max(0, got - debt) on ETH and again on HLX. If one side comes back below its debt, the shortfall is not taken from your surplus on the other side. Inside the liquidation band this is a small advantage to whoever closes, absorbed by insurance. It is bounded by the 90% line, which is why the line exists.
The reference price
A flash loan can move a pool a thousand-fold and put it back inside one transaction. Any lender that reads the pool price and acts on it in the same breath can be drained. HELIX never acts on the live price. It acts on a reference that is allowed to change only slowly.
function _projectOracleTick(int24 spot) internal view returns (int24 projected) {
projected = oracleTick;
if (oracleBlock == 0) return spot;
if (block.number <= oracleBlock) return projected; // frozen within a block
uint256 maxMove = (block.number - oracleBlock) * MAX_TICK_DELTA_PER_BLOCK;
int256 diff = int256(spot) - int256(projected);
if (diff > 0 && uint256(diff) > maxMove) diff = int256(maxMove);
else if (diff < 0 && uint256(-diff) > maxMove) diff = -int256(maxMove);
projected = int24(int256(projected) + diff);
}
The reference is synced in beforeSwap with the tick before the swap, and at the top of every economic action. Whichever comes first in a block wins, and nothing can move it again until the next block. Then the guard:
if (|spotTick - oracleTick| > MAX_SPOT_DEVIATION_TICKS) revert PriceOutOfBand();
What this means
- A price pushed inside one transaction cannot be used to open, close, liquidate or fold. The push moves the pool, the reference stays, the guard refuses.
- A price held across blocks must be held for
distance / 240blocks against arbitrage before the reference arrives there, paying for every block. A 20% move takes about 8 L1 blocks, about a minute and a half, during which every action is refused. - Honest users are only ever delayed. After a large market move the app shows how many ticks the reference still has to travel; it closes the gap at 240 ticks per block.
Lifecycle and ownership
- Deploy. The hook is deployed through CREATE2 with a mined salt, because Uniswap v4 reads a hook's permissions from the low bits of its address. The token is deployed next and mints the whole supply to the hook.
- Launch. The owner calls
launch(sqrtPrice, seedHlx)with ETH. The pool is initialized at that price, the seed is created from the ETH sent plusseedHlxfrom the hook's own balance, everything else becomes insurance,startedflips to true and the 3-minute launch protection begins. One shot: it cannot be called twice. - Live. Anyone can swap, open, close, repay, collect, liquidate, fold, seed and claim. None of these involve the owner.
- Renounce. The owner calls
renounceOwnership(). From then on no address holds any special power.
Between launch and renounce, the owner holds exactly one capability: renouncing. There is no pause, no parameter change, no fee switch, no upgrade path and no way to move the seed or the reserves.
The HLX token
- Standard ERC-20 with EIP-2612
permitand a publicburn(amount). - 1,000,000 HLX minted once, to the hook, in the constructor. There is no
mintand no owner. - Launch protection: for 3 minutes after
launchedAt, a transfer from the PoolManager (a buy) that would leave the recipient above 20,000 HLX, 2% of supply, reverts withMaxWalletExceeded. Sells, wallet-to-wallet transfers and payouts from the hook are never capped, and the hook itself is exempt. After the window the check switches itself off permanently. - Half of every HLX entry fee is burned, so supply only falls.
Parameters
All immutable, set in the constructor. The values below are the Robinhood Chain deployment.
| Name | Value | Meaning |
|---|---|---|
MAX_LEVERAGE_BPS | 50000 | 5x maximum. MIN_LEVERAGE_BPS is a constant 11000, 1.1x. |
LIQ_THRESHOLD_BPS | 9000 | Liquidatable when 90% of value is below debt. The constructor requires that the maximum leverage opens at health >= 1. |
ORIG_FEE_BPS | 200 | 2% entry fee on both tokens. |
INSURANCE_SPLIT_BPS | 5000 | Share of the HLX fee kept as insurance; the rest is burned. The ETH fee is always insurance. |
LIQ_BONUS_BPS | 500 | Liquidator's share of residual equity. |
MAX_TICK_DELTA_PER_BLOCK | 240 | Reference price speed limit, about 2.4% per block. |
MAX_SPOT_DEVIATION_TICKS | 200 | Guard band, about 2%. |
MIN_HOLD_BLOCKS | 5 | No close for 5 L1 blocks after opening. |
MIN_DEPOSIT_ETH / MIN_DEPOSIT_TOKEN | 0.05 ETH / 10 HLX | Anti-dust floors. |
MAX_FOLD_TIP_BPS | 500 | Constant. Cap on the keeper tip. |
FEE / TICK_SPACING | 3000 / 60 | The only pool key the hook accepts. |
Hook callbacks
| Callback | Behaviour |
|---|---|
afterInitialize | Accepts exactly one pool: currency0 = ETH, currency1 = HLX, fee 3000, spacing 60, hooks = this. Anything else reverts InvalidPoolKey; a second pool reverts AlreadyInit. Stores the key and seeds the reference price with the initial tick. |
beforeAddLiquidity / beforeRemoveLiquidity | Revert ExternalLiquidityBlocked unless the caller is the hook. The hook is the only liquidity provider. |
beforeSwap | Syncs the reference price with the pre-swap tick. Never changes amounts or fees. |
Uniswap v4 does not invoke hook callbacks when the hook itself is the caller. That is why launch() records the pool state directly after initializing, and why the hook's own liquidity changes do not pass through beforeAddLiquidity.
Launchpad
HELIX is also a factory. Anyone can launch a coin that comes with its own pool and its own copy of the HELIX hook, in one transaction, from the Launch page.
What a launch does
- Deploys the token: fixed supply, no owner, no mint, with the launch cap the creator chose.
- Deploys the hook from the audited HELIX bytecode (the factory checks it against a stored hash) with the creator's numbers: max leverage, liquidation line, creator fee.
- Mints the whole supply to the hook, initializes the pool at the chosen price, seeds it with the creator's ETH and the chosen share of supply, keeps the rest as insurance.
- Renounces the hook's ownership. The creator has no power over the coin from the first block.
Limits the factory enforces
| Setting | Range |
|---|---|
| Max leverage | 1.2x to 5x |
| Liquidation line | 85% to 95% |
| Creator fee | 0% to 3% of swap volume |
| Supply in the pool | 50% to 95%; the rest is insurance |
| Seed | at least 0.1 ETH of the creator's own ETH |
| Launch cap | none, or 0.5% to 10% per wallet for up to 1 hour |
| Launch fee | 0.01 ETH to the treasury |
Fees on a launched coin
The pool fee is 0.30% + 0.20% + creator fee. Positions and the seed keep the 0.30%, exactly like the HLX pool. The 0.20% goes to the treasury. The creator fee goes to the creator's wallet, paid out at every harvest with the same gas-capped payout used everywhere else.
Why addresses are mined in your browser
Uniswap v4 reads a hook's permissions from the low bits of its address, so the hook has to be deployed at an address that carries them. The launch page tries salts until it finds one. The salts must start with your own address, so nobody can take a launch you prepared.
Listing a coin that already exists
A coin does not have to be born on HELIX to get leverage. A second, separate factory, HelixListingFactory, opens a HELIX pool for any standard coin on the chain. The List page drives it.
In plain words
You bring ETH and some of the coin. HELIX creates a new pool for that coin with its own leverage hook, puts your ETH and coins in it for good, keeps a slice of the coins as insurance, and drops ownership in the same transaction. From then on anyone can open leveraged positions on that coin, and you earn your fee on every swap in that pool.
What a listing does
- Checks the coin: 18 decimals, a standard transfer that returns true, and the exact amount arriving. Coins that tax or rebase on transfer are rejected.
- Deploys the hook from the same audited bytecode as every other HELIX hook, checked against the stored hash.
- Pulls your coins into the hook, opens the pool at the price your two amounts imply, and seeds it with your ETH and coins. The seed can never be withdrawn.
- Keeps the insurance coins in the hook to cover bad debt, then renounces ownership.
Limits
| Setting | Range |
|---|---|
| Max leverage | 1.2x to 5x |
| Liquidation line | 85% to 95% |
| Creator fee | 0% to 3% of swap volume |
| Seed | at least 0.1 ETH plus the matching coins |
| Insurance | at least 5% of the coins you seed |
| Listing fee | 0.01 ETH to the treasury |
How a listed coin differs from a launched coin
- No launch cap. The coin already trades elsewhere, so there is no opening to protect.
- Nothing is burned. The token share of the entry fee goes fully to insurance, because HELIX cannot burn somebody else's coin.
- A coin launched on HELIX can never be listed. It has one HELIX pool, with the fee its creator chose, and nobody can open a second one next to it to split its traders or charge them more. That includes HLX.
- A coin from outside can be listed more than once, by different people, with different rules. Each listing is its own pool with its own price, positions and fees, and one pool cannot move or liquidate another. This is on purpose: with one listing per coin, anyone could grab a popular coin first with a bad pool.
- The price you pick matters. If your two amounts do not match the coin's market price, traders will correct the pool and the difference comes out of your seed.
HELIX controls the pool and the hook, not the coin. If the coin's owner can pause transfers, blacklist wallets, mint or add a tax later, positions in that pool can lose value or get stuck. The coin page shows a warning on every listed coin.
Treasury
Every HELIX pool sends 0.20% of its swap volume to HelixBuyback, a contract with no owner and no withdrawal function. Launch fees go there too. Anyone can turn its balance into value for HLX holders in two steps:
commitFlush()records the current pool price and liquidity for the caller.- Between 3 and 100 blocks later,
flush(minOut)buys HLX in the HLX pool with the ETH balance, burns 50% of all HLX held, and adds the other 50% together with the remaining ETH to the HLX seed as permanent liquidity. The caller keeps 0.5% of the ETH as a tip.
The buy has a floor computed along the pool curve at the committed price and liquidity, minus a 4% allowance. A pump between commit and flush, or a sandwich around the flush, pushes the real output under that floor and the whole flush reverts. Nobody can extract from the treasury; they can only delay a flush by a few blocks.
Fees paid in other coins
Pools pay fees in both ETH and the coin. The ETH side is ready for a flush. The coin side of every launched or listed coin can be sold for ETH by anyone with the same two steps: commitSell(hook), then sell(hook, minOut) between 3 and 100 blocks later, with the same price floor and the same tip. It only works on pools created by the two HELIX factories, and HLX itself is never sold.
One rule keeps this safe when a coin has more than one HELIX pool: a pool's fees can only be sold through that same pool. Every hook counts the coins it has sent to the treasury (treasuryToken1), and sell(hook) never sells more than that count. So nobody can open a tiny second pool for a coin, push its price where nobody is watching, and make the treasury dump another pool's fees into it. sellable(hook) shows what a pool can sell right now.
Result for HLX: supply falls with every flush, the HLX seed grows with every flush, and both are funded by activity on every coin launched on HELIX.
Functions
Every action runs inside PoolManager.unlock; the liquidity work happens in a callback that only the PoolManager can invoke. Every entry point is nonReentrant. Actions marked price guard first sync the reference price and require the live price to be within the band.
launch(uint160 sqrtPriceX96, uint256 seedToken) payable to uint128 liq
renounceOwnership()
launch initializes the pool at sqrtPriceX96 if nobody has, adds msg.value ETH plus seedToken HLX from the hook's own balance as the seed, keeps unused ETH and every remaining HLX as insurance, and sets started and launchedAt. If someone pre-initialized the pool at a price more than about 6% away from the requested one it reverts InitPriceOutOfRange. renounceOwnership sets the owner to zero. Emits Launched, OwnershipRenounced.
seed(uint256 amount0, uint256 amount1) payable to uint128 liq
Donate liquidity to the seed after launch. amount0 must equal msg.value; HLX is pulled only for what the pool ratio uses, so approve the hook first. Unused ETH is refunded. Emits Seeded.
open(uint256 amount0, uint256 amount1, uint16 leverageBps, uint128 minLiq, uint256 deadline) payable to uint256 id
- Checks: deadline not passed, protocol started,
11000 <= leverageBps <= 50000,msg.value == amount0, both amounts above the minimums, no liquidation in this block. - Entry fee, 2% of each side, rounded up. ETH fee to
reserve0; HLX fee half toreserve1, half burned. - The full
amount1is pulled from you. - Inside the callback: fees are harvested; your equity liquidity is added at the live price; whatever the ratio did not use is refunded and
Refundedis emitted. (leverageBps - 10000) / 10000 * equity liquidityis relabeled from the seed to you. The token amounts that liquidity represents at the reference price, rounded up, becomedebt0anddebt1. RevertsSeedTooThinif the seed cannot cover it.- The position is stored with the current fee index as its snapshot, the receipt is minted, health must be at least 1 (
Unhealthy), and the position's liquidity must be at leastminLiq(Slippage).
Emits Opened(id, owner, liq, borrowed, debt0, debt1, leverageBps). Use previewOpen for minLiq.
close(uint256 id, uint256 minOut0, uint256 minOut1, uint256 deadline)
Reverts NotOwner for anyone else, NoPosition for an unknown id, MinHold before openedAt + 5 blocks. Harvests fees, removes the position's liquidity, keeps the debt amounts, pays you max(0, got - debt) per token plus every fee the position earned, and requires the payout to be at least minOut0 and minOut1 (Slippage). The kept tokens, topped up from insurance where needed, are rebuilt into the seed. Burns the receipt. Emits Closed and, if fees were owed, FeesCollected.
repay(uint256 id, uint256 amount0, uint256 amount1, uint256 deadline) payable
Pay down debt with fresh ETH (msg.value == amount0) and HLX. Both are required (OneSidedRepay), each at most the corresponding debt (OverRepay). The amounts are turned into liquidity at the live ratio, capped at the position's borrowed liquidity, added to the seed, and the tokens actually used are subtracted from debt0, debt1 and borrowed. Unused amounts are refunded. Allowed during the minimum hold. Emits Repaid.
collectFees(uint256 id) to (uint256 fee0, uint256 fee1)
Harvests, pays the owner everything the position has earned since it opened or last collected, and moves the snapshot forward. Nothing here depends on price, so there is no guard and it works during the minimum hold. Emits FeesCollected when the amount is non-zero.
liquidate(uint256 id, address receiver)
Reverts Healthy unless healthFactor(id) < 1e18 at the reference price, and OneLiqPerBlock if a liquidation already ran in this block. Settlement is the same as close, except that 5% of each token's residual goes to receiver and 95% to the owner. The owner also receives the position's fees. The bonus is never taken from the seed or the insurance. Burns the receipt. Emits Liquidated.
fold(uint256 tipBps)
Harvests, pays the caller tipBps of the pending bucket (at most 500, TipTooHigh above), and adds the rest to the seed at the live ratio. Rounding dust goes to insurance. Emits Folded(keeper, added, tip0, tip1).
claim()
Payouts inside close, liquidate, repay and collect are sent with a gas cap so a hostile recipient cannot block them. If a send fails, the amount is credited to escrow0 / escrow1 for that address. claim() pays it out with full gas. NothingToClaim if empty. Emits Claimed.
Views
| Function | Returns |
|---|---|
previewOpen(amount0, amount1, leverageBps) | The position liquidity open would produce at the live price, fee rounding included. Multiply by 1 - slippage for minLiq. Returns 0 for a leverage outside the range. |
positions(id) | (owner, liquidity, borrowed, debt0, debt1, openedAt, leverageBps, feeSnap0, feeSnap1). Owner is zero for closed or unknown ids. |
healthFactor(id) | 0.9 * V / D at the reference price, scaled by 1e18. Max uint for no debt or no position. |
isLiquidatable(id) | healthFactor < 1e18 for an existing position. |
pendingFees(id) | Fees harvested and not yet collected. Fees still sitting in the pool are added at the next harvest. |
feeGrowth0X128() / feeGrowth1X128() | Cumulative fees per unit of position liquidity, Q128. |
oracleSqrtPrice() | The reference price right now, as a sqrt price, projection included. |
oracleTick() / oracleBlock() | Stored reference tick and the block it was last synced in. |
seedLiquidity() / totalUserLiquidity() | Lendable liquidity, and liquidity labeled to open positions. |
reserve0() / reserve1() / pending0() / pending1() | Insurance and the seed's unfolded fee share. |
escrow0(a) / escrow1(a) | Undelivered payouts for an address. |
started() / launchedAt() / owner() / lastLiquidationBlock() | Lifecycle state. |
poolKey() / poolId() / poolManager() / TOKEN() | Pool binding. |
Events
| Event | Fields |
|---|---|
Launched | sqrtPriceX96, seedLiq, insuranceToken |
Seeded | from, liq |
Opened | id, owner, liq, borrowed, debt0, debt1, leverageBps |
Refunded | to, amt0, amt1 |
Closed | id, owner, out0, out1 |
Repaid | id, owner, liqRepaid, debt0After, debt1After |
FeesCollected | id, owner, fee0, fee1 |
FeesHarvested | toPositions0, toPositions1, toSeed0, toSeed1 |
Liquidated | id, liquidator, receiver, bonus0, bonus1 |
Folded | keeper, added, tip0, tip1 |
Escrowed / Claimed | to, amt0, amt1 |
OwnershipRenounced | none |
Errors
| Error | When |
|---|---|
PriceOutOfBand | The live price is more than 200 ticks from the reference. Wait; the reference closes 240 ticks per block. |
MinHold | Close within 5 blocks of opening. |
BlockedByLiq / OneLiqPerBlock | Open in a block that had a liquidation / second liquidation in a block. |
Healthy / Unhealthy | Liquidating a healthy position / opening one that would start below health 1. |
NotOwner / NoPosition | Acting on someone else's position / an id that does not exist. |
BadLeverage / BelowMinDeposit / EthMismatch / Expired / Slippage | Input validation. |
OverRepay / OneSidedRepay | Repaying more than owed / with only one token. |
SeedTooThin / ZeroLiquidity / RoundingExceedsInput | Liquidity edge cases. |
NotStarted / AlreadyStarted / ZeroSeed / SeedExceedsBalance / InitPriceOutOfRange | Launch lifecycle. |
InvalidPoolKey / AlreadyInit / NotInitialized / ExternalLiquidityBlocked | Pool binding. |
NonTransferable | Any attempt to move or approve a receipt. |
MaxWalletExceeded | Token: a buy above 2% of supply during the first 3 minutes. |
TipTooHigh / NothingToClaim / TransferFailed / Reentrancy / BadParams / BadDelta / NotPoolManager | Guards. |
Security model
HELIX is a lender that prices everything off the pool it lives in. These are the threats that matter for such a design and the answer built in for each.
| Threat | Defence |
|---|---|
| Flash-loan manipulation: move the pool inside one transaction, act at the fake price, put it back | The reference price cannot move within a block and follows at most 240 ticks per block. Debt is priced at it. Every action refuses to run while the live price is more than 200 ticks away. |
| Multi-block manipulation | Holding a moved price costs arbitrage losses for every block until the reference arrives. The minimum hold, one liquidation per block and no opens in a liquidation block remove the quick round trips that would make it pay. |
| Capturing other people's fees | Fees are harvested and split before any principal change. Each position only earns from its own snapshot forward. The fold tip is capped at 5%. |
| One-directional liquidation blind spot | Health is value-based and falls whether HLX rises or falls. |
| Draining the seed through shortfalls | Insurance rebuilds borrowed liquidity first. The liquidator bonus is paid only from residual equity. |
| Attaching the hook to a look-alike pool | afterInitialize accepts exactly one pool key. |
| Hostile recipients blocking closes or liquidations | Gas-capped payouts with escrow and claim(). |
| Reentrancy, direct callback calls, outside liquidity | nonReentrant on every entry point; the unlock callback accepts only the PoolManager; only the hook may add or remove liquidity. |
| Insider risk | Supply minted to the hook, no seed-withdrawal function, owner can only launch once and renounce, no tax and no treasury. |
| Launch sniping | 2% of supply per wallet on buys for the first 3 minutes. |
Evidence
The Foundry suite has 29 tests. It checks that open and close round trips never shrink the seed (fuzzed); that manipulated opens and closes revert; that the reference price is rate-limited across blocks; that a copy of the contract with the guard disabled leaks value under the manipulation attack while the guarded contract moves nothing; that nobody can close, repay, collect on or liquidate someone else's healthy position; that receipts cannot be moved or approved; that the unlock callback cannot be called directly; that outside liquidity is blocked; that fees split pro rata by liquidity and pay out on collect, close and liquidation, always to the owner; that positions opened later get none of the earlier fees; that a 5x position opens at health 1.125 and is liquidatable inside its band; that liquidation works in both price directions; that only one liquidation runs per block; that repay lowers debt and raises health; that unused deposit is refunded; that minimum hold, minimum deposit, deadline and leverage bounds are enforced; that the launch cap works and lifts; that burns reduce supply; and that launch is one-shot with no seed-withdrawal path. A separate RPC smoke test drives the exact calls the website makes against a local chain.
Risks
- Impermanent loss, multiplied. Leverage scales the loss an LP position takes when the price moves. If the pool is quiet and the price trends, a leveraged position underperforms holding. See the table.
- Liquidation in both directions. A 5x position is liquidated by a 63% drop or a 2.7x rise. Repay widens the band.
- Insurance depth. The ETH reserve starts near zero and grows only with entry fees. Until it is deep, a strong rally can leave the seed smaller in liquidity units, with the surplus parked in the HLX reserve.
- Sustained manipulation. The guard stops atomic and short attacks. Holding a moved price for many blocks in a thin pool is expensive but not impossible; depth is the defence.
- Immutability. No upgrades. A bug that ships, ships forever.
- Unaudited. Tested against the known failure modes above; not reviewed by a third-party auditor.
Robinhood Chain notes
- Chain id 4663. RPC
https://rpc.mainnet.chain.robinhood.com. Explorerrobinhoodchain.blockscout.com. Uniswap v4 PoolManager0x8366a39CC670B4001A1121B8F6A443A643e40951. The canonical CREATE2 deployer exists, so the hook's flag-encoded address is mined the same way as on Ethereum. - It is an Arbitrum-Orbit chain: inside the EVM,
block.numberis the L1 block, about 12 seconds, while the RPC's block numbers are L2 blocks, about a quarter of a second. Every per-block rule in the hook (reference speed, minimum hold, one liquidation per block, liquidation-block open pause) counts L1 blocks. The app reads the L1 block from the block header. - The hook runtime is under the 24,576-byte contract size limit, which the chain enforces.
- Gas is cheap: the whole deploy plus launch simulates at well under 0.01 ETH.
Integrating
Opening a position (ethers v6)
const hook = new ethers.Contract(HOOK, HOOK_ABI, signer);
const token = new ethers.Contract(HLX, ERC20_ABI, signer);
const a0 = ethers.parseEther("0.1"), a1 = ethers.parseEther("9000"); // pool ratio
const leverageBps = 25000; // 2.5x, allowed 11000 .. 50000
const deadline = Math.floor(Date.now() / 1000) + 600;
await (await token.approve(HOOK, a1)).wait();
const liq = await hook.previewOpen(a0, a1, leverageBps);
await hook.open.staticCall(a0, a1, leverageBps, liq * 99n / 100n, deadline, { value: a0 }); // surfaces reverts
const tx = await hook.open(a0, a1, leverageBps, liq * 99n / 100n, deadline, { value: a0 });
// later
await hook.collectFees(id);
Reading the pool price
const slot = ethers.keccak256(ethers.concat([poolId, ethers.zeroPadValue(ethers.toBeHex(6n), 32)]));
const data = BigInt(await poolManager.extsload(slot));
const sqrtPriceX96 = data & ((1n << 160n) - 1n);
const hlxPerEth = (Number(sqrtPriceX96) / 2 ** 96) ** 2;
Liquidation prices for a position
const p = await hook.positions(id);
const T = 0.9, l = Number(p.liquidity), a = Number(p.debt0), b = Number(p.debt1);
const s = Math.sqrt(T * T * l * l - a * b);
const pLow = ((T * l - s) / a) ** 2, pHigh = ((T * l + s) / a) ** 2; // HLX per ETH
Measuring the fee rate
// feeGrowthGlobal0X128 / 1X128 live at pool state slot + 1 and + 2
const base = BigInt(slot);
const g0 = BigInt(await poolManager.extsload(ethers.toBeHex(base + 1n, 32)));
const g1 = BigInt(await poolManager.extsload(ethers.toBeHex(base + 2n, 32)));
// sample twice, dt seconds apart: fees per unit L = (dg0 + dg1 / P) / 2**128, value per unit L = 2 / (sqrtPriceX96 / 2**96)
// APR = fees / value * (365 * 86400 / dt); a position at leverage m earns m * APR on equity
The current EVM block on Robinhood
const b = await provider.send("eth_getBlockByNumber", ["latest", false]);
const evmBlock = parseInt(b.l1BlockNumber, 16); // compare with positions(id).openedAt
Deploying
# simulate against Robinhood Chain; broadcasts nothing
forge script script/Deploy.s.sol:Deploy --rpc-url https://rpc.mainnet.chain.robinhood.com --sender YOUR_ADDRESS
# real deploy: the same command plus --broadcast and your wallet configuration
# optional: SEED_ETH_WEI, SEED_HELIX_WEI, START_TICK
The script predicts the token address from the deployer's nonce, mines the hook salt, deploys the hook and then the token, calls launch, and writes web/deployments/4663.json for the site. ETH sent above what the ratio needs becomes ETH insurance. After launch: verify both contracts on the explorer, watch a few positions open and close, then call renounceOwnership().
FAQ
Is this a leveraged long on HLX? No. It is a leveraged liquidity position. It earns more fees and carries more impermanent loss. If you want price exposure, hold the token.
Do I earn anything while the position is open? Yes. Your share of every swap fee, on your whole liquidity, borrowed part included. Collect at any time, or receive it when you close.
Does my debt grow? No. It is two fixed numbers written at open. There is no interest.
Why do I need both tokens? A full-range LP position always holds both. The app matches the HLX amount to your ETH at the live price, and any excess is refunded.
Why can I not transfer my position? Receipts are soulbound by design. No secondary market, no hidden owners, no way to sell a position to someone who does not understand it.
What is PriceOutOfBand? The pool moved faster than the reference price is allowed to follow. Wait a few blocks; the app shows the remaining distance.
Why can I not close yet? Minimum hold of 5 L1 blocks, about a minute. You can repay and collect fees in the meantime.
What happens if I get liquidated? Your liquidity is removed, your debt is kept, 5% of what remains goes to the liquidator and 95% to you, along with your fees. It triggers while 10% of position value is still yours, so it is rarely a total loss.
Can the team change the fee, pause the protocol or take the seed? No. Those functions do not exist. The owner can launch once and renounce.
Where do the fees go? Entry fee: ETH to insurance, HLX half to insurance and half burned. Trading fees: 0.30% to positions and the seed by liquidity, 0.20% to the treasury that buys and burns HLX, plus the creator fee on launched coins. Liquidation bonus: to the liquidator. No team wallet.
Can I launch my own coin? Yes. The Launch page deploys a token, a pool and a leverage hook in one transaction and gives up ownership in the same block. See Launchpad.
My coin launched somewhere else. Can it get leverage here? Yes. The List page opens a HELIX pool for a coin that already exists. See Listing a coin.
Can someone open a second pool for a HELIX coin and charge traders more? Not on HELIX. The listing factory refuses any coin that was launched here. Anyone can still open a plain Uniswap pool anywhere, as for every coin on every chain, but it is not a HELIX pool: it cannot move the HELIX price, cannot liquidate anyone, is not shown on this site, and the treasury never trades through it.
What is the seed, and who owns it? Liquidity the hook owns outright and lends from. Nobody can withdraw it. It grows from fees, repayments and donations.
Why is there a 2% cap for the first 3 minutes? So that bots cannot buy the opening. It applies to buys from the pool only and switches itself off.
Has it been audited? No. It has 29 tests, including a replay of the manipulation attack against a guard-disabled copy. Treat it as experimental software.
Glossary
| Term | Meaning |
|---|---|
| Liquidity unit, L | Uniswap's measure of a position's size. For a full-range position at price P, ETH held is L / sqrt(P) and HLX held is L * sqrt(P). |
| Seed | The hook's own liquidity, the lender of last and only resort. |
| Equity liquidity | The part of your position you paid for. |
| Borrowed liquidity | The part relabeled from the seed. Returned when you close. |
| Debt | Two fixed token amounts, ETH and HLX, owed for the borrowed liquidity. |
| Health | 0.9 * value / debt at the reference price. Below 1 means liquidatable. |
| Reference price | The hook's rate-limited price. Also called the oracle in the code. |
| Guard band | The 200 ticks around the reference within which the live price must be for actions to run. |
| Tick | Uniswap's price unit. One tick is a 0.01% price step; 100 ticks is about 1%. |
| Harvest | Collecting accrued fees from the pool and splitting them between positions and the seed. |
| Fold | Compounding the seed's fee share into the seed. Anyone can do it for a tip. |
| Insurance | The ETH and HLX reserves that rebuild the seed when a position comes back short on one token. |
| Escrow | Where a payout waits if it could not be delivered to your address. |
| Receipt | The soulbound ERC-6909 token that represents your position. |