Skip to main content

Integration

What a front end or an indexer needs. The protocol page is the mechanism; this is the surface.

Live, and open

The six core contracts are deployed on chain 4663 and frozen, twelve stocks are listed, and public launching is open: on 2026-09-22 publicLaunch reads true and strategyCount reads 1.

Addresses below are the production ones, verified read-only on chain that day. The addresses on this page are the protocol — the sandbox hook is a different contract with a similar-looking address, so point nothing at it.

Network​

ChainRobinhood Chain
Chain ID4663
The deskhedgefun.trade — its own domain, not a subdomain of the app
Explorerrobinhoodchain.blockscout.com
A launch's own poolUniswap V4, on the shared hook, quoted in the stock
The treasury's stock legUniswap V3 only, with a 10-minute TWAP corroborating spot
Stock oracleChainlink, RHxxx / USD ÷ the USDG feed — see the three prices
Block time~0.1s, which is why every decay here is timed in seconds, not blocks

The contracts​

Production addresses​

Deployed from commit 3dc07eb at block 69,454,565 on chain 4663, and verified read-only at block 69,459,976 on 2026-09-22. All six carry a Sourcify creation and runtime match (not exact_match); Blockscout source display and Uniswap routing approval are separate checks that do not follow from it.

contractaddress
HedgeFunFactory0x58F6Ced8d02cD2567f1458801440Bc4eb67fA961
HedgeFunHook0x2A16d0973385952cFBE750D37f803d0958472844
TradingCalendar0xFE9E85f0C258Fc2757eB6Acd1ca032Ec860487F5
HedgeFunLaunchRouter0x470F5DeB0897118F6575F72183781C6a0610E1FA
TreasuryDeployer0x05BC7875a7d61C3bbA2D7737D40C81aF5fD10DBE
TokenDeployer0x9C0440dCc1b651C4707aa44E0eA083Fa4E0E8A6b
HedgeFunTradeRouter0xb281F7D91325A3A386A00cA0F6010BC8B1491c8C

owner, protocol and the calendar's owner are all the same Safe: 0x2910117dd2cB431173Ae9Fb6eAF30726321d1693, 3-of-4, with pendingOwner zero.

Listed stocks​

Twelve, listed by the owner, each opening around a $10k FDV. A listing fixes the oracle and the V3 pool a creator cannot choose:

listings(stock) -> (oracle, pool, openingPrice)
bandCeiling(stock) -> the most staleness band a creator may pick, in bps/hour

Verified on chain 2026-09-22. Open price is openPriceE18, stock per token; the last column is the band ceiling.

stockstock tokenprice oracleopen price · band
NVDA0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC0x03c77f527Aa1B0B304602e3fB9Ac994dd1c157f844200000000 · 0
SPCX0x4a0E65A3EcceC6dBe60AE065F2e7bb85Fae35eEa0xC109426706b9D01719ED82e8cd027fA91fBcdC0b65600000000 · 0
CRCL0xdF0992E440dD0be65BD8439b609d6D4366bf1CB50x3bd2c093948D38A5eC2D945C5b065e5Db89aaB36109000000000 · 10
GOOGL0x2e0847E8910a9732eB3fb1bb4b70a580ADAD4FE30x15400359B0D14B4151FAe80b837abF3fA197725628000000000 · 0
AMZN0x12f190a9F9d7D37a250758b26824B97CE941bF540xb34d278D2c792B7C48252C5eB8130Db45e35294e38500000000 · 5
GME0x1b0E319c6A659F002271B69dB8A7df2F911c153E0x7548A343D06E45507Dd8F546D9d9Fdf684575ecE423000000000 · 5
META0xc0D6457C16Cc70d6790Dd43521C899C87ce02f350x699E34068b8975bE113eD5fF12e429c69BCf101113400000000 · 5
USAR0xd917B029C761D264c6A312BBbcDA868658eF86a60x02dE419166CED89fc9FCe2687CdBcBbc9eDe2612596000000000 · 5
MSTR0xec262a75e413fAfD0dF80480274532C79D42da090x19d0328F3152d1361db7B3Dd7708Cc36A779d61261100000000 · 0
AMD0x86923f96303D656E4aa86D9d42D1e57ad2023fdC0xc809bDf7E31E4830de2b03e6f809869Fb99f224616300000000 · 0
MU0xfF080c8ce2E5feadaCa0Da81314Ae59D232d4afD0x4D15A4A1028f001800774A3d2DC31d77945399a49620000000 · 0
INTC0xc72b96e0E48ecd4DC75E1e45396e26300BC396810xd399113f3196044A001614Ca9dda9cD8c942426482700000000 · 0

The V3 pool comes back from the same listings call — NVDA's is 0xD4EB21209c4d6093F80B5b84f5C45cC093eA14A3 — and a creator may not substitute either leg.

publicLaunch reads true and strategyCount reads 1. Read both live rather than hard-coding a state.

Launches​

Platform test with a failed launch setup. CRCLGRID launched without two-sided liquidity or an initial USDG treasury reserve. Its strategy may remain inactive indefinitely if no lot reaches the first take-profit level and no reserve is added. See the launch postmortem.

CRCLGRID — Hedgefun CRCL Range Grid
token0xF5501c0D85992dD59371e15e3e7b60654ebaF332
treasury0xc21873529515990C80BACe0931141e6B9D5A4fe0
stockCRCL, 0xdF0992E440dD0be65BD8439b609d6D4366bf1CB5
V4 pool id0xfe98797b4dc2e5008712f812f3d90acba5adb216f8aa32e412fa377fb90b0b64
pool keycurrency0 CRCL, currency1 the token, fee 0, tickSpacing 60, hook 0x2A16d097…2844
launch tx0x9a0c0240e9d2172440b70968294896a2b236e42ebf717fe781262b5666a1ca82, block 69,523,800
ruletp1 2000, tp2 4000, dip 1500, stop 0, lotBps 2000, bandBpsPerHour 10
rates, 2026-09-22buyRateBps 1000, sellRateBps 1000 — the flat rate, both windows expired

Enumerate the rest from strategies(i) for i < strategyCount(): each entry is (token, treasury, hook, stock, creator).

What each contract is for​

contractwhat you call it for
HedgeFunFactorypredict(request) for a quote and its hash, launch(request, terms) to launch, and the listings a creator may pick from
HedgeFunHookone instance for every launch, state per pool id. The live tax rates, the split, and the tax events
HedgeFunTokenthe token, plus its page — logo(), description(), socials(), getTokenInfo(), with pons' reader names and selectors, so a tool written for a pons token reads this one unchanged
HedgeFunTreasurylots, the reserve, and health()
HedgeFunLaunchRouterlaunch + the creator's first buy + the treasury's first lot, in one transaction
HedgeFunTradeRouterUSDG ↔ a launch's token in one transaction: the V3 hop, all-or-nothing, then the V4 pool
PriceOracle, TradingCalendarthe stock's price in USDG, and the 24/5 exchange calendar it consults

The ABI bundle lives in abi/ in the contracts repo, next to a generated surface listing. Generate it against whatever commit is actually deployed: the take-profit fields widened to uint32 in 09f42b4, which changed the launch, launchWithMetadata and predict selectors.

Launching​

A launch takes a request and terms — the hash predict(request) returned, which is the launcher's commitment to everything they were quoted. If a listing, a default or a fee moved in between, launch reverts rather than going through at the new one.

fieldwhat it is
name, symbolthe token's
stocka stock the factory already lists. A creator-supplied address is refused: a creator-supplied oracle is a creator-controlled price
creatorreceives the creator's share of the stock-denominated sell tax, forever. Must be an address that can call vetoCreator — an EOA or a Safe, not a splitter
taxBps, creatorBpsthe tax and the creator's cut of it, both bounded by the factory
tp1Bps, tp2Bpsthe two take-profit levels, uint32 and uncapped — surface what a creator actually set, however large
dipBpshow far under the last sale the USDG reserve re-buys
stopBpsoptional stop. 0 means no stop, and every lot then sells above its own cost
lotBpsthe lot size the rule works in
bandBpsPerHourthe staleness band — see below. Legal range is 0..bandCeiling(stock), which is 0 until the owner sets it, and the contract bounds it again at 200. Frozen into the treasury at birth

Launch fee, optional, in one of three currencies: the native gas token (straight through, no swap), USDG, or the same stock being launched against — so a creator holding only NVDA never has to touch USDG. A stray msg.value on a non-native fee reverts rather than being kept.

launchWithMetadata also writes the token's page in the same transaction. The page belongs to the launching address, which may appoint one editor and may lock() it for good; the protocol has no power over it.

Quoting a trade​

Read the live rate. In a pool's first seconds a buy can pay up to 99%, and a sell can pay a spiked rate after every buy-back:

buy → hook.buyRateBps(poolId) // 99% → 66% → 33% → flat over the first 3 seconds
sell → hook.sellRateBps(poolId) // spiked at launch and after each buy-back, decaying to flat

A quote that shows the flat rate during those windows is wrong by up to 99 percentage points. Show the rate the hook returns, and show that it is decaying.

Other rules that change what you can offer:

  • Sells are exact-input only.
  • Exact-output is accepted for a buy at the flat rate only, taxed on the stock going in and grossed up so the route costs the same. Anything else is refused.
  • The launcher's own buys inside the launch transaction are exempt from the window, with no cap on size or count. Render them in a launch's early history rather than averaging them away.
  • Show first-buy concentration on every token — how much of the supply the launcher took in the launch transaction. It is the single number that tells a buyer how much of the float is still out there.

The staleness band, and how to ask for it​

The band widens how far spot may sit from the last Chainlink print before health() closes — maxDeviationBps + bandBpsPerHour × feedAgeHours, capped at 3000 — and the trade still executes against the oracle-derived bound.

Read bandCeiling(stock) and branch, rather than always rendering the field:

  • Ceiling 0 — seven of the twelve listings today — the only legal value is 0. Skip the field and say the treasury follows Chainlink and keeps market hours.
  • Ceiling above 0 — a slider from 0 to the ceiling, defaulting to the ceiling. Tighter is stricter, and 0 is a legitimate choice that trades only in market hours.

A wider band buys tolerance rather than a better price: the trade still executes against the oracle-derived bound, and the extra hours it opens are closure hours. Either way, label it frozen at launch — set once, by the creator, for the life of the treasury.

Reading a launch​

viewwhat it tells you
lotCount()how many lots the rule is carrying
reserveUsdg()the dip-buying reserve
unbookedStock()stock that has arrived but is not yet costed — anyone may call book()
health()whether the treasury can price and trade right now, and at what price

Read health() before showing a launch as trading. It is true when the feed is fresh within the band, the token's oraclePaused() is clear, the calendar says the market is open, and the pool agrees with the oracle inside the execution gate. The treasury trades on a price it can verify, by construction — while its token keeps trading all week.

Running a treasury, and getting paid​

The treasury has no keeper and no privileged caller. The five writes below are open to anyone, they check their own triggers against the oracle, and each pays the caller bountyBps of what that call produced — 50 (0.5%) as shipped, 200 (2%) at the contract's ceiling, read it from params().

calldue whenpays youreverts with
book()stock has arrived and the oracle is livenothing — it returns false instead of reverting(never; returns a bool)
takeProfit(id)p reached cost + tp1, then cost + tp2a cut of the profit, in the stockNotDue, Unhealthy
stopLoss(id)the creator set a stop and p fell to ita cut of the proceeds, in USDGNotDue, Unhealthy
buyDip()p fell dip under the last sale, and the spend clears minLotUsdga cut of what was spent, in USDGNotDue, Unhealthy
buyback()the treasury holds profit and the cooldown has passeda cut of the tokens bought, in the tokenNotDue, Cooldown, Unhealthy
hook.sweep(poolId)tax has accrued on a poolsweepTipBps of what the sweep distributes—

takeProfit calls book() for you first, so a separate book() is only worth sending when nothing else is due and you want the lot costed at today's price.

Finding work​

for i in 0 .. factory.strategyCount()-1:
(token, treasury, hook, stock, creator) = factory.strategies(i)
(ok, p) = treasury.health() # false → nothing but buyback can fire
params = treasury.params() # tp1Bps, tp2Bps, dipBps, stopBps, lotBps, bountyBps …
for id in 0 .. treasury.lotCount()-1:
(qty, cost, half, tp1Left) = treasury.lots(id)
# tp1 is due at cost*(1+tp1Bps/1e4) while `half` is false, tp2 at cost*(1+tp2Bps/1e4) after
# stop, if stopBps != 0, at cost*(1-stopBps/1e4)
treasury.unbookedStock() # > 0 → book() has work
treasury.reserveUsdg() # buyDip spends lotBps of this

Simulate before you send. NotDue is the normal answer, not an error: an eth_call costs nothing and tells you whether the transaction would earn anything.

What bounds a call​

  • One call is one chunk. takeProfit and stopLoss offer at most sellChunkUsdg at the rule's price, and buyDip spends lotBps of the reserve. A lot that is larger than a chunk takes several calls, each paying.
  • A sale fills as far as the oracle price less the slippage limit allows, and every effect — the lot, the event, your bounty — is sized from what actually filled.
  • buyback() has a cooldown (buybackCooldown, 60s as shipped) and prices itself off the token pool's own ten-minute TWAP, so it keeps working through a weekend when the equity feed is frozen.
  • buyDip() takes the bounty off the spend, not off the ask, so what you earn tracks what the treasury actually bought.

Pricing​

A launch pool's price is the token in the stock, not in USDG. To show a USDG price or a market cap, multiply by the stock's own oracle price.

price_usdg = price_in_stock × oracle_usdg(stock)
market_cap = price_usdg × (total supply − burned supply)

Two things to read from chain rather than assume:

  • Token ordering. Which side of a pool is token0 is not a constant across this chain's stock pools. Assuming one ordering produces a near-zero number with no error, which reads as "no liquidity" rather than as a bug. It has shipped twice.
  • The seeded range. The launch position is one-sided, from just above the opening tick to the top of the usable range, so progress along it is computed from the pool's current tick. There is no graduation event to listen for, because nothing migrates.

Computing the three figures​

A front end shows market FDV, the stock sitting in the pool, and what the treasury holds. They come from three different places, and each has a lookalike that returns a confident number instead of an error.

FDV = poolPrice(token in stock) × supply × oracleUsdg(stock)
^ marginal price, not an average, and not what a sale would realise
^ say which supply: issued, or issued less burned — and subtract the burn once
^ the opening FDV is stock-denominated: supply × listings(stock).openPriceE18
NVDA at launch = 1e9 × 4.42e-8 = 44.2 NVDA, which is a dollar figure only
after you multiply by the stock's own price

pool reserve = the stock held by THIS pool, from the pool's own state
✗ balanceOf(PoolManager) — V4 keeps every pool's balances in one contract,
so that address holds the whole chain's stock, not this pool's
the token side is reported as a count, beside it, never valued at its own
marginal price and added in

treasury = stock + USDG the treasury address holds, split into principal,
realised profit, and what is free for the next buy-back
✗ principal + realised + budget summed — they are stages of one pile
✗ treasury ÷ supply presented as a redemption value — there is no redemption
✗ pool reserve + treasury — different pots, different owners

Three display rules that follow from this:

  • An unread number is "not fetched", never 0. Zero is a fact about a balance; a failed read is a fact about your connection.
  • Every figure is its own read — a reserve comes from the pool, never from FDV or from whatever else is in hand.
  • Carry provenance: which price, read when, and whether it is stale. Feeds are 24/5, so a stale read on a weekday evening is the normal state and should be labelled.
  • Show first-buy concentration wherever a token is listed.

Events​

Event topics and decoding examples are published here with the addresses. The paths worth indexing are the launch itself, the hook's tax split on each swap, and the treasury's book / takeProfit / stopLoss / buyDip / buyback steps — together they reconstruct every lot without needing our API.

Support​

[email protected], or @0xHedgehood.

This is an interface, not investment advice. See the Terms of Use.