DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: medium
Invalid

When calling withdrawMargin, the provided amount is converted needlessly to 18 decimals and might lead to the revert of the function call

Lines of code

https://github.com/Cyfrin/2024-07-zaros/blob/d687fe96bb7ace8652778797052a38763fbcbb1b/src/perpetuals/branches/TradingAccountBranch.sol#L369

Impact

According to the netspec, the amount provided when calling withdrawMargin is the UD60x18 amount. Nevertheless, the amount is still converted to UD60x18 which, for tokens with less than 18 decimals, increased the amount by a magnitude of 18 - decimal of the token. This will result in the revert of the call or the withdrawal of way to many collateral.

Proof of Concept

According to the netspec, the amount which is provided to the function withdrawMargin is a UD60x18 value.

/// @param amount The UD60x18 amount of margin collateral to withdraw.
function withdrawMargin(uint128 tradingAccountId, address collateralType, uint256 amount) external {…}

Nevertheless, the amount is upscaled to 18 decimals using convertTokenAmountToUd60x18():

// convert uint256 -> UD60x18; scales input amount to 18 decimals
UD60x18 amountX18 = marginCollateralConfiguration.convertTokenAmountToUd60x18(amount);

convertTokenAmountToUd60x18() takes the amount and scales it up by the difference of decimals of the token compared to 18 decimals:

function convertTokenAmountToUd60x18(Data storage self, uint256 amount) internal view returns (UD60x18) {
if (Constants.SYSTEM_DECIMALS == self.decimals) {
return ud60x18(amount);
}
return ud60x18(amount * 10 ** (Constants.SYSTEM_DECIMALS - self.decimals));
}

This means that any collateral which has less than 18 decimals will be upscaled. E.g. USDT with 6 decimals will be upscaled by 1e12. This results in an overinflated amount which is used to determine if the user deposited enough collateral which will fail and in turn revert the function call.

// enforces that user has deposited enough collateral of this type to withdraw
_requireEnoughMarginCollateral(tradingAccount, collateralType, amountX18);

Recommended Mitigation Steps

Since the provided amount is already with 18 decimals there is not need to scale it further. Instead simply convert the provided uint256 to a UD60x18:

function withdrawMargin(uint128 tradingAccountId, address collateralType, uint256 amount) external {
- // convert uint256 -> UD60x18; scales input amount to 18 decimals
- UD60x18 amountX18 = marginCollateralConfiguration.convertTokenAmountToUd60x18(amount);
+ // convert uint256 -> UD60x18;
+ UD60x18 amountX18 = amount.intoUD60x18()
;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

benrai Submitter
over 1 year ago
inallhonesty Lead Judge
over 1 year ago
benrai Submitter
over 1 year ago
inallhonesty Lead Judge
over 1 year ago
benrai Submitter
over 1 year ago
inallhonesty Lead Judge
over 1 year ago
inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!