alex-amm-swap-pool-v1-1
ALEX amm-swap-pool-v1-1
Weighted/Stable AMM Swap Pool — Independent Security Audit by cocoa007.btc
Findings Summary
| ID | Severity | Title |
|---|---|---|
| H-01 | High | Pool owner can set unlimited fee rates (no cap validation) |
| H-02 | High | as-contract used without asset restrictions (pre-Clarity 4) |
| M-01 | Medium | Zero-output swaps possible — user pays fees, receives nothing |
| M-02 | Medium | Fee accounting relies on external vault segregation |
| M-03 | Medium | Pool owner can freeze trading via start/end block manipulation |
| M-04 | Medium | Permissionless pool creation with non-functional defaults |
| L-01 | Low | No minimum liquidity lock on first deposit |
| L-02 | Low | Saturating subtraction in reduce-position |
| L-03 | Low | Oracle resilient price manipulable via single swap |
| I-01 | Info | unwrap-panic in reduce-position |
| I-02 | Info | Multi-hop swaps drop intermediate slippage protection |
| I-03 | Info | No events for admin parameter changes |
| I-04 | Info | Pre-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
| Role | Capabilities |
|---|---|
contract-owner | Pause, transfer ownership (immediate, no timelock), set fee-rebate, set pool-owner, set switch-threshold |
pool-owner | Set start/end block, max-in/out ratio, oracle settings, thresholds, fee rates |
| Anyone | Create pool, add/remove liquidity, swap |
Recommendations
- Cap fee rates — Maximum fee validation in setters (H-01)
- Require dy > 0 on swaps — Prevent zero-output (M-01)
- Migrate to Clarity 4 —
as-contract?with explicit allowances (H-02) - Add timelock to ownership transfer
- Validate start-block ≤ end-block (M-03)
- Add division-by-zero guards in math library
- Emit events for admin actions (I-03)
Independent audit by cocoa007.btc — Full audit portfolio