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

NoyaValueOracle.getValue returns an incorrect price when a multi-token route is used #1430

Open
c4-bot-6 opened this issue May 17, 2024 · 6 comments
Labels
3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working H-03 primary issue Highest quality submission among a set of duplicates 🤖_22_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards selected for report This submission will be included/highlighted in the audit report sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") sufficient quality report This report is of sufficient quality

Comments

@c4-bot-6
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2024-04-noya/blob/9c79b332eff82011dcfa1e8fd51bad805159d758/contracts/helpers/valueOracle/NoyaValueOracle.sol#L89

Vulnerability details

The NoyaValueOracle.getValue is used to convert the price of an asset to baseToken, using token routing when necessary.

If there is no oracle for two tokens, a route needs to be set up between them. This route can then be used to get a value using NoyaValueOracle.getValue.

However, there's a mistake in the NoyaValueOracle.getValue function that makes it give the wrong price.

Impact

The NoyaValueOracle.getValue will return incorrect prices for tokens when the configured priceRoutes[asset][baseToken].length is more than 1.

Proof of Concept

To set a price path for a token pair, the maintainer should use NoyaValueOracle.updatePriceRoute.

For instance, for the SOL to UNI conversion. 1 SOL is roughly equal to 21 UNI, but there's no direct oracle. So, the maintainer sets a route SOLBNBETHUNI.

When _getValue tries to convert 100 SOL into UNI, it should first convert SOLBNB, then BNBETH, and lastly ETHUNI. But, what _getValue really does is to convert SOLBNB, SOLETH, and SOLUNI.

You can see this error in the _getValue function, where asset is used each time instead of quotingToken.

    function _getValue(address asset, address baseToken, uint256 amount, address[] memory sources)
        internal
        view
        returns (uint256 value)
    {
        uint256 initialValue = amount;
        address quotingToken = asset;
        for (uint256 i = 0; i < sources.length; i++) {
>           initialValue = _getValue(asset, sources[i], initialValue);
            quotingToken = sources[i];
        }
        return _getValue(quotingToken, baseToken, initialValue);
    }

The first problem comes up if the SOLBNB, SOLETH, and SOLUNI oracles are not set up. This will cause a revert of _getValue.

    function _getValue(address quotingToken, address baseToken, uint256 amount) internal view returns (uint256) {
        INoyaValueOracle oracle = priceSource[quotingToken][baseToken];
        if (address(oracle) == address(0)) {
            oracle = priceSource[baseToken][quotingToken];
        }
        if (address(oracle) == address(0)) {
            oracle = defaultPriceSource[baseToken];
        }
        if (address(oracle) == address(0)) {
            oracle = defaultPriceSource[quotingToken];
        }
        if (address(oracle) == address(0)) {
>           revert NoyaOracle_PriceOracleUnavailable(quotingToken, baseToken);
        }
        return oracle.getValue(quotingToken, baseToken, amount);
    }

Even if we configure these oracles, the calculated value will still be incorrect.

Consider this example - the _getValue is called with the following parameters:

  • asset = SOL
  • baseToken = UNI
  • amount = 100
  • sources = [BNB, ETH]

This will convert 100 SOL to UNI, using BNB and ETH as the route.

Iteration initialValue quotingToken asset sources[i] initialValue’ quotingToken’
1 100 SOL SOL BNB 100SOL ≈ 25BNB BNB
2 25 BNB SOL ETH 25BNB ≈ 1.25ETH ETH

The result is calculated using quotingToken = ETH, baseToken = UNI, and the initialValue = 1.25, which returns 526.

However, the expected result should be 2094.

Tools Used

Manual Review

Recommended Mitigation Steps

Replace asset with quotingToken:

    function _getValue(address asset, address baseToken, uint256 amount, address[] memory sources)
        internal
        view
        returns (uint256 value)
    {
        uint256 initialValue = amount;
        address quotingToken = asset;
        for (uint256 i = 0; i < sources.length; i++) {
-           initialValue = _getValue(asset, sources[i], initialValue);
+           initialValue = _getValue(quotingToken, sources[i], initialValue);
            quotingToken = sources[i];
        }
        return _getValue(quotingToken, baseToken, initialValue);
    }

Assessed type

Oracle

@c4-bot-6 c4-bot-6 added 3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working labels May 17, 2024
@c4-bot-13 c4-bot-13 added the 🤖_22_group AI based duplicate group recommendation label May 17, 2024
@c4-pre-sort
Copy link

DadeKuma marked the issue as primary issue

@c4-pre-sort c4-pre-sort added the primary issue Highest quality submission among a set of duplicates label May 18, 2024
This was referenced May 18, 2024
@c4-pre-sort
Copy link

DadeKuma marked the issue as sufficient quality report

@c4-pre-sort c4-pre-sort added the sufficient quality report This report is of sufficient quality label May 20, 2024
@HadiEsna
Copy link

true, needs to be fixed

@HadiEsna HadiEsna added the sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") label May 23, 2024
@c4-judge
Copy link
Contributor

c4-judge commented Jun 1, 2024

gzeon-c4 marked the issue as satisfactory

@c4-judge c4-judge added the satisfactory satisfies C4 submission criteria; eligible for awards label Jun 1, 2024
@c4-judge
Copy link
Contributor

c4-judge commented Jun 1, 2024

gzeon-c4 marked the issue as selected for report

@c4-judge c4-judge added the selected for report This submission will be included/highlighted in the audit report label Jun 1, 2024
jacobheun pushed a commit that referenced this issue Jun 4, 2024
@HadiEsna
Copy link

HadiEsna commented Jun 4, 2024

fix in 66d4104e83cc1b68ab117c78c4a92eafac86341c

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 H-03 primary issue Highest quality submission among a set of duplicates 🤖_22_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards selected for report This submission will be included/highlighted in the audit report sponsor confirmed Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity") sufficient quality report This report is of sufficient quality
Projects
None yet
Development

No branches or pull requests

6 participants