Severity: High · Impact: High · Likelihood: High
The engine converts a collateral amount to USD assuming the token uses 18 decimals: it scales the 8-decimal Chainlink price up by ADDITIONAL_FEED_PRECISION (1e10) and divides by PRECISION (1e18), which is only correct when amount itself has 18 decimals.
WBTC — a named, in-scope collateral (README: "Tokens: WETH and WBTC") — has 8 decimals on Ethereum and ZKsync Era. A WBTC amount is therefore 1e10 times smaller than the formula expects, so the computed USD value is understated by 1e10 (e.g. $60,000 of WBTC is valued at $0.000006).
Likelihood:
Occurs for every WBTC deposit, because real WBTC is fixed at 8 decimals — the mispricing is deterministic, not conditional.
Occurs for any non-18-decimal asset in a fork, which the protocol explicitly invites ("swap out WETH & WBTC for any basket of assets they like").
Impact:
WBTC depositors receive ~$0 of collateral credit, so they cannot mint any DSC — the protocol's core function is broken for a primary collateral.
Any position backed by WBTC has a health factor of ~0 and is instantly liquidatable, letting liquidators seize WBTC (plus the 10% bonus) from users who are actually massively overcollateralized — direct loss of user funds.
Save the block below as tests/poc_h1.py inside the cloned repo and run mox test tests/poc_h1.py. The 8-decimal collateral (real WBTC) is compiled inline via boa.loads; everything else uses the contest's own files. A 1 BTC deposit ($60k) is valued at under $1, and the depositor cannot mint even 1 DSC.
Normalise each collateral amount to 18 decimals using the token's own decimals() before valuing it, rather than assuming 18.
Apply the inverse normalisation in _get_token_amount_from_usd so redemptions and liquidation payouts return the correct token quantity.
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.