sherlock-audit / 2023-01-uxd-judging

3 stars 1 forks source link

0x52 - Price disparities between spot and perpetual pricing can heavily destabilize UXD #305

Open github-actions[bot] opened 1 year ago

github-actions[bot] commented 1 year ago

0x52

high

Price disparities between spot and perpetual pricing can heavily destabilize UXD

Summary

When minting UXD using PerpDepository.sol the amount of UXD minted corresponds to the amount of vUSD gained from selling the deposited ETH. This is problematic given that Perp Protocol is a derivative rather than a spot market, which means that price differences cannot be directly arbitraged with spot markets. The result is that derivative markets frequently trade at a price higher or lower than the spot price. The result of this is that UXD is actually pegged to vUSD rather than USD. This key difference can cause huge strain on a USD peg and likely depegging.

Vulnerability Detail

function deposit(
    address asset,
    uint256 amount
) external onlyController returns (uint256) {
    if (asset == assetToken) {
        _depositAsset(amount);
        (, uint256 quoteAmount) = _openShort(amount);
        return quoteAmount; // @audit this mint UXD equivalent to the amount of vUSD gained
    } else if (asset == quoteToken) {
        return _processQuoteMint(amount);
    } else {
        revert UnsupportedAsset(asset);
    }
}

PerpDepository#deposit shorts the deposit amount and returns the amount of vUSD resulting from the swap, which effectively pegs it to vUSD rather than USD. When the perpetual is trading at a premium arbitrage will begin happening between the spot and perpetual asset and the profit will be taken at the expense of the UXD peg.

Example: Imagine markets are heavily trending with a spot price of $1500 and a perpetual price of $1530. A user can now buy 1 ETH for $1500 and deposit it to mint 1530 UXD. They can then swap the UXD for 1530 USDC (or other stablecoin) for a profit of $30. The user can continue to do this until either the perpetual price is arbitraged down to $1500 or the price of UXD is $0.98.

Impact

UXD is pegged to vUSD rather than USD which can cause instability and loss of peg

Code Snippet

https://github.com/sherlock-audit/2023-01-uxd/blob/main/contracts/integrations/perp/PerpDepository.sol#L240-L253

Tool used

Manual Review

Recommendation

I recommend integrating with a chainlink oracle and using its price to determine the true spot price of ETH. When a user mints make sure that the amount minted is never greater than the spot price of ETH which will prevent the negative pressure on the peg:

function deposit(
    address asset,
    uint256 amount
) external onlyController returns (uint256) {
    if (asset == assetToken) {
        _depositAsset(amount);
        (, uint256 quoteAmount) = _openShort(amount);

+       spotPrice = assetOracle.getPrice();
+       assetSpotValue = amount.mulwad(spotPrice);

-       return quoteAmount;
+       return quoteAmount <= assetSpotValue ? quoteAmount: assetSpotValue;
    } else if (asset == quoteToken) {
        return _processQuoteMint(amount);
    } else {
        revert UnsupportedAsset(asset);
    }
}
WarTech9 commented 1 year ago

It's a design decision to use the PERP price to determine mint/redeem amounts. We can add oracle pricing in the future to be more robust, but that is not a priority at this moment.

acamill commented 1 year ago

This is a known issue on Solana implementation too. Over the course of the year this offset due to the spread between spot and perp prices always went back to 0. But this is something that we have in mind for later

hrishibhat commented 1 year ago

This is a valid issue in case of certain market conditions or manipulations for the vUSD to trade away from the peg. Considering this issue as a valid medium.

IAm0x52 commented 1 year ago

Sponsor has acknowledged this risk