Lucene search

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

The user has the ability to bypass a fee claim protection for their own benefit while purchasing tokens

2023-11-1700:00:00
Code4rena
github.com
3
vulnerability
fee claim protection
token purchase
multiple purchases
reward calculation
security audit
mitigation steps
code documentation
smart contract

AI Score

7

Confidence

Low

Lines of code

Vulnerability details

Impact

User can bypass a fee claim protection for his own benefit by making multiple purchases instead of one, and as the result claim a fee part by part.
Due to code documentation: The reward calculation has to use the old rewards value (pre fee-split) to not include the fees of this buy

<https://github.com/code-423n4/2023-11-canto/blob/main/1155tech-contracts/src/Market.sol#L150-L169&gt;

        require(shareData[_id].creator != msg.sender, "Creator cannot buy");
        (uint256 price, uint256 fee) = getBuyPrice(_id, _amount); // Reverts for non-existing ID
        SafeERC20.safeTransferFrom(token, msg.sender, address(this), price + fee);
        // The reward calculation has to use the old rewards value (pre fee-split) to not include the fees of this buy

        // @audit Fee protection here
        // The rewardsLastClaimedValue then needs to be updated with the new value such that the user cannot claim fees of this buy
        uint256 rewardsSinceLastClaim = _getRewardsSinceLastClaim(_id);
        // Split the fee among holder, creator and platform
        _splitFees(_id, fee, shareData[_id].tokensInCirculation);


        rewardsLastClaimedValue[_id][msg.sender] = shareData[_id].shareHolderRewardsPerTokenScaled;

Proof of Concept

Let’s check two cases, how it intended to be and how it can be bypassed.

A. How it intended

  1. User buy 100 tokens from the market - Market.buy(id, 100).

  2. Fee is not collected but stored to rewardsLastClaimedValue[_id][msg.sender] after _splitFees() calculation.
    <https://github.com/code-423n4/2023-11-canto/blob/335930cd53cf9a137504a57f1215be52c6d67cb3/1155tech-contracts/src/Market.sol#L280-L296&gt;

       if (_tokenCount &gt; 0) {
           shareData[_id].shareHolderRewardsPerTokenScaled += (shareHolderFee * 1e18) / _tokenCount;
       } else {
           // If there are no tokens in circulation, the fee goes to the platform
           platformFee += shareHolderFee;
       }
    

    rewardsLastClaimedValue[_id][msg.sender] = shareData[_id].shareHolderRewardsPerTokenScaled;

  3. Next user interaction will get the reward fee.

B) Bypass.

  1. User buy 100 tokens one by one from the market - Market.buy(id, 1)…
  2. 99 buy operations will collect fees. All except first.
  3. Reward fee for next user will be small.

Tools Used

Manual audit

Recommended Mitigation Steps

Add a threshold for getting the reward(based on msg.sender for example).

Assessed type

Other


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

All reactions

AI Score

7

Confidence

Low