https://github.com/OpenEdenHQ/openeden.usdoexpress.audit/tree/f3f31d2ac15e3253cba342229f9d05495f95d6fd
The protocol can mint tokens above the _totalSupplyCap due to cumulative rounding errors in the token-to-shares conversion process. This breaks a fundamental supply limit mechanism designed to protect the protocol.
function checkNewTotalSupply(uint256 amount) public view returns (bool, uint256, uint256) {
//@audit Two rounding downs(bug 1.1 & 1.2) will make it worse
uint256 shares = convertToShares(amount); // bug 1.1 rounded down
uint256 newTotalSupply = convertToTokens(_totalShares + shares); // bug 1.2 Also rounded down @audit will permit minting about above _totalSupplyCap
return (newTotalSupply <= _totalSupplyCap, newTotalSupply, shares);
}
function _safeMintInternal(address to, uint256 amt) internal {
// @audit totalSupply() gets rounded down so it's possible to exceed _totalSupplyCap
if (_usdo.totalSupply() + amt > _totalSupplyCap) revert TotalSupplyCapExceeded();
_usdo.mint(to, amt);
}
The issue stems from multiple rounding operations that consistently round down, creating an accumulated error:
convertToShares(amount) rounds down.convertToTokens(_totalShares + shares) rounds down due to integer divisionnewTotalSupply accounts for since it's a product of muliple rounded down operarions and this inaccurate values is then used to check if newly minted shares cause a surplus in usdo cap.Cap Violation: Actual token supply can exceed _totalSupplyCap which is a major invariant for the protocol, leading to loss of trust as well
// Setup: _totalSupplyCap = 1000000e18, bonusMultiplier = 1.1e18
// Current supply: 999999e18 (just under cap)
// User tries to mint 2e18 tokens
uint256 shares = convertToShares(2e18); // Returns shares for ~1.818e18 tokens
uint256 newSupply = convertToTokens(totalShares + shares); // Returns ~999999.818e18
// Check passes: 999999.818e18 <= 1000000e18 ✓
// But actual minted amount: 2e18
// Actual new supply: 999999e18 + 2e18 = 1000001e18 > cap
Available soon...