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

_curveSwap: getDpxEthPrice and getEthPrice is in wrong order #1558

Open
code423n4 opened this issue Sep 5, 2023 · 5 comments
Open

_curveSwap: getDpxEthPrice and getEthPrice is in wrong order #1558

code423n4 opened this issue Sep 5, 2023 · 5 comments
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working M-05 primary issue Highest quality submission among a set of duplicates selected for report This submission will be included/highlighted in the audit report sufficient quality report This report is of sufficient quality

Comments

@code423n4
Copy link
Contributor

Lines of code

https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L545

Vulnerability details

Impact

When _curveSwap is called with minAmount = 0 (upperDepeg/lowerDepeg use the default slippage 0.5%), the minOut will be a wrong value which leads to slippage protect failure.

Proof of Concept

In _curveSwap, the getDpxEthPrice and getEthPrice is in wrong order:

    uint256 minOut = _ethToDpxEth
      ? (((_amount * getDpxEthPrice()) / 1e8) -
        (((_amount * getDpxEthPrice()) * slippageTolerance) / 1e16))
      : (((_amount * getEthPrice()) / 1e8) -
        (((_amount * getEthPrice()) * slippageTolerance) / 1e16));

When _ethToDpxEth is true, we swap eth for dpxeth. However, we use getDpxEthPrice, which is dpxeth's price in eth (dpxeth/eth). Also, when we swap dpxeth for eth, we use getEthPrice which is eth's price in dpxeth.

Below is a PoC that demonstrates we get the wrong slippage when calling upperDepeg with default slippage tolerance:

// add this to _curveSwap
    amountOut = dpxEthCurvePool.exchange(
      _ethToDpxEth ? int128(int256(a)) : int128(int256(b)),
      _ethToDpxEth ? int128(int256(b)) : int128(int256(a)),
      _amount,
      minAmount > 0 ? minAmount : minOut
    );
    if (!_ethToDpxEth) {
      console.log("getDpxEthPrice = %s > 1e8, swap %s dpxEth for Eth (0.5% slippage):", getDpxEthPrice(), _amount);
      console.log("minOut (wrong slippage) = \t%s", minOut);
      uint256 ideal_Out = (_amount * getDpxEthPrice()) / 1e8;
      uint256 correct_minOut = (ideal_Out - (((_amount * getDpxEthPrice()) * slippageTolerance) / 1e16));
      console.log("minOut (correct slippage) = \t%s", correct_minOut);
      console.log("Actual got Eth amountOut = \t%s", amountOut);
      console.log("Actual slippage = \t\t%s% > 0.5%", (ideal_Out - amountOut)*1e2/ideal_Out);
    }
// tests/rdpxV2-core/Unit.t.sol
function testUpperDepeg_default_slippageTolerance() public {
    // swap weth for dpxETH (price after swap 180000000)
    dpxETH.approve(address(curvePool), 200 * 1e18);
    address coin0 = IStableSwap(curvePool).coins(0);
    if (coin0 == address(weth)) {
      IStableSwap(curvePool).exchange(0, 1, 200 * 1e18, 0);
    } else {
      IStableSwap(curvePool).exchange(1, 0, 200 * 1e18, 0);
    }
    // dpxEth : Eth = 1.8 : 1
    dpxEthPriceOracle.updateDpxEthPrice(180000000);

    // mint dpxEth and swap for Eth, using default slippage (0.5%)
    rdpxV2Core.upperDepeg(10e18, 0);
}

Output:

$ forge test -vv --match-test "testUpperDepeg_default_slippageTolerance"
Running 1 test for tests/rdpxV2-core/Unit.t.sol:Unit
[PASS] testUpperDepeg_default_slippageTolerance() (gas: 246264)
Logs:
  getDpxEthPrice = 180000000 > 1e8, swap 10000000000000000000 dpxEth for Eth (0.5% slippage):
  minOut (wrong slippage) =     5527777722500000000
  minOut (correct slippage) =   17910000000000000000
  Actual got Eth amountOut =    15885460869832720611
  Actual slippage =             11% > 0.5%

Tools Used

Manual Review.

Recommended Mitigation Steps

Reverse the order:

    uint256 minOut = _ethToDpxEth
      ? (((_amount * getEthPrice()) / 1e8) -
        (((_amount * getEthPrice) * slippageTolerance) / 1e16))
      : (((_amount * getDpxEthPrice()) / 1e8) -
        (((_amount * getDpxEthPrice()) * slippageTolerance) / 1e16));

Assessed type

Context

@code423n4 code423n4 added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working labels Sep 5, 2023
code423n4 added a commit that referenced this issue Sep 5, 2023
@c4-pre-sort
Copy link

bytes032 marked the issue as duplicate of #2172

@c4-pre-sort
Copy link

bytes032 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 Sep 12, 2023
@c4-pre-sort
Copy link

bytes032 marked the issue as duplicate of #970

@GalloDaSballo
Copy link

Best POC

@c4-judge c4-judge reopened this Oct 18, 2023
@c4-judge c4-judge added primary issue Highest quality submission among a set of duplicates selected for report This submission will be included/highlighted in the audit report labels Oct 18, 2023
@c4-judge
Copy link
Contributor

GalloDaSballo marked the issue as selected for report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working M-05 primary issue Highest quality submission among a set of duplicates selected for report This submission will be included/highlighted in the audit report sufficient quality report This report is of sufficient quality
Projects
None yet
Development

No branches or pull requests

5 participants