Contract map
Everything an indexer needs to pick up every token launched on hartiilabs.com, on one page.
New launches now go through a fourth-generation factory (V4, live 2026-10-02), so index all three
factories. Every address below returned bytecode from quai_getCode and every event topic was
matched against real logs on Quai mainnet (chain 9, Cyprus-1) at block 10366996 (2026-09-30);
the V4 addresses were confirmed at block 10407813 (2026-10-02).
1. Index these three factories
All three factories emit the same TokenLaunched event, so one handler covers them all. V1 and V3
still accept launches — keep indexing them.
| Factory | Address | Index from block | Status |
|---|---|---|---|
| TokenFactoryV4 (LP Reserve) | 0x005566187B52313e03978C2caF4BE1a0A88eb90A | 10407724 | Live since 2026-10-02 — every new launch from hartiilabs.com |
| TokenFactoryV3 | 0x00249722868732Ee678b88Db668EAf7cC75Ae12A | 10356575 | Live — hartiilabs.com's default from 2026-09-29 to 2026-10-02; its tokens trade on unchanged |
| TokenFactory (V1) | 0x001AF1BbB40807fcb99C9Eeaa49dF5E91e7Efd42 | 8872950 | Live — the original factory |
2. Events
topic0 is keccak256 of the signature.
| Event | Emitted by | topic0 |
|---|---|---|
TokenLaunched(address indexed token, address indexed curve, address indexed creator, string name, string symbol, bytes32 metadataHash) | V1, V3 and V4 factory | 0x57e2b1dd3b3baad37496efb283e2935bc1cfedc331530404a4530514e5e71356 |
LaunchConfigured(address indexed token, uint256 vestingDurationSecs, uint256 lockStartDelaySecs, uint256 creatorFeeShareBps, uint256 treasuryFeeShareBps, uint256 snipeWindowBlocks, bool autoBuyback) | V3 and V4 factory | 0x87811f92b40333fcc295e685f06b34bc066187e283798479a0ab372528df5b2a |
Buy(address indexed buyer, uint256 quaiIn, uint256 tokensOut, uint256 fee) | each token's curve | 0xbeae048c6d270d9469f86cf6e8fedda3c60ad770f16c24c9fc131c8e9a09101d |
Sell(address indexed seller, uint256 tokensIn, uint256 quaiOut, uint256 fee) | each token's curve | 0x846c37eef631e0943682d87352ec117c20008eb7f425c9b85ac011a6d4774cc0 |
Graduated(address indexed token, uint256 quaiReserve, uint256 tokenReserve) | each token's curve | 0x1c858049e704460ab9455025be4078f9e746e3fd426a56040d06389edb8197db |
LiquidityAdded(address indexed provider, uint256 quaiIn, uint256 tokensIn, uint256 shares) | V3 curves after graduation | 0x64b83944e79c3ce8d4c297411de637c3e102d064677aac0c163976ebdcd6f50e |
LiquidityRemoved(address indexed provider, uint256 quaiOut, uint256 tokensOut, uint256 shares) | V3 curves after graduation | 0x1dc8bb69df2b8e91fbdcbfcf93d951b3f0000f085a95fe3f7946d6161439245d |
3. How a token trades
- Launch. The factory emits
TokenLaunched.tokenis a plain ERC-20 with 18 decimals;curveis where it trades. Both are EIP-1167 clones of the implementations in section 5. - Bonding curve. Buys and sells hit the curve and emit
Buy/Sell. The curve holds the QUAI reserve. - Graduation.
Graduatedfires when the curve fills. The same curve contract then becomes the token's pool:Buy/Sellkeep firing from the same address, so there is no new venue to discover. V3 curves also take LP deposits after graduation (LiquidityAdded/LiquidityRemoved). - Optional HartiiSwap pair. Some tokens also have a Uniswap-V2-style pair on HartiiSwap
(section 4). Resolve it with
factory.getPair(token, WQUAI)— pairs areCREATE-deployed, so there is no init-code hash to compute.
4. HartiiSwap
A Uniswap V2 port, live since 2026-09-23. Pairs emit the standard V2 Mint, Burn, Swap and
Sync events; the factory emits PairCreated. More in HartiiSwap.
| Contract | Address |
|---|---|
| Factory | 0x002E75653C6189087Eb9E512cE7319eC21140956 |
| Router | 0x006B3450cca780066A3A8aA8b508103d25315Ea4 |
| Lens (read helper) | 0x00295dFCA930646abAC327C9CcB2f4e1E206C5Ec |
| WQUAI | 0x006C3e2AaAE5DB1bCd11A1a097cE572312EADdBB |
5. Implementations
For source verification — every launch clones these.
6. Other live HartiiLabs contracts
Not needed for token indexing.
| Contract | Address | From block | Status |
|---|---|---|---|
| LpLocker (time-locks LP, max 90 days) | 0x00276419b3aa2E7d034D2d54d52b59BdfFF4e60E | 10341499 | Live |
| AgentVaultFactory | 0x006C2be96D6Ca90d0105a2Bfa7aC2187f40e899d | 10341473 | Live — see Agent Terminal |
| HartiiProfiles | 0x0015f71de1574c772B6815D25B233C065f42c896 | 10341682 | Live |
| LpArena v2 | 0x00614295C6AC13d3B7d93844b9BacC61a7680820 | 10351500 | Live |
| LpArena v1 | 0x0075B00Ca0313f88b0825BE62bBFB890c9F4C03F | 10341703 | Deprecated — unstake only |
| MiningVaultFactory v2 | 0x0024596369Fc22A22b720B0A959630913d8D680b | 10342308 | Live |
| MiningVaultFactory v1 | 0x0059f740fb9AD9F2Db19DA5Dac3b71bF6BD6B68c | 10341712 | Abandoned — never used, do not integrate |
| AchievementRewards | 0x001d607B22de6ACcFB4adEE62838DED222Aa0c8a | 10352297 | Live |
| QuaiRelay | 0x0031B09e63592B713768761cdDACC603974c10bD | — | Live — see QuaiRelay |
7. LP Reserve (TokenFactoryV4 / BondingCurveV4) — live on mainnet
Every V4 launch reserves 3% of its supply (lpReserveBps = 300, read live from
TokenFactoryV4.lpReserveBps()) as a protocol-owned bucket, carved off before the creator / curve /
migration split. Nothing happens to it before graduation. When the token graduates, the whole
reserve streams to real liquidity providers in proportion to their LP shares, linearly over
56 days (lpReserveStreamSeconds = 4838400). Rewards are paid in the launched token. LPs can
claim them at any time with no expiry, and claiming never locks LP funds. V4 also works out
virtualTokenReserve per launch, so the pool opens at exactly the curve's last price whatever the
creator allocation is. Owner setters only change these numbers for future launches. A live curve
keeps the values it launched with. Design rationale: docs/design/lp-reserve-2026-09-30.md in
the hartii-labs repo.
| Contract | Address | Notes |
|---|---|---|
| TokenFactoryV4 | 0x005566187B52313e03978C2caF4BE1a0A88eb90A | Deployed block 10407724. Creation fee 5 QUAI, graduation 25,000 QUAI net raised. |
| LaunchToken implementation (V4) | 0x007a8Fc000eB5D353b1f3c5C7019efeAAa3d5D03 | Same bytecode as LaunchTokenV3. |
| BondingCurveV4 implementation | 0x0049Ba9169F36a18b4a190AE057Ad69Ef8eDf75e | Clone target for V4 curves. Buy / sell / LP ABI unchanged from V3; sells need an ERC-20 approve to the curve first. |
V4-only events (in addition to every V3 event, which is unchanged):
| Event | Emitted by | topic0 |
|---|---|---|
LpReserveConfigured(address indexed token, uint256 lpReserveTokens, uint256 lpReserveStreamSeconds) | V4 factory, at launch | 0x112337f0e3b9bacb1cfaed29b8f0dc4e971d82b2c0a30d2cc9e80e2e941755c5 |
LpReserveStreamStarted(uint256 rewardRate, uint256 periodFinish, uint256 lpReserveTotal) | V4 curve, at graduation | 0xbd0a41a511264ef937cf1a0914883798b1c0984bd6920ac3eb72e61cba4ce9b9 |
LpReserveRewardClaimed(address indexed account, uint256 amount) | V4 curve | 0xbe9bfd96b705f3a9977d024b0db3388eeb5d13881c48615f09ab395d5a275cd7 |
LpReserveOrphanedSwept(uint256 amount) | V4 curve | 0x92c2bc4c57c9d8c40362fd46277a2035dc8777ea6a8e543fb97cf329d4dd0d43 |
Read functions on a V4 curve: lpReserveTotal(), lpReserveRemaining(), rewardRate(),
rewardPeriodFinish(), earnedLpReserve(address). Write: claimLpReserveRewards().
sweepOrphanedLpReserve() is permissionless. It burns only the reserve that accrued while there
were zero real LPs, which nobody can ever claim, and it never touches an accrued claim.
8. Shortcuts
- If you'd rather not scan logs:
GET https://hartiilabs.com/api/tokenslists every indexed token, andGET https://hartiilabs.com/api/token/<address>returns one token with its curve address. See the API reference and how the indexer works. - When scanning yourself: Quai's
quai_getLogsrejects ranges over 10,000 blocks, so page through in windows of 10,000 blocks or fewer.