dsc_engine.vy's price math assumes every collateral token uses 18 decimals. The real WBTC token configured for zkSync Era mainnet in moccasin.toml (0xBBeB516fb02a01611cBBE0453Fe3c580D7281011) actually has 8 decimals, verified directly on-chain. Since _get_usd_value/_get_token_amount_from_usd never adjust for a token's actual decimals(), any real WBTC deposit is undervalued by a factor of 10^10, and any WBTC amount computed for liquidation payouts is off by the same factor in the other direction -- both directions make the protocol either impossible to use safely with real WBTC or trivially breakable via reverts/underflows.
Both formulas treat amount/their result as if the token always uses 18 decimals (that's what PRECISION = 1e18 implicitly assumes for the amount parameter's unit). This is correct for WETH (verified 18 decimals), but the real configured WBTC token has 8 decimals:
Concretely: 1 real WBTC = 1e8 raw units (not 1e18). Plugging amount = 1e8 (1 real WBTC) into _get_usd_value at a BTC price of, say, $30,000 (price = 30000e8 from the feed) gives:
i.e. 1 whole WBTC is valued at roughly 0.0000003 dollars instead of $30,000 -- undervalued by a factor of ~10^11. This breaks collateral accounting catastrophically: depositing real WBTC contributes effectively nothing to collateral_value_in_usd, so mint_dsc would always fail the health-factor check for anyone trying to mint DSC against WBTC collateral (the protocol becomes unusable for one of its two advertised collateral types), while _get_token_amount_from_usd (used inside liquidate to size the liquidator's payout) has the mispricing in the opposite direction relative to any correctly-priced debt, so a mixed WETH/WBTC liquidation scenario computes wildly inconsistent, exploitable payout sizes between the two collateral types.
Likelihood:
Deterministic given the protocol's own configured collateral set -- WBTC is one of only two collateral tokens the protocol supports, per its own README.md ("deposit WETH and WBTC") and moccasin.toml.
Impact:
Either bricks WBTC as usable collateral entirely (health factor checks always fail once WBTC is worth ~$0.0000003 per whole token in the engine's accounting) or, if any function path skips the health-factor gate, allows drastically miscalculated liquidation payouts -- both are severe breaks of the core collateral-value invariant the entire protocol is built on.
The two collateral tokens the protocol is configured to accept have different decimals (WBTC=8, WETH=18), but _get_usd_value/_get_token_amount_from_usd apply the identical 18-decimals-assumed formula to both, with no per-token decimals normalization anywhere in dsc_engine.vy.
Read each collateral token's actual decimals() at deposit/valuation time (or store it per-token at construction) and normalize amount to 18-decimal terms before applying the price formula, e.g. amount_in_18_decimals = amount * (10 ** (18 - token_decimals)), mirroring how ADDITIONAL_FEED_PRECISION already normalizes the price feed's own 8-decimal output.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.