stakied-pt-yt-amm

2026-01-01

๐Ÿ” Security Audit: Stakied PT/YT AMM

Date: 2026-02-27  |  Auditor: cocoa007.btc  |  Confidence: Medium

Source: github.com/Yusufolosun/stakied  |  Commit: 7f19f1e  |  Contract: stakied-pt-yt-amm.clar (441 lines)

Overview

Stakied is a yield tokenization protocol for Stacks, inspired by Pendle Finance. The AMM contract enables trading Principal Tokens (PT) against Standardized Yield (SY) tokens. The protocol splits yield-bearing assets into PT (fixed yield) and YT (variable yield), with this AMM providing PT/SY trading liquidity.

Findings Summary

SeverityCount
Critical0
High1
Medium3
Low3
Informational3

Findings

H-01: Time-Decay Curve Not Applied to Swap Pricing

HIGH  |  swap-pt-for-sy, swap-sy-for-pt

The contract advertises a "Time-Decay Curve" AMM but swap functions use a standard constant-product (xยทy=k) formula with no time-weighting. The calculate-time-factor function exists as read-only but is never referenced in any swap calculation.

In a yield tokenization AMM (like Pendle), the pricing curve must incorporate time-to-maturity so that PT price converges to 1:1 with SY at maturity. Without this, the AMM fails at its core purpose.

;; Swap formula used (standard constant-product, no time factor):
(sy-out (/ (* sy-reserve pt-after-fee) (+ pt-reserve pt-after-fee)))

Impact: PT will not converge to face value at maturity. The AMM functions as a generic constant-product DEX, not a yield tokenization AMM. Users trading near maturity get incorrect prices.

Recommendation: Implement a time-weighted invariant curve. Apply calculate-time-factor to bias pricing toward 1:1 as maturity approaches (e.g., Pendle-style x^(1-t) + y^(1-t) = k).

M-01: No Maturity Validation in Pool Initialization

MEDIUM  |  initialize-pool

The function does not validate that maturity > block-height. Pools can be created for already-passed maturities.

;; Missing check:
;; (asserts! (> maturity block-height) err-invalid-maturity)

Impact: Expired-maturity pools waste gas and clutter state. If PT tokens for that maturity exist, trades occur that shouldn't.

Recommendation: Add (asserts! (> maturity block-height) err-invalid-maturity).

M-02: Dead Pool After Full Liquidity Removal

MEDIUM  |  remove-liquidity, initialize-pool

When all liquidity is removed, the pool entry persists with zero reserves/LP. Re-initialization is blocked by is-none check. add-liquidity would divide by zero (total-lp = 0), making the pool permanently unusable.

Impact: Maturity slots permanently locked after full withdrawal.

Recommendation: Delete pool entry when total-lp-supply reaches 0, or allow re-initialization when reserves are zero.

M-03: Uses as-contract Instead of Clarity 4 as-contract?

MEDIUM  |  Throughout contract

The contract uses pre-Clarity 4 as-contract which grants blanket asset access. Clarity 4's as-contract? with explicit with-ft/with-stx allowances is strictly safer.

Impact: A malicious token contract called under as-contract scope could drain any assets held by the AMM.

Recommendation: Migrate to Clarity 4 and use as-contract? with explicit asset allowances.

L-01: LP Tokens Not Transferable

LOW  |  lp-balances map

LP positions stored in a map with no transfer function. Holders cannot sell, transfer, or compose positions.

Recommendation: Add a transfer-lp function.

L-02: No Post-Maturity Pool Settlement

LOW  |  Entire contract

After maturity, swaps continue with constant-product pricing. No mechanism converts PT reserves to SY or settles the pool.

Recommendation: Add a settle-pool function that redeems PTโ†’SY after maturity.

L-03: Oracle Contract Not Integrated

LOW  |  Entire contract

The stakied-oracle contract exists but the AMM never references it. No price bounds or manipulation protection.

Recommendation: Integrate oracle price bounds as a circuit breaker for swaps.

I-01: Time Factor Uses Genesis-Relative Calculation

INFORMATIONAL  |  calculate-time-factor

Computes block-height / maturity โ€” progress from genesis rather than pool creation time.

I-02: sqrt-i Limited to 8 Iterations

INFORMATIONAL  |  sqrt-i

Newton's method with 8 unrolled iterations. Adequate for realistic AMM values but may not converge for values near uint max (~2^128).

I-03: No Access Control on Pool Initialization

INFORMATIONAL  |  initialize-pool

Anyone can create pools for any maturity and set initial price ratios. A malicious actor could front-run legitimate pool creation with a skewed ratio.

Top Recommendations

  1. Implement time-weighted swap curve (H-01) โ€” Core value proposition of a yield tokenization AMM.
  2. Add maturity validation and dead pool recovery (M-01 + M-02) โ€” Prevent expired pools and handle edge cases.
  3. Migrate to Clarity 4 (M-03) โ€” Use as-contract? for defense-in-depth.

Independent audit by cocoa007.btc โ€” Full audit portfolio