Pre-launch. The protocol is not publicly live yet. This documentation describes the contracts as implemented; deployed addresses are published at launch.

GraduationManager

The Gnosis equivalent of PrimaryHook. Uniswap V3 has no hook mechanism, so fees must be collected explicitly and the distribution logic differs — but the external surface is deliberately close to the V4 hooks.

Contract Type

Singleton — Gnosis only. Manages WNATIVE/token V3 pools at the 1% fee tier. No owner, no admin keys. There is no secondary pool on this chain.

Economic invariant

Token-side LP fees are never sold to the market. The deployer (40%) and protocol (20%) cuts come exclusively from native-side fees. Token-side fees are bucketed in pendingTokens and either burned or paired back into liquidity. Buy-and-burn genuinely buys tokens, reducing supply — the inverse of selling — so it does not violate this.

Pool Lifecycle

preInitializePool(token: address) external

Initialize the V3 pool atomically with token deployment. Called by BondingCurveTemplate.initialize(), itself called by the factory inside deploy_pair.

This closes the V3 pre-init griefing window: a frontrunner who already initialized the pool at a different price causes this to revert, which reverts the whole deployment. The deployer retries with a fresh salt.

Emits

PoolPreInitialized(token, pool, sqrtPriceX96)

createPositionAndRegister(token: address, deployer: address) -> uint256 external payable

Callable only by a factory-registered curve. Wraps the native asset, re-reads slot0 and asserts the price still matches the expected value as defense in depth, then mints a full-range position. Excess native and residual WNATIVE go to protocolBalance.

Reverts
  • "Only a factory curve may graduate"
  • "Already registered"
  • "Invalid deployer"
  • "Insufficient graduation funds"
  • "Pool sqrtPrice mismatch" — pool was re-initialized at a different price
Emits

TokenRegistered(token, deployer, positionId)

Fee Functions

collectFees(token: address) external

Pull accrued V3 fees out of the position into the contract's buckets. Anyone can call. This step has no V4 equivalent — there, fees arrive through the swap callbacks.

  • Native side → unwrapped, then pendingFees[token] (or protocolBalance for $LP24)
  • Token side → pendingTokens[token], above the dust threshold

There is no dust threshold on the native side — dropping sub-threshold collections would leak native into untracked contract balance.

Reverts
  • "Not registered", "No position"
Emits

FeesCollected(token, nativeAmount)

distributeFees(token: address) external

Split collected native fees 40 / 20 / 40 and process the token bucket. Anyone can call. Pool state is read and validated before any state change, so the failure mode is deterministic across both paths.

The processed chunk is capped at max_safe × 9/4 so the reinvest swap stays inside the MEV-safe band. Only the processed chunk is split; the remainder carries forward un-split so it is never taxed twice.

DEEP path — pool ≥ 48,000,000 × 10⁹ (48M tokens)
  • Burn all pending tokens outright
  • Buy-and-burn the entire reinvest budget — no LP'ing
THIN path — pool below threshold
  • Pair pending tokens with the reinvest budget into liquidity
  • Burn excess tokens; run leftover native through buy-half-and-LP
Reverts
  • "Nothing to distribute" — at or below dust
  • "No position"
  • "Pool not initialized"
  • "Pool too thin for any safe swap"
Emits

FeesDistributed, and some of TokensBurned, TokenFeesLPed, BuyAndBurn, Reinvested

processProtocolFees() external

Process the protocol balance against the $LP24 pool, using the same DEEP/THIN logic. Anyone can call.

withdrawDeployerFees(token: address) external

Deployer only. Same semantics as the V4 hook.

creditProtocolBalance() external payable

Accept a protocol share from a bonding curve's refund or sweep.

CTO

initiate_cto_vote, finalize_cto and cancel_failed_cto behave identically to the V4 hook, including the state-first best-effort transition in _changeDeployer. The vote fee on Gnosis is 24 xDAI.

View Functions

FunctionReturns
getTokenInfo(token) -> TokenInfo(deployer, positionId)
getPendingFees(token) -> uint256Native fees awaiting distribution
getPendingTokens(token) -> uint256Token-side fees awaiting burn-or-LP
getDeployerBalance(token) -> uint256Withdrawable deployer balance
isTokenRegistered(token) -> boolWhether the token graduated
canDistribute(token) -> boolWhether distribution would succeed now
canProcessProtocolFees() -> boolWhether protocol processing would succeed now
getPoolLiquidity(token) -> (uint128, uint160, int24)(liquidity, sqrtPriceX96, tick)
getPoolAddress(token) -> addressThe V3 pool contract for this pair
getFeeInfo(token) -> (uint256, uint256)Fee bps and native depth
getSlippageInfo(token, swap_amount)Expected slippage figures for a hypothetical swap
getMaxSafeSwap(token) -> uint256The current MEV-capped swap ceiling
canInitiateCTO(token) -> boolRegistered, no active vote
getActiveCTOVote(token) -> addressCurrent vote contract, or zero
getCTOVoteCount(token) -> uint256Attempts to date

Constants

ConstantValue
POOL_FEE10000 (1% V3 tier)
GRADUATION_NATIVE9,600 xDAI
GRADUATION_TOKENS400,000,000 × 10⁹ (400M)
DISTRIBUTE_THRESHOLD96 xDAI
PROTOCOL_THRESHOLD240 xDAI
POOL_DEPTH_THRESHOLD48,000,000 × 10⁹ (48M tokens)
SLIPPAGE_TIER_1_BPS480 bps (4.8%)
CAP_MULT_BPS100 — 1.00× the pool fee, so the cap is 1%
CTO_VOTE_FEE24 xDAI
CTO_INITIATOR_STAKE60,000,000 × 10⁹ (60M, 5% of supply)
MIN_TOKEN_DUST1,000,000
INITIAL_SQRT_PRICE511415589947267542714504636

Gnosis has one static fee tier, so the MEV cap is a flat constant rather than being derived from a live tier read. Break-even still sits at roughly one fee tier, since an atomic sandwich pays two legs of it.