DittoETH

Ditto
DeFiFoundryOracle
55,000 USDC
View results
Submission Details
Severity: low
Invalid

Users get less than expected `amtZeth` (ethEscrowed) on calling `redeemErc()`

Summary

In the event of market shutdown, users can call redeemErc(). The user gets less than expected amtZeth (ethEscrowed) due to division before multiplication by the protocol.

Vulnerability Details

In the event of market shutdown, users can call redeemErc():

File: contracts/facets/MarketShutdownFacet.sol
57 /**
58 * @notice Allows user to redeem erc from their wallet and/or escrow at the oracle price of market shutdown
59 * @dev Market must be permanently frozen, redemptions drawn from the combined collateral of all short records
60 *
61 * @param asset The market that will be impacted
62 */
63
64 function redeemErc(address asset, uint88 amtWallet, uint88 amtEscrow)
65 external
66 isPermanentlyFrozen(asset)
67 nonReentrant
68 {
69 if (amtWallet > 0) {
70 asset.burnMsgSenderDebt(amtWallet);
71 }
72
73 if (amtEscrow > 0) {
74 s.assetUser[asset][msg.sender].ercEscrowed -= amtEscrow;
75 }
76
77 uint88 amtErc = amtWallet + amtEscrow;
78 @> uint256 cRatio = _getAssetCollateralRatio(asset);
79 // Discount redemption when asset is undercollateralized
80 @> uint88 amtZeth = amtErc.mulU88(LibOracle.getPrice(asset)).mulU88(cRatio);
81 s.vaultUser[s.asset[asset].vault][msg.sender].ethEscrowed += amtZeth;
82 emit Events.RedeemErc(asset, msg.sender, amtWallet, amtEscrow);
83 }

Line 80 contains the calculation uint88 amtZeth = amtErc.mulU88(LibOracle.getPrice(asset)).mulU88(cRatio);, where cRatio is calculated on Line 78 as uint256 cRatio = _getAssetCollateralRatio(asset) calling the private function in the same file, _getAssetCollateralRatio():

File: contracts/facets/MarketShutdownFacet.sol
85 /**
86 * @notice Computes the c-ratio of an asset class
87 *
88 * @param asset The market that will be impacted
89 *
90 * @return cRatio
91 */
92
93 function _getAssetCollateralRatio(address asset)
94 private
95 view
96 returns (uint256 cRatio)
97 {
98 STypes.Asset storage Asset = s.asset[asset];
99 @> return Asset.zethCollateral.div(LibOracle.getPrice(asset).mul(Asset.ercDebt));
100 }

Simplifying, the calculation for amtZeth on Line 80 becomes:

amtZeth = amtErc * price * (cRatio) => amtErc * price * ( zethCollateral / (price * ercDebt) )

Division operation is done before multiplication. Correct form should be:

amtZeth = ( amtErc * price * zethCollateral ) / (price * ercDebt)

Impact

The user gets less than expected amtZeth (ethEscrowed)

Tools Used

Manual inspection.

Recommendations

Perform multiplication before division as shown in the above calculation.

Updates

Lead Judging Commences

0xnevi Lead Judge
almost 2 years ago
0xnevi Lead Judge almost 2 years ago
Submission Judgement Published
Invalidated
Reason: Other

Support

FAQs

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