Skip to main content

DLMM Contract Architecture

Ramses DLMM is an LFJ v2.2-style Liquidity Book implementation integrated with Ramses fee routing and optional voter-directed rewards.

Contract map

Factory

Pool identity

There is at most one pool for an unordered token pair and bin step. The factory sorts tokens for storage, but initialization preserves the supplied tokenX and tokenY order. Key reads:
Pools are deterministic immutable clones. Updating getLBPairImplementation() changes the implementation used for future pools; it does not upgrade an existing clone.

Creation constraints

createLBPair(tokenX, tokenY, activeId, binStep) requires:
  • An existing preset for binStep
  • An open preset unless the caller is the factory owner
  • A whitelisted tokenY quote asset
  • Distinct, non-zero tokens
  • No existing pool for that token pair and bin step
  • A valid active-bin price
The LBPairCreated event is the canonical discovery event.

Mutable configuration

The factory owner controls:
  • Preset parameters and whether a preset is open
  • Fee parameters on an existing pool
  • Pool protocol share
  • Quote-asset membership
  • Routing-ignore state
  • Hook installation and removal through the hook-manager role
  • Fee recipient and flash-loan fee
  • Forced volatility decay
  • The implementation used for future pools
The owner or configured Voter may change an existing pool’s protocolShare.

Pool

Core reads

getReserves() reports pool reserves net of accrued protocol fees. getBin(id) reports the token reserves assigned to one bin.

State-changing entrypoints

These core functions are low-level. swap() relies on pre-transferred input and mint() expects packed liquidity configurations. Public integrations should normally use DLMMRouter.

LP share behavior

Each bin ID has independent balanceOf() and totalSupply() accounting. Initial shares are derived from the square root of bin liquidity; later deposits mint proportionally to the bin’s existing reserves and supply. DLMMToken is ERC1155-like, but:
  • It does not call receiver hooks
  • It has no URI surface
  • Operator approval for all bin IDs uses approveForAll()
  • A linked rewarder hook can disable batch transfers
Burning requires the holder or an approved operator. The reviewed pool contracts do not expose an administrator function that withdraws arbitrary user LP principal.

Router and quoter

DLMMRouter is the intended safety boundary for end-user transactions. It adds:
  • Deadlines
  • Token and active-ID slippage checks
  • ERC20 and native-asset handling
  • Refund routing
  • A caller-only LP recipient check on public add-liquidity functions
  • Exact-input and exact-output swaps
  • Fee-on-transfer swap variants
  • Batched per-bin liquidity operations
The router’s current executable path version is V2_1. Its V1 and V2 enum members are compatibility placeholders. DLMMQuoter evaluates every registered, non-ignored bin-step candidate for a hop and returns the best complete fill. It catches failing candidates, so callers must still verify that every selected pair and amount is non-zero.

Fees

Pool static parameters are:
The base fee scales linearly with baseFactor × binStep. The variable fee scales quadratically with volatilityAccumulator × binStep and is capped. The maximum total swap fee is 10%. protocolShare is measured out of 10,000 and applies to the swap fee, not to trade notional:
The remainder stays in bin reserves and compounds into LP share value. DLMMFeeCollector.collectProtocolFees(pool):
  1. Pulls the pool’s accrued protocol fees
  2. Sends them to treasury if no live rewarder exists
  3. Otherwise applies its configured treasury skim and notifies the rewarder’s FeeDistributor
Ramses gauged policy targets a zero skim so 100% of collected pool fees reach voters. Rewarder creation does not enforce that collector setting, and it remains independently configurable, so integrations must verify live state. Protocol-fee collection intentionally leaves one smallest unit of each non-zero token in the pool. Flash-loan fees are entirely protocol fees. The factory owner can set the flash-loan fee up to 10%.

Oracle

Each pool contains an oracle of cumulative active ID, volatility, and bins crossed. It remains inactive until increaseOracleLength() allocates storage.
Samples have a 120-second maximum lifetime. Integrations must inspect oracle parameters before assuming historical observations are available.

Hooks and rewards

Hooks can execute before or after swaps, flash loans, mints, burns, and batch transfers. Hook calls are synchronous; an enabled hook that reverts or returns an invalid selector can block the corresponding pool operation until governance replaces or removes it. DLMMRewarder enables Ramses voter-directed emissions:
  • Voter treats the rewarder as the pool’s emission target
  • RAM streams over a configurable, upper-exclusive range of at most 11 bins
  • The default (0, 1) range rewards only the active bin
  • Reward weight is calculated from bin liquidity at the active-bin price
  • Each bin then distributes pro rata to its share holders
  • Owners claim only for their own address
Anti-JIT controls can forfeit newly accrued rewards for recently modified positions. Burns remain possible and principal is not forfeited. Rewarders are beacon proxies. Updating the factory’s rewarder implementation can change all existing rewarders. Removing or replacing a rewarder hook makes the old rewarder unlinked; its pending-reward view returns zero and claims revert until linkage is restored.
At the Robinhood snapshot at block 22,674,244, the factory reported voter() == address(0) and sampled pools had no hook. Do not expose RAM claims or gauged fee behavior unless a newer live read confirms that state changed.

Voter and AccessHub integration

When configured, Voter reuses its existing pool/gauge mappings: AccessHub exposes dedicated DLMM operations for pool and rewarder creation, fee changes, hook managers, reward ranges, fee collector settings, and factory ownership. Regular users call an open factory preset directly; protocol operators use createDLMMPool().

Events

Factory

Pool

Rewards and fee routing

Integration invariants

  • binStep = 1 means one basis point, or 0.01%
  • Prices are unsigned 128.128 fixed-point values
  • destinationBin = liveActiveId + deltaId; activeIdDesired is the slippage anchor
  • refundTo receives unused mint inputs
  • Public router adds require to == msg.sender
  • Router paths execute Version.V2_1
  • protocolShare is basis points of swap fees
  • Pool settings and hook state are mutable
  • Current deployment state takes precedence over generic factory constants or documentation labels

Additional resources