alex-amm-swap-pool-v1-1

2026-01-01
← Back to Audit Index

ALEX amm-swap-pool-v1-1

Weighted/Stable AMM Swap Pool — Independent Security Audit by cocoa007.btc

Contract: SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.amm-swap-pool-v1-1
Source: Stacks Explorer | Hiro API
Deploy Height: 104237
Clarity Version: Pre-Clarity 4 (uses as-contract)
Date: 2026-03-02
Auditor: cocoa007.btc
Confidence: Medium

Findings Summary

0
Critical
2
High
4
Medium
3
Low
4
Info
IDSeverityTitle
H-01HighPool owner can set unlimited fee rates (no cap validation)
H-02Highas-contract used without asset restrictions (pre-Clarity 4)
M-01MediumZero-output swaps possible — user pays fees, receives nothing
M-02MediumFee accounting relies on external vault segregation
M-03MediumPool owner can freeze trading via start/end block manipulation
M-04MediumPermissionless pool creation with non-functional defaults
L-01LowNo minimum liquidity lock on first deposit
L-02LowSaturating subtraction in reduce-position
L-03LowOracle resilient price manipulable via single swap
I-01Infounwrap-panic in reduce-position
I-02InfoMulti-hop swaps drop intermediate slippage protection
I-03InfoNo events for admin parameter changes
I-04InfoPre-Clarity 4 — recommend migration to as-contract?

Architecture

The contract implements a configurable AMM with two curve modes controlled by a switch-threshold:

  • High factor (≥ threshold): Linear+product invariant: (1-t)(x+y) + t·x·y
  • Low factor (< threshold): Power-mean invariant: x^(1-t) + y^(1-t)

Dependencies: .alex-vault-v1-1 (custodial vault), .token-amm-swap-pool-v1-1 (LP token), .trait-sip-010 (SIP-010 trait).

Includes a full fixed-point math library (exp, ln, pow) with 8-decimal precision.

Detailed Findings

HIGH H-01: Unlimited Fee Rates

Location: set-fee-rate-x, set-fee-rate-y

The pool owner or contract owner can set fee rates to any uint value with no upper bound. A fee rate ≥ 100% causes the entire user input to be consumed as fees, yielding zero output.

(define-public (set-fee-rate-x (token-x principal) (token-y principal) (factor uint) (fee-rate-x uint))
    (let ((pool (try! (get-pool-details token-x token-y factor))))
        (asserts! (or (is-eq tx-sender (get pool-owner pool)) (is-ok (check-is-owner))) ERR-NOT-AUTHORIZED)
        ;; NO UPPER BOUND CHECK
        (map-set pools-data-map { ... } (merge pool { fee-rate-x: fee-rate-x }))
        (ok true)))

Impact: Effective rug pull — users lose 100% of input. Pool owner can front-run to set fees to max, steal swap inputs, then reset.

Recommendation: Add (asserts! (<= fee-rate-x u10000000) ERR-FEE-TOO-HIGH) (cap at 10%).

HIGH H-02: as-contract Without Asset Restrictions

Location: add-to-position, reduce-position, swap-x-for-y, swap-y-for-x

Uses pre-Clarity 4 as-contract which grants blanket asset authority to the contract principal for the enclosed expression. Clarity 4's as-contract? with with-ft/with-stx can restrict exactly which assets and amounts are authorized.

(as-contract (try! (contract-call? .alex-vault-v1-1 transfer-ft token-y-trait dy sender)))
(as-contract (try! (contract-call? .token-amm-swap-pool-v1-1 mint-fixed ... sender)))

Impact: Broader attack surface if vault or LP token contracts have vulnerabilities.

Recommendation: Migrate to Clarity 4; use as-contract? with explicit with-ft allowances.

MEDIUM M-01: Zero-Output Swaps

Location: swap-x-for-y, swap-y-for-x

Small inputs can result in dy = 0 after fees. The guard (and (> dy u0) ...) silently skips the output transfer — user pays input + gas, receives nothing.

(and (> dy u0) (as-contract (try! (contract-call? .alex-vault-v1-1 transfer-ft token-y-trait dy sender))))

Recommendation: Add (asserts! (> dy u0) ERR-INVALID-LIQUIDITY) before the conditional transfer.

MEDIUM M-02: Fee Accounting Vault Dependency

Location: swap-x-for-y, swap-y-for-x

Non-rebated fees are sent to the vault reserve via add-to-reserve, but the pool's tracked balance-x only includes dx-net-fees + fee-rebate. This creates an implicit dependency on the vault correctly segregating reserve from pool balances.

Impact: If vault accounting is compromised, pool balances become unreliable.

MEDIUM M-03: Pool Owner Can Freeze Trading

Location: set-start-block, set-end-block

Pool owner can set start-block > end-block, causing check-pool-status to always fail. Swaps are blocked; withdrawals still work (reduce-position doesn't check pool status).

Recommendation: Validate start-block <= end-block in both setters.

MEDIUM M-04: Permissionless Pool Creation

Location: create-pool

Anyone can create pools with any SIP-010 pair. Pools are created with max-in-ratio: u0 and max-out-ratio: u0, making the pool non-functional until configured. Malicious token contracts can be paired.

Recommendation: Restrict pool creation to contract owner or require valid initial parameters.

LOW L-01: No Minimum Liquidity Lock

First LP deposit has no minimum locked liquidity, unlike Uniswap V2. Mitigated by requirement that both dx > 0 and dy > 0.

LOW L-02: Saturating Subtraction in reduce-position

Uses (if (<= balance-x dx) u0 (- balance-x dx)) pattern. Rounding could cause computed withdrawal to exceed tracked balance, leaving phantom dust in vault.

LOW L-03: Oracle Price Manipulation

Oracle EMA updated on every swap. If oracle-average is set low, the resilient price tracks spot price closely and can be manipulated in a single block.

INFO I-01: unwrap-panic Usage

reduce-position uses unwrap-panic for LP token balance query. If the LP contract is unreachable, the tx panics with no useful error.

INFO I-02: Multi-Hop Slippage Gap

swap-helper-a/b/c pass none for intermediate slippage. Only the final leg has user-specified min output. Intermediate legs are sandwich-able.

INFO I-03: No Admin Events

Parameter changes (fee rates, ownership, oracle settings) don't emit print events, hindering off-chain monitoring.

INFO I-04: Pre-Clarity 4

Recommend migration to Clarity 4 for as-contract? with explicit asset allowances.

Access Control

RoleCapabilities
contract-ownerPause, transfer ownership (immediate, no timelock), set fee-rebate, set pool-owner, set switch-threshold
pool-ownerSet start/end block, max-in/out ratio, oracle settings, thresholds, fee rates
AnyoneCreate pool, add/remove liquidity, swap

Recommendations

  1. Cap fee rates — Maximum fee validation in setters (H-01)
  2. Require dy > 0 on swaps — Prevent zero-output (M-01)
  3. Migrate to Clarity 4as-contract? with explicit allowances (H-02)
  4. Add timelock to ownership transfer
  5. Validate start-block ≤ end-block (M-03)
  6. Add division-by-zero guards in math library
  7. Emit events for admin actions (I-03)

Independent audit by cocoa007.btcFull audit portfolio