Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Price Denominator logic return wrong results if underlying assets have decimals other than 8 #300

Closed
code423n4 opened this issue Sep 19, 2022 · 1 comment
Labels
3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working duplicate This issue or pull request already exists edited-by-warden satisfactory satisfies C4 submission criteria; eligible for awards sponsor acknowledged Technically the issue is correct, but we're not going to resolve it for XYZ reasons

Comments

@code423n4
Copy link
Contributor

code423n4 commented Sep 19, 2022

Lines of code

https://github.com/code-423n4/2022-09-y2k-finance/blob/2175c044af98509261e4147edeb48e1036773771/src/oracles/PegOracle.sol#L67-L82

Vulnerability details

Impact

The project implements a price oracle in order to get the relative price between the pegged asset and the price of the original asset (example: stETH to ETH). If the ratio (the pegged asset divided by the original asset) is 1 the Token is pegged, otherwise is depegged.

Bellow is a code snippet from the PegOracle.sol function.

 if (price1 > price2) {
            nowPrice = (price2 * 10000) / price1;
        } else {
            nowPrice = (price1 * 10000) / price2;
        }

        int256 decimals10 = int256(10**(18 - priceFeed1.decimals()));
        nowPrice = nowPrice * decimals10;

        return (
            roundID1,
            nowPrice / 1000000,
            startedAt1,
            timeStamp1,
            answeredInRound1
        );
    }

To fetch the ratio at any time, the PegOracle.sol performs some calculations; first the relative price is multiplied by 1e4 and then it returns the above calculation divided by 1e6.

The Controller.sol file makes an external call to the PegOracle.sol oracle to get the relative price. After, the value returned, it is multiplied by 10**(18-(priceFeed.decimals()) and the result represents the relative price between the two assets.

The result is converted to 18 decimal points in order to be compared with the Strike Price passed by the admin on VaultFactory.sol.

While the decimal calculation logic appear to works when decimals == 8, it seems that it won't work when the decimals are different than 8. The impact is relative big, since the whole project depends on the ratio of the price oracles of the two assets.

Proof of Concept

Lets say that we have two assets, A and B, having 6 decimals. Assuming that the oracle of two assets report prices of 400 * 10 ** 6 = 400000000 and 399 * 10 ** 6 = 399000000 , their relative price transformed to 18 decimals is :
uint256(scalePriceTo18(priceA, 6) * 1e18 / scalePriceTo18(priceB, 6)) = 1002506265664160401

where scalePriceTo18 :

function scalePriceTo18(int256 _price, uint8 _priceDecimals)
        internal
        pure
        returns (int256)
    {
        if (_priceDecimals < 18) {
            return _price * int256(10 ** uint256(18 - _priceDecimals));
        } else if (_priceDecimals > 18) {
            return _price * int256(10 ** uint256(_priceDecimals - 18));
        }
        return _price;
    }

By using the formula provided in Controller.soland PegOracle.sol the result is 10025000000000000000000 which has 4 more decimals than the correct result.

The decimal calculation performed by the y2k codebase is :
x / y * (10 ^ 4 * 10 ^ 12 * 10 ^12) / (10 ^ 6) = (x * 10 ^ 22 / y)

Tools Used

Manual Code Review

Recommended Mitigation Steps

Since the 2 assets are required to having the same amount of decimals a formula that transforms the relative price to 1e18 could be:
x * 1e18 / y .

An example that Chainlink implements, that includes a scalePrice function, in order to find a different price denominator could be found here

@code423n4 code423n4 added 3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working labels Sep 19, 2022
code423n4 added a commit that referenced this issue Sep 19, 2022
@code423n4 code423n4 changed the title Price Denominator logic doesn't work with underlying assets having decimals other than 8 Price Denominator logic return wrong results if underlying assets have decimals other than 8 Sep 19, 2022
@MiguelBits MiguelBits added the duplicate This issue or pull request already exists label Sep 23, 2022
@0xnexusflip 0xnexusflip added resolved Finding has been patched by sponsor (sponsor pls link to PR containing fix) sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") labels Sep 28, 2022
@0xnexusflip 0xnexusflip removed resolved Finding has been patched by sponsor (sponsor pls link to PR containing fix) sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") labels Sep 29, 2022
@MiguelBits MiguelBits added sponsor acknowledged Technically the issue is correct, but we're not going to resolve it for XYZ reasons and removed duplicate This issue or pull request already exists labels Oct 3, 2022
@HickupHH3
Copy link
Collaborator

dup of #195

@HickupHH3 HickupHH3 added duplicate This issue or pull request already exists satisfactory satisfies C4 submission criteria; eligible for awards labels Oct 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working duplicate This issue or pull request already exists edited-by-warden satisfactory satisfies C4 submission criteria; eligible for awards sponsor acknowledged Technically the issue is correct, but we're not going to resolve it for XYZ reasons
Projects
None yet
Development

No branches or pull requests

4 participants