Target bounty: mqf84kgs5a5b6c995a80
Target contract: SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-freddie-v1-1
Source URL: https://api.hiro.so/v2/contracts/source/SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR/arkadiko-freddie-v1-1
Snapshot time: 2026-06-23
Source metadata:
- Published at Stacks height:
34239 - Source length:
46156bytes,1060lines - Source SHA256:
9ab03ff419d4d527518ff3e443bc77727a545e4dfb45e70be98ca1d7eaccc689 - Current DAO registry resolves:
collateral-types->SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-collateral-types-v3-1oracle->SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-oracle-v2-3stx-reserve->SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-stx-reserve-v1-1sip10-reserve->SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-sip10-reserve-v2-1auction-engine/liquidator->SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-auction-engine-v4-5
- Live read-only context:
arkadiko-vault-data-v1-1.get-last-vault-idreturned2869.freddie.get-stx-redeemablereturned400000000000.freddie.get-usda-balancereturned0.freddie.get-diko-balancereturned0.get-stability-fee-for-vaultusing the live collateral-types contract returned non-zero fees for active recent vaults:- vault
2852:117427618 - vault
2856:44912640 - vault
2864:713227464 - vault
2869:79156176
- vault
Responsible disclosure note: I did not identify a high or critical severity issue in this public report. No private disclosure was triggered.
arkadiko-freddie-v1-1 is an orchestration contract. Most vault state lives in arkadiko-vault-data-v1-1; collateral parameters, debt caps and stability fees live in the current DAO-selected collateral-types contract.
- Lines 14-31 define error constants
ERR-NOT-AUTHORIZED, transfer/mint/burn/deposit/withdraw/mint/liquidation failures, collateral/debt/stacking/liquidation/auction errors. - Line 34 defines
BLOCKS-PER-DAYasu144.
- Line 36:
stx-redeemable, amount of STX redeemable for xSTX after liquidated stacked collateral is released. - Line 37:
block-height-last-paid, last foundation payout block used byredeem-tokens. - Line 38:
maximum-debt-surplus, initialized tou10000000000000. - Lines 39-44:
stacking-unlock-burn-height, maps stacker names to burnchain unlock heights. - Line 45:
freddie-shutdown-activated, local emergency flag.
The vault map contains:
id,ownercollateral,collateral-type,collateral-tokenstacked-tokens,stacker-name,revoked-stacking,auto-payoffdebtcreated-at-block-height,updated-at-block-heightstability-fee-accrued,stability-fee-last-accruedis-liquidated,auction-ended,leftover-collateral
Important supporting state:
vault-entriesmaps a user principal to a list of up to 20 vault IDs.closing-vaultis a helper map keyed by user.last-vault-idis the global ID counter.
- Freddie mutates vault records through
arkadiko-vault-data-v1-1.update-vault, which allows the DAO-registeredfreddie,stacker-payer, or stacker contracts. - Freddie creates and closes entries through
update-vault-entries,set-last-vault-id, andclose-vault. - Collateral/debt totals are mutated through the DAO-selected collateral-types contract.
- USDA mint/burn authority is delegated through
arkadiko-dao.mint-tokenandarkadiko-dao.burn-token; DAO checks whethercontract-callerhas mint/burn permission. - Reserve custody is delegated to the current DAO-selected STX or SIP10 reserve.
get-stx-redeemable lines 48-50
- Authority: none.
- Returns
stx-redeemable.
get-stacking-unlock-burn-height lines 70-72
- Authority: none.
- Reads
stacking-unlock-burn-height. - Uses
unwrap-panicfor missing stacker names.
get-vault-by-id lines 94-96
- Authority: none.
- Delegates to
arkadiko-vault-data-v1-1.
get-vault-entries lines 98-100
- Authority: none.
- Delegates to
arkadiko-vault-data-v1-1.
get-collateral-type-for-vault lines 102-106
- Authority: none.
- Reads a vault and returns
collateral-type.
get-collateral-token-for-vault lines 108-112
- Authority: none.
- Reads a vault and returns
collateral-token.
get-usda-balance lines 961-963
- Authority: none.
- Reads Freddie's USDA balance via
as-contract.
get-diko-balance lines 965-967
- Authority: none.
- Reads Freddie's DIKO balance via
as-contract.
set-stacking-unlock-burn-height lines 78-92
- Authority:
contract-callermust be one of DAO-registeredstacker,stacker-2,stacker-3,stacker-4. - Mutates
stacking-unlock-burn-height.
calculate-current-collateral-to-debt-ratio lines 120-152
- Authority:
oraclemust match DAO registry;coll-typeis only checked insidestability-fee-helperwhen fees are included. - Reads vault, oracle price, debt and optional fee.
- No direct state mutation.
toggle-stacking lines 165-187
- Authority: global shutdown must be false;
tx-sendermust be vault owner. - Requires STX vault, not liquidated.
- Calls STX reserve and updates vault stacking flags.
stack-collateral lines 191-215
- Authority: global shutdown false;
tx-sendermust be vault owner. - Requires STX vault, not liquidated, no existing stacked tokens.
- Calls STX reserve and updates stacked-token fields.
release-stacked-stx lines 219-247
- Intended authority per comment: deployer/contract owner.
- Actual authority: no owner/deployer assertion.
- Requires xSTX, liquidated vault, non-zero stacked tokens and burn-height >= configured unlock height.
- Adds to
stx-redeemableand zeroesstacked-tokens.
redeem-stx lines 255-267
- Authority: any caller with xSTX to burn.
- Burns xSTX and redeems STX up to
min(stx-redeemable, ustx-amount). - Decrements
stx-redeemable.
toggle-freddie-shutdown lines 269-275
- Authority:
tx-sendermust be DAO guardian. - Toggles local shutdown flag.
collateralize-and-mint lines 288-371
- Authority: shutdown false;
coll-type,oracle, andreservemust match DAO registry; collateral token must match collateral-type. - Calculates initial ratio, verifies min collateral ratio and max-debt cap.
- Calls reserve custody, mints USDA via DAO, creates vault, updates entries, rewards and collateral-type total debt.
deposit lines 380-427
- Authority: shutdown false; reserve/collateral-types must match DAO registry;
tx-sendermust be owner. - Requires not liquidated and token match.
- Calls reserve deposit, updates collateral and rewards.
withdraw lines 437-501
- Authority: shutdown false; reserve/collateral-types/oracle must match DAO registry;
tx-sendermust be owner. - Requires not liquidated, positive amount, enough collateral, no stacked tokens and token match.
- Verifies resulting collateral ratio, calls reserve withdraw, updates vault and rewards.
mint lines 510-581
- Authority: shutdown false; reserve/collateral-types/oracle must match DAO registry;
tx-sendermust be owner. - Requires not liquidated, healthy ratio, max-debt cap.
- Calls
accrue-stability-fee, reserve mint, then updates vault debt and collateral-type debt.
burn lines 590-626
- Authority: shutdown false; reserve/collateral-types must match DAO registry.
- No owner check.
- Pays stability fee from
tx-sender, then burnsmin(debt, vault.debt)USDA fromtx-senderthroughburn-partial-debt. - Does not transfer collateral.
close-vault lines 628-670
- Authority: no
tx-sender == ownercheck. - Requires no stacked tokens, collateral-types/reserve match and not liquidated.
- Burns principal debt from the vault owner via DAO, withdraws all collateral to owner, subtracts debt, updates vault, removes rewards, then calls vault-data close.
- Does not call
pay-stability-fee.
get-stability-fee-for-vault lines 694-703
- Authority: checks collateral-types inside helper.
- Calculates fee from the vault's last-accrual height, debt, and collateral type.
accrue-stability-fee lines 729-745
- Authority: collateral-types must match DAO registry.
- Updates
stability-fee-accruedandstability-fee-last-accrued.
pay-stability-fee lines 751-774
- Authority: collateral-types must match DAO registry.
- Transfers fee amount from
tx-senderto Freddie's contract principal and resets fee fields.
liquidate lines 782-840
- Authority:
contract-callermust be DAO-registeredliquidator. - Removes rewards/collateral accounting, computes penalty and auction discount, updates vault to liquidated state.
- For stacked STX, changes collateral token to xSTX and mints xSTX.
finalize-liquidation lines 848-874
- Authority:
contract-callermust be DAO-registered auction engine. - Requires liquidated vault.
- Sets
auction-ended, stores leftover collateral and subtracts debt total.
redeem-auction-collateral lines 884-896
- Authority: reserve must match DAO registry;
contract-callermust be auction engine. - Calls reserve to transfer auction collateral to winning lot owner.
withdraw-leftover-collateral lines 904-954
- Authority: shutdown false; reserve/collateral-types must match;
tx-sendermust be owner. - Requires liquidated, auction ended, no stacked tokens, token match.
- Calls
pay-stability-fee, then withdraws leftover collateral to owner and zeros leftover.
redeem-tokens lines 975-992
- Authority: no owner/governance check; only requires 31 days since
block-height-last-paid. - Updates
block-height-last-paidbefore performing caller-specified USDA/DIKO transfers to DAO payout.
migrate-funds lines 1000-1010
- Authority:
contract-callermust be DAO owner. - Transfers Freddie's whole balance of a supplied token to the new vault-manager contract.
set-stx-redeemable lines 1015-1022
- Authority: DAO owner.
- Sets
stx-redeemable.
set-block-height-last-paid lines 1024-1031
- Authority: DAO owner.
- Sets
block-height-last-paid.
set-maximum-debt-surplus lines 1033-1040
- Authority: DAO owner.
- Sets
maximum-debt-surplus.
migrate-state lines 1044-1053
- Authority: DAO owner.
- Calls setter functions on a supplied new vault manager.
Post-conditions cannot cover every cross-contract state write, but callers should attach them for token movement and vault-facing workflows.
| Function | Expected movements | Recommended caller post-conditions |
|---|---|---|
collateralize-and-mint |
Collateral leaves user/reserve custody path; USDA minted to user | Assert exact collateral transfer from user, exact USDA increase to user, no unexpected token sends. |
deposit |
Additional collateral leaves owner | Assert exact collateral transfer from owner to approved reserve; no USDA/DIKO movement. |
withdraw |
Collateral moves from reserve to owner | Assert exact collateral received by owner; no USDA/DIKO movement. |
mint |
USDA minted to owner | Assert exact USDA increase by extra-debt; no collateral movement. |
burn |
USDA and fee can be transferred/burned from tx-sender |
Assert USDA decrease does not exceed debt + expected fee; for non-owner callers, avoid calling unless intentionally paying another vault's debt. |
close-vault |
Owner's principal debt is burned; all collateral returns to owner | Owner should assert full collateral returned and USDA burned equals principal debt plus expected fees. Current code does not charge fees, so this is also a finding. |
redeem-stx |
xSTX burned from caller; STX redeemed to caller | Assert xSTX decrease and STX increase bounded by min(stx-redeemable, ustx-amount). |
release-stacked-stx |
No direct caller token movement; stx-redeemable increases |
Protocol/keeper call should assert vault stacked-tokens becomes zero. |
liquidate |
Rewards removed; collateral converted to auction accounting; possible xSTX mint | Auction engine should enforce expected collateral and debt tuple before proceeding. |
finalize-liquidation |
No direct token movement | Auction engine should assert leftover value matches auction settlement. |
redeem-auction-collateral |
Collateral transferred from reserve to auction winner | Assert exact collateral to winning sender. |
withdraw-leftover-collateral |
Fee paid by owner; leftover collateral moves to owner | Assert fee paid and exact leftover collateral received. |
redeem-tokens |
Freddie's USDA/DIKO transferred to DAO payout | Governance/keeper call should assert exact token transfers; currently any caller can trigger it. |
migrate-funds |
Whole token balance moves to new manager | DAO migration should assert recipient is exact new manager and token balance becomes zero. |
| Setters/toggles | No direct token movement | No token post-condition required; require governance/guardian source. |
| Surface | Required authority in code | Notes |
|---|---|---|
| Global shutdown | tx-sender == arkadiko-dao.get-guardian-address |
Guardian can toggle local Freddie shutdown. |
| DAO-owner admin setters | contract-caller == arkadiko-dao.get-dao-owner |
Used by migration and local variable setters. |
| Stacker unlock heights | contract-caller one of DAO-registered stackers |
Strong contract-caller based check. |
| Vault owner actions | tx-sender == vault.owner on toggle/stack/deposit/withdraw/mint/withdraw-leftover |
burn and close-vault are exceptions. |
| Liquidation | contract-caller == DAO liquidator/auction-engine |
Uses DAO registry; current registry points both liquidator and auction-engine to arkadiko-auction-engine-v4-5. |
| Reserve/collateral/oracle dependencies | Must match DAO registry | Some contract arguments are evaluated before all auth checks, but registry checks exist before state updates. |
| Foundation payout | Only 31-day time gate | No governance caller check in redeem-tokens. |
release-stacked-stx |
No deployer/owner check despite comment | Any principal can trigger once burn-height gate passes. |
tx-senderowner checks are used for end-user vault mutation. This is consistent across owner functions but blocks smart-contract wallets and managers. The larger issue is inconsistent absence of the check onclose-vaultandburn.unwrap-panicis used on DAO registry, map reads, price reads and helper calls in user-facing paths. This creates runtime panics instead of typed errors for malformed vault IDs, missing stacker names and registry/oracle failures.- Arithmetic uses raw
+,-,*,/. Current live values are well below uint128 limits, but fee and ratio calculations can still abort if governance parameters or debt/collateral grow without bounded checked math. as-contractis used for DAO minting and collecting stability fees into Freddie. The direction is intended, but it means post-conditions should be attached to all fee and payout flows.- Trait conformance is broad: reserve and collateral-type traits include state-mutating functions. Registry checks prevent unauthorized state updates, but some external trait calls are in
letbindings before every assertion has run. - Liquidation flow is access-controlled by DAO registry, but fee collection is uneven:
withdraw-leftover-collateralpays fees, whileclose-vaultdoes not.
| ID | Severity | Function | Line | Finding | Recommended fix |
|---|---|---|---|---|---|
| ARK-01 | Medium | close-vault, arkadiko-vault-data-v1-1.close-vault |
Freddie 628-670; vault-data 147-156 | close-vault has no owner authorization, and the downstream data contract removes the closed ID from vault-entries under tx-sender rather than the vault owner. A non-owner can force-close an unstacked, non-liquidated vault if the owner has burnable USDA, receive no funds, but destroy the position, return collateral to the owner, and leave the owner's vault-entries pointing at a deleted/default vault. |
Add asserts! (is-eq tx-sender (get owner vault)) before any burn/withdraw/update. In vault-data, update vault-entries for (get owner vault), not raw tx-sender, or pass the owner explicitly from Freddie. |
| ARK-02 | Medium | mint, accrue-stability-fee |
517-523, 564-577, 737-740 | mint computes updated-vault from the pre-accrual vault, then calls accrue-stability-fee, then writes the stale updated-vault. This can discard the fee just accrued in the same transaction. Separately, accrue-stability-fee sets stability-fee-accrued to only the newly calculated interval, rather than adding to any prior accrued amount. Live read-only calls show non-zero current fees for active vaults, e.g. vault 2869 returns 79156176. |
After accruing, re-read the vault or merge debt into the post-accrual record. Change accrual to (+ (get stability-fee-accrued vault) newly-calculated-fee). Add regression tests covering two accruals and a mint after fee accumulation. |
| ARK-03 | Medium | close-vault |
658-667 | Closing a vault burns only principal debt and withdraws all collateral without pay-stability-fee. Owners can close an unstacked vault and avoid current and accrued stability fees. When combined with ARK-01, a non-owner caller can trigger this fee bypass while closing someone else's eligible vault. |
Call pay-stability-fee before burning principal debt, or include principal plus current/accrued fees in a single settlement path. Make the close path use the same fee semantics as burn and withdraw-leftover-collateral. |
| ARK-04 | Low | release-stacked-stx |
217-245 | The comment says the method can only be called by the deployer/contract owner, but the code has no owner/deployer/DAO assertion. Any caller can release liquidated xSTX collateral after burn-height unlock, moving value into stx-redeemable and zeroing stacked-tokens. This is not direct theft, but it removes sequencing control from the protocol. |
Add the intended deployer/DAO/auction-engine authorization or update the comment and document this as a permissionless keeper action. Emit an event identifying the vault and released amount. |
| ARK-05 | Low | redeem-tokens |
975-992 | Foundation payout is permissionless after the 31-day gate and accepts caller-supplied USDA/DIKO amounts. It updates block-height-last-paid before transfers. If zero-value or dust-value transfers succeed for the token implementation, any caller can reset the payout clock without meaningful payout; even without zero-value success, the caller controls payout timing. |
Restrict to DAO owner/governance/keeper or require positive, bounded amounts based on actual Freddie balances before updating the clock. Move block-height-last-paid update after successful transfers. |
| ARK-06 | Low | get-stacking-unlock-burn-height, DAO lookups, helper paths |
70-72 and repeated | Missing map entries and DAO/oracle/helper failures use unwrap-panic, producing runtime failures rather than typed errors. A live call to get-stacking-unlock-burn-height("missing") returned UnwrapFailure. |
Replace unwrap-panic in user-facing/read paths with unwrap! and explicit error constants. |
burnhas no owner check, but it burns USDA fromtx-sender, not the vault owner. This allows third parties to voluntarily pay another vault's fees/debt. I rate it as a design inconsistency rather than a direct vulnerability unless the project intended all vault mutations to be owner-only.- The current DAO registry is not the same as the v1-1 contracts named in the original deployment. Freddie's registry checks correctly route to the currently configured
v3-1collateral-types andv2-1SIP10 reserve where applicable. - Several active recent vaults have non-zero current fees by read-only calculation while stored
stability-fee-accruedremains zero. That is not itself a bug, but it makes the fee-accounting findings economically relevant.
close-vaultlacks owner authorization and downstream vault-data cleanup usestx-sender, so a non-owner can force-close eligible vaults and leave stale owner entries.- Stability fee accrual is lossy:
mintoverwrites the accrual it just triggered, and repeated accrual replaces rather than accumulates prior fee. close-vaultburns only principal debt and never callspay-stability-fee, allowing current/accrued fees to be skipped on closure.
No high or critical findings were identified; private disclosure was not triggered.