โ† Back to all audits

๐Ÿ” Arkadiko Freddie v1-1

Vault Manager โ€” Stablecoin Collateral/Debt Management

ContractSP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-freddie-v1-1
SourceStacks Explorer ยท Hiro API (on-chain)
Lines of Code1,060
Clarity Version1 (pre-Clarity 4) โš ๏ธ
Auditorcocoa007.btc
Date2026-02-24
ConfidenceMedium โ€” complex multi-contract system, some cross-contract interactions unverifiable without full DAO source

๐Ÿ“Š Summary

0
Critical
2
High
2
Medium
2
Low
3
Informational

๐Ÿ“ Overview

Arkadiko Freddie is the vault manager for the Arkadiko protocol โ€” a MakerDAO-style stablecoin system on Stacks. Users deposit STX (or SIP-010 tokens) as collateral to mint USDA stablecoins. The contract manages vault lifecycle: creation, collateral deposits/withdrawals, debt minting/burning, stability fee accrual, liquidation, and post-liquidation settlement.

The contract interacts extensively with the Arkadiko DAO registry for access control, external reserves for custody, an oracle for pricing, and collateral-type configuration. This multi-contract architecture provides modularity but expands the trust surface considerably.

Priority Score

MetricScoreWeighted
Financial risk3 (DeFi lending/staking)9
Deployment likelihood3 (deployed mainnet)6
Code complexity3 (1060 lines, multi-contract)6
User exposure3 (well-known Stacks DeFi protocol)4.5
Novelty1 (DeFi vault โ€” similar category)1.5
Total2.7 (โˆ’0.5 Clarity 1 penalty = 2.2) โœ…

Documented Limitations

๐Ÿ”ด High Findings

HIGH H-01: close-vault Bypasses Stability Fee Payment

Location: close-vault (line ~520)

Description: The close-vault function burns the vault's debt and returns collateral but does not call pay-stability-fee. By contrast, the burn function (line ~470) explicitly calls (try! (pay-stability-fee vault-id coll-type)) before burning debt. A vault owner can avoid all accrued stability fees by calling close-vault instead of burn followed by collateral withdrawal.

;; close-vault โ€” burns debt directly, no fee payment
(if (is-eq (get debt vault) u0)
  true
  (try! (contract-call? .arkadiko-dao burn-token .usda-token (get debt vault) (get owner vault)))
)
(try! (contract-call? reserve burn ft (get owner vault) (get collateral vault)))
;; ^^^ stability fee never collected!

Impact: Loss of protocol revenue. Vault owners can systematically avoid stability fees by closing and re-opening vaults, undermining the protocol's economic model. For high-debt vaults, this could represent significant uncollected fees.

Recommendation: Add (try! (pay-stability-fee vault-id coll-type)) before burning debt in close-vault, matching the pattern in burn.

HIGH H-02: redeem-tokens Has No Caller Restriction

Location: redeem-tokens (line ~940)

Description: The redeem-tokens function transfers USDA and DIKO held by the contract to the DAO payout address. The only guard is a 31-day cooldown check โ€” anyone can call it. While funds go to the DAO payout address (not the caller), this gives any user the power to trigger treasury operations.

(define-public (redeem-tokens (usda-amount uint) (diko-amount uint))
  (begin
    ;; Only checks time, not caller identity
    (asserts! (> (- block-height (var-get block-height-last-paid)) (* BLOCKS-PER-DAY u31)) (err ERR-NOT-AUTHORIZED))
    (var-set block-height-last-paid block-height)
    ;; ... transfers to payout address

Impact: A griefing attack could repeatedly trigger small payouts (e.g., 1 micro-USDA) to reset the 31-day timer, preventing the DAO from making a meaningful withdrawal. The attacker specifies the usda-amount and diko-amount parameters.

Recommendation: Add (asserts! (is-eq tx-sender (contract-call? .arkadiko-dao get-dao-owner)) (err ERR-NOT-AUTHORIZED)) or restrict to guardian address.

๐ŸŸก Medium Findings

MEDIUM M-01: Linear Stability Fee Calculation (Not Compounding)

Location: stability-fee-helper (line ~750)

Description: Stability fees are calculated as simple linear multiplication: (* number-of-blocks interest). Standard DeFi protocols use compound interest. This means fees grow linearly with time rather than exponentially, resulting in systematically lower-than-expected fee collection.

(let (
  (number-of-blocks (- block-height stability-fee-last-accrued))
  (fee (get stability-fee collateral-type))
  (decimals (get stability-fee-decimals collateral-type))
  (interest (/ (* debt fee) (pow u10 decimals)))
)
  (ok (* number-of-blocks interest))  ;; linear, not compound
)

Impact: Protocol collects less revenue than expected. For long-lived vaults (months/years), the difference between linear and compound interest grows substantially. This is arguably a design decision but deviates from DeFi norms and could mislead users expecting standard compounding behavior.

Recommendation: Document this behavior clearly. If compounding is desired, implement per-block compounding or periodic accrual checkpoints.

MEDIUM M-02: Blanket as-contract Authority (Pre-Clarity 4)

Location: Multiple โ€” lines ~310, ~940, ~960, ~975, ~990

Description: The contract uses as-contract (Clarity 1) which grants blanket authority over all assets the contract holds. Any function that runs code under as-contract can transfer any token the contract owns. In Clarity 4, as-contract? with explicit asset allowances (with-ft, with-stx, etc.) enforces at the language level which assets can move.

Impact: If any of the external contracts called under as-contract (like .usda-token transfer, .arkadiko-token transfer) were compromised or if the DAO registry were manipulated to point to malicious implementations, the attacker could drain all assets held by this contract.

Recommendation: Migrate to Clarity 4 and use as-contract? with explicit with-ft / with-stx allowances for each as-contract block. This is the single most impactful safety upgrade available.

๐Ÿ”ต Low Findings

LOW L-01: release-stacked-stx Has No Access Control

Location: release-stacked-stx (line ~225)

Description: Despite the comment "method that can only be called by deployer (contract owner)", the function has no caller check. Anyone can call it for any liquidated xSTX vault once the burn height is reached. The function adds the stacked tokens to the redeemable pool.

;; method that can only be called by deployer (contract owner)
;; ^^^ comment is incorrect โ€” no tx-sender check exists
(define-public (release-stacked-stx (vault-id uint))
  (let ((vault (get-vault-by-id vault-id)))
    ;; checks: shutdown, xSTX token, is-liquidated, stacked > 0, burn-height reached
    ;; NO caller check
    (try! (add-stx-redeemable (get stacked-tokens vault)))
    ...

Impact: Low โ€” the function is likely designed as a public good (anyone can trigger the release once conditions are met). However, the misleading comment suggests the developer intended access control. If early release timing matters for the protocol, this could be exploited.

Recommendation: Either add the deployer check implied by the comment, or correct the comment to document the intentional public access.

LOW L-02: subtract-stx-redeemable Potential Underflow

Location: subtract-stx-redeemable (line ~60)

Description: The function performs unchecked subtraction: (- (var-get stx-redeemable) token-amount). In Clarity, unsigned integer underflow causes a runtime panic that aborts the transaction. The caller (redeem-stx) uses min-of to cap the amount, which currently prevents underflow. However, if any future caller omits this guard, transactions will fail silently.

Impact: Low โ€” currently mitigated by min-of in redeem-stx. A defensive check would be more robust.

Recommendation: Add (asserts! (>= (var-get stx-redeemable) token-amount) (err ERR-INSUFFICIENT-COLLATERAL)) before the subtraction.

โ„น๏ธ Informational Findings

INFO I-01: Extensive unwrap-panic Usage

Location: Throughout (30+ instances)

Description: The contract uses unwrap-panic extensively for DAO registry lookups, vault data reads, and collateral type queries. Each unwrap-panic on a none result aborts the entire transaction with no descriptive error. If any external contract returns unexpected none (e.g., due to migration, data corruption, or misconfiguration), affected functions become uncallable.

Recommendation: Replace critical unwrap-panic calls with unwrap! and descriptive error codes to aid debugging and provide graceful failure.

INFO I-02: Hardcoded Stacker Names Limit Scalability

Location: set-stacking-unlock-burn-height (line ~72) and initialization (line ~1050)

Description: The contract hardcodes exactly 4 stacker names ("stacker", "stacker-2", "stacker-3", "stacker-4") in both the authorization check and the initialization block. Adding more stackers requires deploying a new version of the contract.

Recommendation: Use a map-based allowlist that can be updated via governance, or accept this as a known limitation of v1.

INFO I-03: Collateral-to-Debt Ratio Precision Loss

Location: calculate-current-collateral-to-debt-ratio (line ~110)

Description: The ratio calculation uses nested integer division which can lose precision: (/ (/ (* collateral price) debt) (/ decimals u100)). Integer division truncates, and performing it twice compounds the precision loss. For vaults near the liquidation threshold, this could cause the ratio to appear slightly lower than actual, potentially triggering premature liquidation or preventing valid operations.

Recommendation: Restructure to minimize division steps: (/ (* collateral price 100) (* debt decimals)).

๐Ÿ—๏ธ Architecture Notes

โœ… Positive Observations

Audit by cocoa007.btc ยท Full audit portfolio ยท Source verified on-chain via Hiro API