Skip to main content
Status: Draft Type: Standards Track Category: Core Created: 2026-01-18 Requires: CIP-20

Abstract

CIP-21 defines Cowboy’s standard for decentralized exchanges and liquidity pools. The design is hybrid: pools are actors (maximum flexibility) with platform-level primitives for efficiency (math helpers, routing, LP tokens). Key features:
  • Two pool types: Constant product (V2-style) and concentrated liquidity (V3-style)
  • Platform LP tokens: Fungible LP shares for V2 pools (CIP-20 tokens)
  • Actor-managed positions: Non-fungible liquidity positions for V3 pools
  • Validation hooks: can_swap / on_swap for compliance and MEV protection
  • Dual routing: Actor-based router for flexibility, platform primitive for efficient multi-hop

Motivation

DEXes are critical infrastructure for any blockchain ecosystem. Cowboy’s unique features—actors, timers, platform tokens—enable DEX designs not possible on Ethereum:
  • Native TWAP oracles via timers (no external keeper)
  • On-chain limit orders via height-timer polling (a state-triggered timer is a future CIP-5 extension; see §Limit Orders)
  • Efficient batch swaps via platform routing
  • Compliance pools via validation hooks
This CIP provides a standard interface so wallets, aggregators, and applications can interact with any Cowboy DEX predictably.

Specification

Overview

DEX Architecture

Part 1: Platform Primitives

The runtime provides efficient helpers for common AMM operations.

1.1 Math Primitives

1.2 Concentrated Liquidity Math

1.3 Platform Routing


Part 2: V2 Pool Standard (Constant Product)

V2 pools use the classic x * y = k formula with fungible LP tokens.

2.1 Interface

2.2 Validation Hooks

V2 pools MAY specify a validation hook for compliance or MEV protection:

2.3 Reference Implementation

2.4 Worked Example: CIP-20 token ↔ V2 pool

This walks the full path end to end — deploy CIP-20 tokens → seed a V2 pool → swap → harvest LP fees — with concrete addresses, amounts, and expected balances. Every figure below is produced by the spec formulas in §1.1 and §2.3 (integer floor division); a runnable snippet that reproduces them is at the end. Cast (illustrative addresses):

Step 1 — Deploy two CIP-20 tokens

decimals=0 keeps the arithmetic whole-numbered for readability; production tokens typically use 6–18 decimals.

Step 2 — Seed the V2 pool (first liquidity)

The pool pulls both legs with Token.transfer_from (Alice must approve the pool first), then mints LP tokens. For the first provider the spec mints sqrt(amount_a * amount_b) - 1000 and locks 1000 to address(0):
Emits AddLiquidity(alice, 100_000, 100_000, 99_000, alice) and Sync(100_000, 100_000). 1_000 LP is permanently locked at address(0) (anti-first-depositor-griefing), so Alice owns 99_000 / 100_000 = 99% of the pool.

Step 3 — Swap (round trip)

Bob swaps 10_000 ACME for USDC. With fee_bps = 30:
Carol then swaps those 9_066 USDC back for ACME, returning the price to ~1:1 so the harvest in step 4 is purely accrued fees (no impermanent-loss noise): Each swap emits Swap(sender, token_in, amount_in, amount_out, recipient) and a Sync. Note k strictly grows (10.000B → 10.0055B): the 30 bps fee on every swap stays in the reserves. That growth is the LP fee.

Step 4 — Harvest LP fees

V2 has no separate “claim fees” call — fees accrue into the reserves, so each LP token becomes redeemable for more than it was at seed. Measuring redemption value per LP token isolates the fee cleanly (it is unaffected by the locked 1_000): +0.0275% per LP token — entirely harvested swap fees. Alice realizes her share by burning her LP:
Alice receives 99_054 ACME + 99_000 USDC (emits RemoveLiquidity(alice, 99_000, 99_054, 99_000, alice)). Her LP redeemed at the grown per-LP value (2.00055 vs 2.00000 at seed): that uplift is her cut of the 30 bps fees Bob and Carol paid. (Her redemption tracks 99% of reserves, not 100%, because of the locked minimum liquidity.)

Reproduce the numbers


Part 3: V3 Pool Standard (Concentrated Liquidity)

V3 pools allow LPs to concentrate liquidity in price ranges for higher capital efficiency.

3.1 Core Concepts

Ticks: Price space is divided into discrete ticks. Each tick represents a 0.01% price change. Positions: LPs provide liquidity between two ticks (a price range). Positions are non-fungible. Liquidity: A position’s liquidity value determines its share of fees when price is in range.

3.2 Interface

3.3 Position Data

Positions are stored in actor state (not as NFTs):

3.4 Validation Hooks

V3 pools follow the same hook pattern as V2 (validation-only: return True/False, cannot modify amounts), but with V3-specific signatures — can_swap takes sqrt_price_limit in place of V2’s min_amount_out, and position hooks (can_mint_position / can_burn_position) replace V2’s can_add_liquidity / can_remove_liquidity:

3.5 Position Manager (Optional)

For better UX, a position manager actor can wrap positions as transferable:

Part 4: Factory

The factory creates and indexes pools:

Standard Fee Tiers


Part 5: Router

5.1 Actor Router (Flexible)

5.2 Platform Router (Efficient)

The platform router (amm_swap_exact_in / amm_swap_exact_out) provides:
  • Lower gas cost (no actor call overhead per hop)
  • Atomic multi-hop execution
  • Standardized interface
Use platform router when:
  • Standard path-based swap
  • No custom logic needed
  • Maximum efficiency required
Use actor router when:
  • Complex operations (add liquidity + swap)
  • Custom fee handling
  • Flash swaps

Part 6: Advanced Features

6.1 Native TWAP Oracle

V2 pools include a built-in TWAP oracle updated via timers:
No external oracle needed. Price manipulation requires sustained capital over the period.

6.2 On-Chain Limit Orders

⚠️ Note (timer API): CIP-5 timers are height-triggered one-shot only — there is no state/condition trigger (trigger_type="state", watch_address, condition, handler=) in the deployed timer API (schedule_timer(height, payload) / schedule_timer_ex). The example below is illustrative of a desired pattern; against the current API a limit order is emulated by re-arming a short-interval height timer each block that polls the pool price (the handler re-schedules itself, CIP-5 §4.2 / Appendix B). A true state-triggered timer would be a future CIP-5 extension.
Using a limit-order pattern layered on CIP-5 timers:

6.3 MEV Protection via Hooks

6.4 Compliance Pools


Events

V2 Pool Events

V3 Pool Events

Error Conditions

Actor pools are illustrative reference implementations and revert via require(cond, "<message>") rather than numeric codes. The canonical revert messages are:

Security Considerations

Reentrancy

The actor model provides natural reentrancy protection—actors process one message at a time. However, cross-actor calls during swaps should follow checks-effects-interactions pattern.

Price Manipulation

  • TWAP oracles mitigate flash loan attacks
  • Concentrated liquidity pools are more sensitive to manipulation at range boundaries
  • Hooks can implement additional protections (MEV detection, circuit breakers)

Hook Security

  • Hooks are capped at 50,000 Cycles and 50,000 Cells (same as CIP-20 token hooks)
  • Malicious hooks can block all swaps—pool deployers must be trusted
  • Consider timelock for hook updates on major pools

Integer Precision

  • Use Q128 format for prices to maintain precision
  • Concentrated liquidity math uses Q64.96 (matching Uniswap V3)
  • Platform primitives handle precision; actor implementations should use them

Rationale

Why Hybrid (Actor + Platform)?

Pure actor-based: Maximum flexibility but higher gas costs Pure platform-based: Maximum efficiency but inflexible Hybrid gives:
  • Flexibility for pool logic (actors)
  • Efficiency for common operations (platform primitives)
  • Best of both worlds

Why Both V2 and V3?

V2 (constant product):
  • Simpler for LPs
  • Fungible LP tokens (composable with DeFi)
  • Lower gas cost
  • Good for stable pairs
V3 (concentrated):
  • Higher capital efficiency
  • Better for professional LPs
  • Required for competitive pricing on major pairs

Why Validation-Only Hooks?

Full hooks (modifying amounts) add complexity:
  • Unpredictable outputs
  • Gas estimation difficulty
  • Hidden fees
Validation hooks are simpler:
  • Swap succeeds or fails
  • Predictable gas
  • Covers compliance use cases

Backwards Compatibility

This is a new standard. No backwards compatibility concerns.

Reference Implementation

See cowboy-core/src/runtime/amm.rs for platform primitive implementations. See examples/cowswap/ for reference V2 and V3 pool implementations.