Submitted by zanderbyte, also found by 0xDemon, araj, Fortis_audits, and TheSchnilch
https://github.com/code-423n4/2025-04-bitvault/blob/04694fc83f4183e4c57a52599be624fb4aadc013/contracts/src/TroveManager.sol#L360
https://github.com/code-423n4/2025-04-bitvault/blob/04694fc83f4183e4c57a52599be624fb4aadc013/contracts/src/TroveManager.sol#L421
https://github.com/code-423n4/2025-04-bitvault/blob/04694fc83f4183e4c57a52599be624fb4aadc013/contracts/src/TroveManager.sol#L989
https://github.com/code-423n4/2025-04-bitvault/blob/04694fc83f4183e4c57a52599be624fb4aadc013/contracts/src/TroveManager.sol#L1133
The original Liquity V2 code is designed to work with collateral tokens that have 18 decimal places (WETH, rETH, wstETH). BitVault, however, intends to use WBTC and other BTC-like tokens as collateral, which only have 8 decimal places.
This difference in the decimal precision introduces a lot of issues across the entire system, as many core calculations - such as collateral ratios, interest accruals, redemptions, and liquidations - are written with the assumption of 18-digit precision.
The problem is systemic and scattered across many parts of the codebase. While not all instances are immediately exploitable, the cumulative effect will lead to incorrect behaviour, wrong calculations, broken incentives, and a lot of issues.
Due to the scope of this issue, I highlight a few cases in this report. However, the full impact requires a detailed audit of the whole system to ensure it correctly accounts for 8 decimal collateral assets.
Example 1: Incorrect gas compensation cap for liquidations
During liquidation, the total funds the liquidator receives are:
WETH gas compensation + min (0.5% of Troves collateral, 2 units of collateral token)
The following function determines the collateral portion of the compensation:
With constants defined as:
As we can observe, the cap here is in 2e18, meaning the liquidator can exceed the cap of 2 units of collateral token.
Example 2:
In TroveManager we have the following function, in which I highlight the decimal precision of the parameters:
Since _collToLiquidate is in 8 decimals (WBTC), and maxSeizedColl is computed using 18-decimal debt and price values, the comparison is unreliable. The if condition can never be true.
Example 3: Redistribution rewards calculation fails due to decimal mismatch
In _getLatestTroveData, redistribution gains are calculated as:
However:
Result:
trove.redistBoldDebtGain results in values with 8 decimal precision, which may still work but significantly reduces the granularity.
trove.redistCollGain becomes effectively zero, since the numerator ends up far smaller than the 1e18 divisor (e.g., (e.g., 1e8 * 1e8 / 1e18 = 0.01).)
These are just a few examples where the precision mismatch leads to broken calculations. Fully enumerating all such cases would make the report overly lengthy, but these are sufficient to demonstrate the associated risks.
Additionally, many other calculations rely heavily on consistent decimal precision across components like oracle prices and collateral ratios. Without further clarification from the team on how these values are standardized across the system, its difficult to assess the full scope of potential issues.
The fix here is not straightforward, since it heavily depends on other values, contracts outside the scope of this audit, and system assumptions. Since WBTC uses 8 decimals, all relevant calculations, constants, and contract interactions should be reviewed and updated to properly support tokens with 8-decimal precision.
RedVeil (BitVault) acknowledged
