Crypto Training

Fluid Deep Dive: DEX v2 Architecture, Money Market Flows, and Security Threat Models

A code-informed, security-first walkthrough of Fluid's Liquidity Layer, DEX v2 (D3/D4), and Money Market: architecture, user stories, fund flows, invariants, and vulnerability hunting playbooks.

Crypto Training2025-11-0917 min read

Fluid is one of the most interesting protocol stacks to study right now because it combines:

  • a shared Liquidity Layer
  • AMM logic (DEX v2)
  • lending-style debt/collateral semantics
  • concentrated liquidity
  • aggressive gas optimization and precision trade-offs

This post is a security-oriented architecture guide written from code and docs, not just from marketing diagrams. The goal is to build a mental model you can actually use for research, integration reviews, and audits.

Primary references:

  • 2026-01-fluid-dex-v2/fluid-contracts (contest/audit codebase)
  • mellow/fluid/fluid-contracts-public (public repo with Liquidity Layer context)
  • external-docs/dex-v2-swaps.html
  • external-docs/understanding-fluid-key-concepts.html
  • external-docs/blog-fluid-dex-v2.html

Why Fluid's model is unusual#

Most DeFi systems are either:

  • pure AMM with reserves and fee accounting, or
  • pure lending market with collateral and debt books.

Fluid DEX v2 intentionally blurs this by introducing smart collateral (D3) and smart debt (D4), with range orders and money market integration.

flowchart LR LL[Liquidity Layer] DEX[DEX v2 Singleton] MM[Money Market] R[Resolvers/Router] U[Users + Integrators] U --> R R --> DEX MM --> DEX DEX --> LL MM --> LL

The key consequence: a single user action may alter AMM state, debt/supply accounting, fee growth, and collateral health in one atomic flow.

Layered architecture#

At a high level, think in three planes:

  1. Settlement plane: Liquidity Layer holds funds and executes supply/borrow/payback/withdraw.
  2. Logic plane: DEX v2 modules (D3/D4) update pool and position state.
  3. Risk plane: Money Market computes health factor, caps, liquidation bounds, and position lifecycle.
flowchart TB subgraph S[Settlement Plane] LL[Fluid Liquidity] end subgraph L[Logic Plane] DEX[FluidDexV2] D3[D3 Modules] D4[D4 Modules] end subgraph R[Risk Plane] MM[FluidMoneyMarket] ORACLE[Oracle] end USER[EOA/Integrator] --> MM USER --> DEX MM --> DEX DEX --> D3 DEX --> D4 D3 --> LL D4 --> LL MM --> LL MM --> ORACLE

DEX v2 execution model: startOperation -> callback -> settle#

The most important primitive in DEX v2 is not swap; it is the operation envelope.

In dexV2/base/core/main.sol:

  • startOperation(bytes) activates transient operation state.
  • Caller callback (startOperationCallback) executes arbitrary module calls via operate(...).
  • Pending transfers must be fully cleared before completion via PendingTransfers.requireAllPendingTransfersCleared().

This gives DEX v2 an explicit flash-accounting-like envelope.

sequenceDiagram autonumber participant C as Caller (Router/MM/Custom) participant D as FluidDexV2 participant M as D3/D4 Module participant L as Liquidity Layer C->>D: startOperation(data) D->>D: activate operationControl D->>C: startOperationCallback(data) C->>D: operate(dexType, moduleId, calldata) D->>M: delegatecall module M-->>D: update pending supply/borrow (transient) C->>D: settle(token, supply, borrow, store, to, isCallback) D->>L: operate(...) if needed D->>D: update pending deltas + stored balances D->>D: requireAllPendingTransfersCleared() D->>D: deactivate operationControl D-->>C: result

Why this matters for security#

The invariant is simple but deep:

  • Module logic may create pending deltas.
  • Only successful settlement paths must clear them.
  • If pending deltas survive the operation, the whole transaction reverts.

That blocks many classes of "state moved but funds unpaid" bugs.

The Pending Transfers ledger (transient)#

pendingTransfers.sol keeps per-user per-token pending values in transient storage (tstore/tload) and tracks non-zero entry counts.

flowchart LR A[Module action] B[addPendingSupply / addPendingBorrow] C[Transient key user+token] D[Count slots supply/borrow] E[settle] F[add negative delta to clear] G[Counts return to zero] A --> B --> C --> D E --> F --> C C --> G

Useful mental shortcut: pending values are the atomic IOU book for the current operation envelope.

settle() is a mini settlement engine#

settle is not just transfer logic. It supports:

  • net supply and borrow
  • storing/un-storing balances in DEX contract
  • callback-based funding
  • fallback paths when Liquidity interaction fails
flowchart TD S["settle(token, supply, borrow, store, to, isCallback)"] --> V["Validate bounds and int128 limits"] V --> D["Expand sentinel max/min values"] D --> N["Compute net amount"] N --> P{"net amount positive?"} P -->|yes| IN["User pays net in"] P -->|no| OUT{"net amount negative?"} OUT -->|yes| OUTFLOW["Protocol pays net out"] OUT -->|no| ZERO["No net transfer"] IN --> LL1{"Skip Liquidity Layer path?"} OUTFLOW --> LL2{"Skip Liquidity Layer path?"} LL1 -->|no| CALL1["Call Liquidity.operate"] LL2 -->|no| CALL2["Call Liquidity.operate"] CALL1 --> FB1{"Liquidity call failed?"} CALL2 --> FB2{"Liquidity call failed?"} FB1 -->|yes| STORE1["Direct transfer fallback handling"] FB2 -->|yes| STORE2["Store owed amount"] STORE1 --> U["Update storage deltas"] STORE2 --> U ZERO --> U U --> E["Emit LogSettle"]

A lot of subtle attack surface sits here: callback authorization, balance delta checks, branch-specific accounting, and fallback consistency.

D3 vs D4: same shell, different economics#

Both are concentrated-liquidity modules, but the accounting interpretation differs.

D3 (Smart Collateral)#

D3 behaves like supply-oriented range liquidity:

  • swaps use supply exchange price conversions
  • position actions are deposit / withdraw
  • pending changes are mostly in pending supply
flowchart LR U[User] -->|deposit/withdraw| D3U[D3 userModule] D3U -->|update position/ticks| D3CORE[D3 internals] D3U -->|addPendingSupply +/-| PT[PendingTransfers] U -->|settle| DEX[DexV2 settle] DEX --> LL[Liquidity]

D4 (Smart Debt)#

D4 is debt-oriented liquidity:

  • swaps use borrow exchange price conversions
  • position actions are borrow / payback
  • pending borrow and pending supply can both move in one action (fees + debt netting)
flowchart LR U[User] -->|borrow/payback| D4U[D4 userModule] D4U -->|update position/ticks| D4CORE[D4 internals] D4U -->|addPendingBorrow +/-| PT[PendingTransfers] D4U -->|fee adjustments via pendingSupply| PT U -->|settle| DEX[DexV2 settle] DEX --> LL[Liquidity]

The D4 fee model is one of the most non-trivial parts of the system and deserves targeted invariant testing.

Money Market as NFT position orchestrator#

Money Market wraps user state into NFT positions and can route D3/D4 actions through DEX v2 callbacks.

In moneyMarket/core/operateModule/main.sol:

  • operate(nftId, positionIndex, actionData) can create new NFT/position or mutate existing one.
  • For D3/D4 positions, it decodes position metadata and calls DEX_V2.startOperation(...).

In moneyMarket/core/callbackModule/main.sol:

  • callback validates sender (msg.sender == DEX_V2)
  • branches by position type and action sign
  • executes DEX user-module calls
  • settles amounts
  • updates fee storage and caps
  • checks health factor where needed
sequenceDiagram autonumber participant U as User participant MM as MoneyMarket.operate participant DEX as DexV2.startOperation participant CB as MoneyMarket.startOperationCallback participant MOD as D3/D4 userModule participant LL as Liquidity U->>MM: operate(nftId,positionIndex,actionData) MM->>DEX: startOperation(abi.encode(dexKey,params)) DEX->>CB: startOperationCallback(data) CB->>DEX: operate(D3/D4,moduleId,encoded call) DEX->>MOD: delegatecall MOD-->>DEX: pending deltas CB->>DEX: settle(...) DEX->>LL: operate(...) CB->>CB: update fees/caps/HF DEX->>DEX: require pending cleared DEX-->>MM: result MM-->>U: LogOperate + return ids

User stories and real use cases#

1) Simple D3 LP (yield + range + collateral semantics)#

User objective: supply concentrated liquidity and earn fees while participating in the broader collateralized system.

flowchart TD U[LP User] --> A[Create/Select MM NFT position] A --> B[Operate: D3 deposit action] B --> C[DexV2 D3 add liquidity] C --> D[Pending supply deltas] D --> E[Settle token flows] E --> F[Position active] F --> G[Later: fee collect / withdraw]

2) D4 debt-side LP#

User objective: open debt-side concentrated position, effectively borrowing into a range strategy.

flowchart TD U[Debt-side LP] --> A[Operate: D4 borrow action] A --> B[D4 computes reserves/debt amounts] B --> C[Pending borrow + fee supply deltas] C --> D[Settle via Liquidity] D --> E[Position owes debt, tracks fees] E --> F[Payback path to de-risk or close]

3) Multi-step aggregator swap with callback integration#

Integrator objective: custom route with maximum control and minimal gas overhead.

sequenceDiagram participant Agg as Aggregator Contract participant DEX as DexV2 participant Mod as D3/D4 swap modules Agg->>DEX: startOperation(routeData) DEX->>Agg: startOperationCallback(routeData) Agg->>DEX: operate(... hop1 ...) DEX->>Mod: swap Agg->>DEX: operate(... hop2 ...) DEX->>Mod: swap Agg->>DEX: settle(tokenA,...) Agg->>DEX: settle(tokenB,...) DEX-->>Agg: success only if pending cleared

4) Liquidator workflow#

Liquidator objective: repay unhealthy debt and seize collateral value with penalty constraints.

flowchart TD L["Liquidator"] --> H["Check health factor below threshold"] H --> P["Choose payback position"] P --> Q["Choose withdraw position"] Q --> R["Execute liquidate()"] R --> S{"Payback type"} S -->|Normal Borrow| N["Direct Liquidity Layer payback"] S -->|D4| D4PATH["DexV2 startOperation payback"] N --> W["Compute withdraw value plus penalty"] D4PATH --> W W --> X{"Withdraw type"} X -->|Normal Supply| NS["Liquidity Layer withdraw"] X -->|D3| D3W["DexV2 withdraw flow"] NS --> Z["Transfer seized collateral"] D3W --> Z

Fund flow map (token-level)#

This is the part auditors and integrators should obsess over.

A) D3 deposit fund flow#

flowchart LR U[User wallet] -->|token0, token1 in| DEX[DexV2 settle] DEX --> LL[Liquidity Layer] LL --> D3POS[D3 position accounting] D3POS --> FEE[Fee growth tracking]

B) D3 withdraw flow#

flowchart LR D3POS[D3 position] -->|amounts + fees out| DEX[DexV2 settle] DEX -->|transfer out| U[User/to] DEX -->|or store owed amount| STORED[userStoredTokenAmount]

C) D4 borrow flow#

flowchart LR D4POS[D4 position] -->|pendingBorrow +| PT[PendingTransfers] PT --> DEX[DexV2 settle] DEX --> LL[Liquidity borrow leg] LL --> U[User receives tokens] D4POS --> DEBT[Debt accounting]

D) D4 payback flow#

flowchart LR U[User] -->|repay tokens| DEX[DexV2 settle] DEX --> LL[Liquidity payback leg] LL --> D4POS[D4 debt reduced] D4POS --> FEE[Fee settlement adjustments]

E) Fee collection flow (D3/D4)#

flowchart TD POS[Position] --> ACC[Accrued fee in module] ACC --> MM[MoneyMarket callback collect path] MM --> DEX[operate withdraw/payback with zero principal] DEX --> PT[Pending deltas] MM --> FS[feeStored update] MM --> SET[_feeSettle] SET --> TO[recipient]

F) Liquidity callback trust boundary#

flowchart LR DEX[DexV2] --> LL[Liquidity Layer] LL --> CBACK[liquidityCallback] CBACK --> DEX DEX --> USERCB[user dexCallback branch] DEX --> ERC20[transferFrom branch]

This edge is a prime audit boundary: callback data provenance and caller authenticity assumptions must stay tight.

Core invariants worth formalizing#

If you only verify a handful of properties, verify these:

  1. Operation closure invariant Every successful startOperation exits with all pending supply/borrow counts equal to zero.

  2. No free-credit invariant User cannot increase claimable assets or reduce debt without equivalent cost through settle paths.

  3. D3 accounting shape invariant D3 actions should not accidentally create net positive pending borrow without explicit D4 context.

  4. D4 debt-fee invariant Fee-induced pending supply/borrow netting cannot let users erase debt or over-collect fees.

  5. HF safety invariant Operations that worsen risk must keep post-check health constraints satisfied in required branches.

  6. Callback authorization invariant Only trusted originators can trigger privileged callback paths (startOperationCallback, liquidityCallback).

  7. Rounding boundedness invariant BigMath/rounding drift must remain within expected conservative windows and never accumulate into insolvency.

flowchart TD I1[Pending cleared] --> SAFE[Atomic safety] I2[No free credit] --> SAFE I3[D3 shape] --> SAFE I4[D4 fee-debt netting] --> SAFE I5[HF checks] --> SAFE I6[Callback auth] --> SAFE I7[Rounding bounds] --> SAFE

Threat model#

Assets to protect#

  • pooled assets in Liquidity
  • collateral value in MM positions
  • debt accounting correctness
  • fee accounting correctness

Trust boundaries#

  • governance/auth roles (trusted per design assumptions)
  • Liquidity contract correctness (critical shared dependency)
  • oracle correctness for HF/liquidation
  • callback counterparties (integrators/custom contracts)

Attacker profiles#

  • malicious integrator contract using callback path
  • MEV/searcher exploiting edge rounding/ordering
  • sophisticated user crafting multi-step netting sequences
  • grief attacker trying to stall or trap flows
flowchart LR A1[Malicious callback integrator] A2[MEV searcher] A3[Edge-case user] A4[Griefer] A1 --> SURF1[callback/reentrancy surfaces] A2 --> SURF2[price+rounding+timing surfaces] A3 --> SURF3[pending netting/state machine surfaces] A4 --> SURF4[fallback/store/liquidity split surfaces]

Potential vulnerability classes (research candidates)#

I am intentionally framing these as hunt targets, not confirmed vulnerabilities.

1) Pending transfer desynchronization across rare branches#

settle has many branch combinations (skip LL, call LL, LL-failed fallback, net-in/net-out, store path). Bugs here can create medium/high issues if pending deltas or unaccounted values diverge.

2) D4 fee/debt netting inconsistencies#

D4 uses combined pending borrow and pending supply adjustments for fee handling. Any sign inversion or asymmetry over long sequences can create hidden debt forgiveness or fee inflation.

3) Callback-induced cross-function reentrancy assumptions#

Reentrancy lock is applied on settle, but operation envelope + callbacks + module calls are still complex. Cross-function reentry that reorders pending updates is a classic candidate.

4) Rounding-driven value leakage under stress#

BigMath + explicit conservative rounding is intentional, but drift can still produce edge-case user-level unfairness, stuck dust, or reconciliation anomalies that become material at scale.

5) Liquidation edge constraints and minimums#

Some checks are intentionally relaxed in withdraw/payback paths to avoid stuck liquidations. This is operationally pragmatic, but always expands the state space for weird edge behavior.

6) Liquidity split and rebalancing dependence#

If liquidity is split between DEX side and Liquidity side, flows can fail despite aggregate liquidity. This is a known design risk, but still a source of practical exploitability patterns (grief, timing, selective failure).

mindmap root((Candidate bug classes)) settle branch divergence D4 fee/debt sign asymmetry callback reentry ordering rounding drift accumulation liquidation edge paths liquidity split griefing

Auditor's test strategy for this architecture#

To reason about Fluid correctly, one-off unit tests are not enough. Use layered testing:

  1. Stateful fuzzing for random action sequences across D3/D4/MM.
  2. Invariants for pending-clearing, debt conservation, and HF bounds.
  3. Differential tests between path variants (skip-LL vs LL path).
  4. Adversarial callback harnesses for integration-style attacks.
  5. Formal checks for arithmetic/sign constraints on the hardest paths.
flowchart LR F[Fuzz sequences] I[Invariants] D[Differential path tests] C[Callback adversarial tests] H[SMT/formal properties] F --> CONF[Confidence] I --> CONF D --> CONF C --> CONF H --> CONF

Observability and production monitoring#

If this were my production rollout checklist, I would track:

  • pending supply/borrow counts at operation boundaries
  • cumulative rounding residuals and reconciliation deltas
  • fallback-to-stored-balance frequency in settle
  • liquidation failure reasons and dust thresholds
  • per-pool D4 fee-vs-debt deltas over time
flowchart TD ONCHAIN[On-chain events + state] --> PIPE[Indexer/analytics] PIPE --> K1[Pending-count alarms] PIPE --> K2[Fallback-rate alarms] PIPE --> K3[Rounding drift dashboards] PIPE --> K4[Liquidation failure metrics] PIPE --> K5[D4 fee/debt delta monitors]

How to read the two repos together#

The public repo (fluid-contracts-public) gives strong context on the Liquidity-first architecture, BigMath philosophy, and gas optimization patterns.

The contest repo (2026-01-fluid-dex-v2/fluid-contracts) extends this with:

  • DEX v2 singleton and modular D3/D4 engines
  • Money Market NFT-position orchestration around DEX v2 callbacks
  • security-critical operation envelope and pending-transfer lifecycle
flowchart LR PUB[fluid-contracts-public] AUDIT[contest fluid-contracts] PUB --> C1[Liquidity Layer philosophy] PUB --> C2[BigMath + limits model] AUDIT --> C3[DEX v2 D3/D4 mechanics] AUDIT --> C4[MM callback orchestration] C1 --> FULL[Full system understanding] C2 --> FULL C3 --> FULL C4 --> FULL

Deep call-trace playbooks#

Below are compact traces that map user intent to state transitions. These traces are useful when writing fuzz harnesses because they define concrete pre/post expectations.

Playbook A: D3 deposit with fee offset#

Intent: add D3 liquidity, pay net supply after subtracting accrued fees.

sequenceDiagram autonumber participant U as User participant MM as MoneyMarket (optional path) participant DEX as DexV2 participant D3U as D3 userModule.deposit participant PT as PendingTransfers participant LL as Liquidity U->>MM: operate(... D3 deposit action ...) MM->>DEX: startOperation(dexKey,startParams) DEX->>MM: startOperationCallback MM->>DEX: operate(D3,userModule,deposit) DEX->>D3U: delegatecall deposit() D3U->>PT: addPendingSupply(token0, amount0-fee0) D3U->>PT: addPendingSupply(token1, amount1-fee1) MM->>DEX: settle(token0,...) DEX->>LL: operate(token0,...) MM->>DEX: settle(token1,...) DEX->>LL: operate(token1,...) DEX->>DEX: pending counts must be zero

Key observation: the fee offset is applied before net settlement, so mismatch bugs usually appear as residual pending supply, not silent success.

Playbook B: D4 payback with conservative rounding#

Intent: reduce debt-side position while preserving protocol-favorable rounding.

sequenceDiagram autonumber participant U as User/Liquidator participant MM as MoneyMarket callback participant DEX as DexV2 participant D4U as D4 userModule.payback participant PT as PendingTransfers participant LL as Liquidity U->>DEX: startOperation(...) DEX->>MM: startOperationCallback MM->>DEX: operate(D4,userModule,payback) DEX->>D4U: delegatecall payback() D4U->>PT: addPendingBorrow(token0, -payback0) D4U->>PT: addPendingBorrow(token1, -payback1) D4U->>PT: addPendingSupply(token0, -fee0) D4U->>PT: addPendingSupply(token1, -fee1) MM->>DEX: settle(token0,...) MM->>DEX: settle(token1,...) DEX->>LL: operate(...) DEX->>DEX: require pending cleared

Key observation: D4 fee semantics update both borrow and supply books; this is where sign bugs can become severe.

Playbook C: liquidation with D4 payback then D3 seize#

Intent: repay unhealthy debt and extract collateral value path-dependently.

flowchart TD L["Liquidator calls liquidate()"] --> HF["Health factor check below threshold"] HF --> PAY["Resolve payback position"] PAY --> TYPE{"Payback type"} TYPE -->|normal borrow| PB1["Liquidity Layer payback path"] TYPE -->|D4| PB2["DexV2 startOperation payback"] PB1 --> VAL["Compute payback value"] PB2 --> VAL VAL --> WD["Resolve withdraw position"] WD --> WTYPE{"Withdraw type"} WTYPE -->|normal supply| WS1["Liquidity Layer withdraw"] WTYPE -->|D3| WS2["DexV2 D3 withdraw"] WS1 --> DONE["Transfer seized amounts"] WS2 --> DONE

Key observation: liquidation combines oracle prices, rounding, and multi-module state updates. Integration errors here are often medium/high because they directly move collateral.

Checklist-driven risk matrix (Solodit-style lens)#

Using a checklist mindset (attacker-first, external calls, math/rounding, token assumptions), the most relevant Fluid hotspots are:

Checklist lensFluid hotspotWhy it matters
External call sequencingsettle callback path + LL callback pathMultiple external edges inside active operation envelope
Reentrancy modelsettle lock vs operate opennessCross-function ordering assumptions can break under adversarial callbacks
Accounting conservationPending supply/borrow + store fallbackBranch-specific bugs can leak or strand value
Precision/roundingBigMath + explicit +/-1 roundingDrift may be acceptable locally but harmful over long sequences
Liquidation correctnessMM liquidation + D3/D4 payback/withdrawValue transfer under stress; easiest place for high impact
Access control boundariesWhitelist/governance assumptionsTrusted roles are assumed; misconfiguration risk remains operationally significant
flowchart LR CHK[Checklist categories] --> E1[External calls] CHK --> E2[Reentrancy] CHK --> E3[Math/rounding] CHK --> E4[Accounting] CHK --> E5[Access control] E1 --> HOT[DexV2 settle + callbacks] E2 --> HOT E3 --> HOT2[D3/D4 conversions + BigMath] E4 --> HOT3[Pending transfer lifecycle] E5 --> HOT4[Admin module wiring]

What would actually qualify as Medium/High here?#

For this architecture, minor rounding weirdness is usually low/accepted. Medium/high outcomes generally need one of these:

  1. Economic extraction at scale Example shape: a user can repeatedly cycle D4 swap/borrow/payback and end with less debt than paid value, or claim more withdrawable balance than supplied.

  2. Collateral seizure mispricing Example shape: liquidation path over-seizes beyond intended penalty due to conversion/sign mismatch.

  3. Permanent liveness/funds lock for normal users Example shape: state can enter a valid-onchain but non-recoverable condition where users cannot close/withdraw without trusted intervention.

  4. Cross-user impact from malicious pool/token in supposedly isolated contexts Example shape: token/pool behavior can corrupt shared accounting and affect unrelated pools/users.

flowchart TD BUG[Bug candidate] --> IMP{Impact class} IMP -->|extracts value| MH1[Medium/High candidate] IMP -->|locks funds/liveness| MH2[Medium/High candidate] IMP -->|isolated dust loss| L[Likely low/accepted] IMP -->|admin misuse only| TRUST[Out of scope if trusted]

Formal verification targets (practical set)#

A useful formal set is not "prove everything"; it is "prove no catastrophic accounting divergence." Suggested properties:

  1. Operation closure: after any successful startOperation, both pending counts are zero.
  2. No-negative stored balances: user stored token amount never underflows in any settle branch.
  3. Sign consistency in D4: payback cannot increase net debt for same action tuple.
  4. Fee boundedness: collected fee never exceeds fee accrued for a position lifecycle segment.
  5. Liquidation monotonicity: liquidation cannot improve target position HF above allowed bound in paths that require post-check constraints.

Pseudo-spec sketch:

SOLIDITY
/// property: operation closure
assert(PendingSupplyCount() == 0 && PendingBorrowCount() == 0);

/// property: no free debt reduction
/// if userDebtAfter < userDebtBefore then netUserPaymentValue > 0
assert(!(debt_after < debt_before && net_payment_value == 0));

/// property: fee boundedness
assert(fee_collected_lifetime <= fee_accrued_lifetime + epsilon_rounding);
flowchart LR P1[Operation closure] P2[Stored balance safety] P3[D4 sign consistency] P4[Fee boundedness] P5[Liquidation monotonicity] P1 --> PROVE[Core proof set] P2 --> PROVE P3 --> PROVE P4 --> PROVE P5 --> PROVE

Integrator hardening checklist#

If you are integrating Fluid DEX v2 or MM from a router/aggregator contract:

  1. Validate callback caller strictly (msg.sender == DexV2) in your callback entrypoints.
  2. Use explicit slippage bounds on every hop and every settle-affecting action.
  3. Avoid reentrant external calls inside your callback body unless strictly required.
  4. Keep per-operation accounting in memory and reconcile against expected deltas before finishing.
  5. Treat native token handling and 0xEeee... conventions carefully to avoid stuck ETH edges.
  6. Prefer conservative pathing when liquidity split is known to be volatile.
flowchart TD I[Integrator callback] --> C1[Caller authentication] I --> C2[Per-hop slippage] I --> C3[No unsafe external reentry] I --> C4[Delta reconciliation] I --> C5[Native token handling] C1 --> SAFE[Safer integration] C2 --> SAFE C3 --> SAFE C4 --> SAFE C5 --> SAFE

Final takeaways#

Fluid DEX v2 is not "just another concentrated liquidity DEX." It is an execution shell joining AMM mechanics with debt/collateral semantics through a shared settlement layer.

The most important things to internalize are:

  • operation envelope correctness (startOperation lifecycle)
  • pending transfer accounting discipline
  • D4 fee/debt netting semantics
  • Money Market callback and health-factor boundary checks
  • rounding/precision trade-offs as first-class protocol behavior

If you understand these five, you can reason about most real risk in the system and avoid superficial audit conclusions.