Part 2

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

Unable to swap USD token to collateral for vaults in credit

Summary

Underflow in UsdTokenSwapConfig.getPremiumDiscountFactor will prevent users from swapping USD token to collateral when vault's credit / vaule ratio is above certain threshold.

Vulnerability Details

Root Cause

UsdTokenSwapConfig.getPremiumDiscountFactor logic can be formalized in the following way:

: vaultAssetsValueUsd

: vaultDebtUsd

: vaultDebtTvlRatioAbs

: premiumDiscountFactor

getPremiumDiscountFactor

According to the following comment:

/// @dev The proposed initial curve is defined as:
/// f(x) = 1 + 9 * ((x - 0.3) / 0.5)^3

we can derive the following:

Thus, when and ,

$f(x) = 1 - y = 1 - (9 * \Delta x ^ 3) $

which will cause underflow in ud60x18 math for certain

POC

import "@zaros/market-making/branches/StabilityBranch.sol";
import { Vault } from "@zaros/market-making/leaves/Vault.sol";
import { UsdTokenSwapConfig } from "@zaros/market-making/leaves/UsdTokenSwapConfig.sol";
import { UD60x18, ud60x18, convert as ud60x18Convert } from "@prb-math/UD60x18.sol";
import "forge-std/Test.sol";
contract MockVault {
function totalAssets() external view returns (uint256) {
return 1000e18;
}
}
contract StabilityBranchTest is StabilityBranch, Test {
using Vault for Vault.Data;
using UsdTokenSwapConfig for UsdTokenSwapConfig.Data;
uint128 vaultId = 1;
uint256 usdAmountInX18 = 100e18;
uint256 indexPriceX18 = 1e18;
address indexToken;
function setUp() external {
indexToken = address(new MockVault());
Vault.Data storage vault = Vault.load(vaultId);
vault.id = vaultId;
vault.indexToken = indexToken;
vault.marketsRealizedDebtUsd = 800e18;
vault.depositedUsdc = 1354e18;
UsdTokenSwapConfig.Data storage swapConfig = UsdTokenSwapConfig.load();
swapConfig.baseFeeUsd = 1e18;
swapConfig.swapSettlementFeeBps = 300;
swapConfig.maxExecutionTime = 100;
swapConfig.pdCurveYMin = 0e18;
swapConfig.pdCurveYMax = 9e18;
swapConfig.pdCurveXMin = 0.3e18;
swapConfig.pdCurveXMax = 0.8e18;
swapConfig.pdCurveZ = 3e18;
}
function test_getAmountOfAssetOutUnderflow() external {
// D = 800 - 1354 = -554
// V = MockVault.totalAssets() * indexPrice = 1000
// x = 0.554
// Δx = (0.554 - 0.3) / 0.5 = 0.508
// y = 9*Δx^3 = 1.17 > 1
vm.expectRevert(stdError.arithmeticError);
StabilityBranchTest(address(this)).getAmountOfAssetOut(
vaultId, ud60x18(usdAmountInX18), ud60x18(indexPriceX18)
);
}
}

Impact

  • Users will be prevented from swapping USD token to underlying collateral for vaults in credit

Tools Used

Manual Review, Foundry

Recommendations

We need to ensure never grows more than 1.

The upper limit of is , because

and since ,

thus

So we need to ensure is set to be lower than 1

Updates

Lead Judging Commences

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

`UsdTokenSwapConfig.getPremiumDiscountFactor` can underflow and prevent users from swapping USD token to collateral when vault's credit / vaule ratio is above certain threshold

Appeal created

0xtimefliez Auditor
6 months ago
inallhonesty Lead Judge
6 months ago
inallhonesty Lead Judge 5 months ago
Submission Judgement Published
Validated
Assigned finding tags:

`UsdTokenSwapConfig.getPremiumDiscountFactor` can underflow and prevent users from swapping USD token to collateral when vault's credit / vaule ratio is above certain threshold

Support

FAQs

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