Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: high
Valid

Amount Of Asset Out Wrong Calculation

Summary

In StabilityBranch there is a function getAmountOfAssetOut used to calculate the amount of assets to be received in a swap based on the input USD amount, its current price and the premium or discount to be applied. However, the calculation is wrong.

Vulnerability Details

In StabilityBranch there is a function getAmountOfAssetOut used to calculate the amount of assets to be received in a swap based on the input USD amount, its current price and the premium or discount to be applied. However, the calculation is wrong.

function getAmountOfAssetOut(
uint128 vaultId,
UD60x18 usdAmountInX18,
UD60x18 indexPriceX18
)
public
view
returns (UD60x18 amountOutX18)
{
// fetch the vault's storage pointer
Vault.Data storage vault = Vault.load(vaultId);
// fetch the vault's total assets in USD; if the vault is empty
// revert here to prevent panic from subsequent divide by zero
UD60x18 vaultAssetsUsdX18 = ud60x18(IERC4626(vault.indexToken).totalAssets()).mul(indexPriceX18);
if (vaultAssetsUsdX18.isZero()) revert Errors.InsufficientVaultBalance(vaultId, 0, 0);
// we use the vault's net sum of all debt types coming from its connected markets to determine the swap rate
SD59x18 vaultDebtUsdX18 = vault.getTotalDebt();
// calculate the premium or discount that may be applied to the vault asset's index price
// note: if no premium or discount needs to be applied, the premiumDiscountFactorX18 will be
// 1e18 (UD60x18 one value)
UD60x18 premiumDiscountFactorX18 =
UsdTokenSwapConfig.load().getPremiumDiscountFactor(vaultAssetsUsdX18, vaultDebtUsdX18);
// get amounts out taking into consideration the CL price and the premium/discount
amountOutX18 = usdAmountInX18.div(indexPriceX18).mul(premiumDiscountFactorX18);
}

Let's take a look at that line:

UD60x18 vaultAssetsUsdX18 = ud60x18(IERC4626(vault.indexToken).totalAssets()).mul(indexPriceX18);

As we know indexToken can have any decimals value that is less than or equal to 18. Let's say that our indexToken is with 6 decimals. We expect that the vaultAssetsUsdX18 will be a value in base 18.

  1. IERC4626(vault.indexToken).totalAssets() will return a value in 6 decimals (for example 1e6)

  2. indexPriceX18 will be a value in 18 decimals (for example 1e18)

  3. vaultAssetsUsdX18 will be equal to 1e6 x 1e18 / 1e18 = 1e6 -> the value is not in 18 decimals.

  4. The whole calculation below that line becomes wrong.

Impact

Wrongly calculated amount of asset out leading to confusion and wrong fetched values.

Tools Used

Manual Review

Recommendations

Convert the IERC4626(vault.indexToken).totalAssets() first to an 18 decimal value before performing the calculation to ensure that all indexTokens with decimals less than or equal to 18 will work correctly.

Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

petersr Submitter
6 months ago
inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

`totalAssets()` is not properly scaled to ZAROS precision

Support

FAQs

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