Algo Ssstablecoinsss

AI First Flight #2
Beginner FriendlyDeFi
EXP
View results
Submission Details
Impact: high
Likelihood: low
Invalid

Unchecked DSC mint/burn extcall lets a failed mint or burn pass silently, breaking the DSC-to-debt invariant

Unchecked DSC mint/burn extcall lets a failed mint/burn pass silently, breaking the DSC-to-collateral invariant

Description

_mint_dsc and _burn_dsc call DSC.mint and DSC.burn_from without checking the external call result — the code even comments that it is skipping the check.

# dsc_engine.vy:236-239 (_mint_dsc)
self.user_to_dsc_minted[msg.sender] += amount_dsc_to_mint
self._revert_if_health_factor_is_broken(msg.sender)
# Note, we are not checking success here
extcall DSC.mint(msg.sender, amount_dsc_to_mint) # @> return value ignored
# dsc_engine.vy:263-265 (_burn_dsc)
self.user_to_dsc_minted[on_behalf_of] -= amount_dsc_to_burn
# Note, we are not checking success here
extcall DSC.burn_from(dsc_from, amount_dsc_to_burn) # @> return value ignored

The engine's internal user_to_dsc_minted ledger is updated regardless of whether the token operation actually moved supply.

Risk

Likelihood:
Low. The in-scope snekmate DSC reverts on failure, so the bug is latent unless the DSC token is upgraded/replaced or wraps a non-reverting implementation.

Impact:
High. If the DSC token ever returns false instead of reverting (or mint is paused), the engine still credits/debits user_to_dsc_minted. On burn that means a user's debt is cleared without the DSC actually being destroyed, breaking the 1:1 supply-vs-debt invariant and letting circulating DSC exceed backed debt — a depeg / bad-debt vector.

Proof of Concept

Point the engine at a DSC mock whose burn_from returns false instead of reverting.

# mock DSC: burn_from does nothing, returns false
engine.burn_dsc(100 * 10**18)
# debt cleared, but 100 DSC still circulating
assert engine.user_to_dsc_minted(user) == 0 # debt gone, supply unchanged -> unbacked DSC

Recommended Mitigation

Make the interface return a bool and assert it (or rely only on revert-on-failure semantics explicitly).

- # Note, we are not checking success here
- extcall DSC.mint(msg.sender, amount_dsc_to_mint)
+ minted: bool = extcall DSC.mint(msg.sender, amount_dsc_to_mint)
+ assert minted, "DSCEngine_MintFailed"
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 5 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!