Skip to main content

Overview

GeodeHook.sol is the entire Geode protocol in a single contract (~1,190 lines). It implements the Uniswap v4 IHooks interface and IUnlockCallback, intercepting swaps via beforeSwap and providing batch settlement through geodeSettleBatch(). Hook flags: BEFORE_SWAP | BEFORE_SWAP_RETURNS_DELTA

Immutables

IPoolManager public immutable poolManager;    // Uniswap v4 PoolManager
ISignatureTransfer public immutable permit2;  // Canonical Permit2 contract
address public immutable protocolTreasury;    // Receives ~1/3 of direct swap fees
address public immutable factory;             // GeodeFactory — authorized to register launches

Constants

uint256 public constant CURVE_RESERVE_FEE_SHARE_BPS = 3334; // ~1/3 of fee → curve ETH reserve
uint256 public constant PROTOCOL_FEE_SHARE_BPS = 3333;      // ~1/3 of fee → treasury
// Remainder (~1/3) → surplus pool

State Variables

mapping(PoolId => PoolConfig) internal _poolConfigs;      // Per-pool configuration
mapping(PoolId => bool) public poolInitialized;           // Configuration flag
mapping(PoolId => uint256) public lastSettledBlock;       // Batch interval enforcement
mapping(PoolId => BatchState) internal _currentBatch;     // Current batch tracking
mapping(PoolId => uint256) public surplusCurrency0;       // Accumulated surplus (token0)
mapping(PoolId => uint256) public surplusCurrency1;       // Accumulated surplus (token1)
mapping(PoolId => LaunchState) internal _launchStates;    // Permanent curve state
mapping(PoolId => uint256) public launchTokenReserve;     // Token reserve for curve dispensing
mapping(PoolId => uint256) public launchEthReserve;       // ETH reserve from curve sales

External Entry Points

geodeSettleBatch()

The main settlement function. Permissionless — anyone can call it and earn rewards.
function geodeSettleBatch(
    PoolKey calldata key,
    GeodeIntent[] calldata buys,
    GeodeIntent[] calldata sells,
    bytes[] calldata buySignatures,
    bytes[] calldata sellSignatures
) external
Flow:
  1. Validate pool is configured and batch interval has elapsed
  2. Validate all intent bindings (poolId, deadlines)
  3. Compute clearing price and determine fills (phase-aware: curve vs standard)
  4. Update batch state, emit GeodeIntentFilled events
  5. Call poolManager.unlock() → enters flash accounting context
  6. Inside unlockCallback():
    • Pull tokens from each user via Permit2
    • Route residual through AMM (standard) or bonding curve (curve mode)
    • Distribute outputs pro-rata to filled intents
    • Pay settler (fees + gas reimbursement)

beforeSwap()

Hook callback intercepting every swap on configured pools.
function beforeSwap(
    address sender,
    PoolKey calldata key,
    SwapParams calldata params,
    bytes calldata
) external onlyPoolManager returns (bytes4, BeforeSwapDelta, uint24)
Behavior:
  • If sender == address(this) (hook routing residual): no fee, pass through
  • If pool is an Active curve pool: _curveDirectSwap() — the hook computes the bonding curve output, charges 0.3% split three ways (reserve, treasury, surplus), and returns the full delta. The AMM processes nothing.
  • Otherwise (standard pool): charge directSwapFeeBps on the swap amount — ~1/3 → treasury, ~2/3 → surplus
Curve direct swap delta accounting: The hook absorbs the entire swap through BEFORE_SWAP_RETURNS_DELTA:
  1. Takes the user’s input from the PoolManager
  2. Computes curve output via ConstantProductCurveLib
  3. Provides output to the user
  4. Returns a BeforeSwapDelta that fully satisfies the swap

geodeInitializePool()

One-time pool configuration. Curve pools (with deployer set) require the factory as caller.
function geodeInitializePool(
    PoolKey calldata key,
    PoolConfig calldata config
) external

registerLaunch()

Called by the factory to register permanent curve state. Sets up LaunchState with virtual reserves and token tracking.

Internal Functions

_curveDirectSwap()

Handles direct swaps on curve pools — the core of the permanent curve architecture:
  1. Validates exactInput only (positive amountSpecified reverts)
  2. Computes 0.3% fee, split three ways:
    • Reserve fee (3334 bps) → added to launchEthReserve / launchTokenReserve
    • Protocol fee (3333 bps) → sent to treasury
    • Surplus fee (remainder) → accumulated in pool surplus
  3. Computes curve output from net input
  4. Updates cumulativeSupplyDistributed, reserves, and token balances
  5. Returns BeforeSwapDelta that fully absorbs the swap
  6. Emits GeodeCurveSwap event

_computeSettlement()

Phase-aware routing:
  • Active curveConstantProductCurveLib.computeLaunchSettlement()
  • StandardClearingPriceLib.computeClearingPrice()

_routeAndDistribute()

Standard mode: routes residual through poolManager.swap(), then distributes outputs.

_routeAndDistributeLaunchMode()

Curve mode: dispenses/absorbs tokens via bonding curve. Updates launchTokenReserve, launchEthReserve, and cumulativeSupplyDistributed.

_paySettler()

Pays the settler:
  1. Settlement fees from unrouted input deposits via poolManager.take()
  2. Gas reimbursement from surplus via _fundSettlerFromSurplus() (capped at maxGasReimbursement)
Emits SettlerPaid with exact per-currency breakdown.

_distributeBuyOutputs() / _distributeSellOutputs()

Pro-rata distribution using each intent’s amountIn as weight. Remainder dust goes to the last filled intent.

View Functions

function getBatchState(PoolId) external view returns (BatchState memory);
function getPoolConfig(PoolId) external view returns (PoolConfig memory);
function getSurplusCurrency0(PoolId) external view returns (uint256);
function getSurplusCurrency1(PoolId) external view returns (uint256);
function getLastSettledBlock(PoolId) external view returns (uint256);
function canSettle(PoolId) external view returns (bool);
function getLaunchState(PoolId) external view returns (LaunchState memory);
function getLaunchMetrics(PoolId) external view returns (
    uint256 currentPriceQ96, uint256 marketCap, uint256 fdv,
    uint256 ethRaised, uint256 circulatingSupply
);

Events

EventWhen
GeodeBatchSettledBatch settlement completes
GeodeIntentFilledEach filled intent
SettlerPaidSettler receives payment (per-currency breakdown)
GeodeCurveSwapDirect bonding curve swap executed
GeodeDirectSwapDirect swap fee charged (standard pools)
GeodeProtocolFeeCollectedProtocol treasury receives fee share
GeodePoolConfiguredPool configured for batching
GeodeLaunchedLaunch token registered
GeodeDeployerRoyaltyPaidDeployer royalty paid from surplus

Source

GeodeHook.sol

View the full source code on GitHub (~1,190 lines).