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

MarsellusWallace - Insecure Token Transfer Methods #9

Closed
sherlock-admin2 opened this issue Jul 25, 2024 · 3 comments
Closed

MarsellusWallace - Insecure Token Transfer Methods #9

sherlock-admin2 opened this issue Jul 25, 2024 · 3 comments
Labels
Excluded Excluded by the judge without consulting the protocol or the senior Non-Reward This issue will not receive a payout 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 Jul 25, 2024

MarsellusWallace

Medium

Insecure Token Transfer Methods

Summary

Ser Marry

Vulnerability Detail

The contract contains several functions (claimWithdraw, claim_, and finishDistribution) that interact with ERC20 tokens. These functions use the .transfer method for sending tokens, However, the .transfer method does not throw an exception or revert the transaction if the transfer fails. Instead, it simply returns a boolean indicating success or failure. If the recipient of the transfer is a contract that does not handle ERC20 token transfers correctly (i.e., it does not have a fallback function that can accept ERC20 tokens), the .transfer call will succeed from the perspective of the calling contract, but the tokens will not be received by the intended recipient. This leads to a silent failure, where the contract believes the transfer was successful, but in reality, the tokens were not moved.
Example Code Snippet:

function claimWithdraw(IERC20 reward, address account, uint256 amount) internal {
    uint256 balance = balanceOf(account); // @audit whenNotPaused
    uint256 numerator = claimed[account][reward] * amount;
    uint256 claimedAmount = numerator == 0 ? 0 : (numerator - 1) / balance + 1;
    claimed[account][reward] -= claimedAmount;

    numerator = saved[account][reward] * amount;
    uint256 savedAmount = numerator == 0 ? 0 : (numerator - 1) / balance + 1;
    saved[account][reward] -= savedAmount;

    uint256 claimableAmount = Math.max(rawClaimable(reward, account, amount), claimedAmount); // due to excess exposure
    uint256 claimAmount = claimableAmount - claimedAmount;
    if (claimAmount != 0) {
      reward.transfer(account, claimAmount); << @audit-ok
      emit RewardPaid(reward, account, claimAmount);
    }

    uint256 rawEarned = earned(reward, account, amount);
    // due to rounding
    uint256 saveAmount = rawEarned <= claimableAmount + savedAmount ? 0 : rawEarned - claimableAmount - savedAmount;
    if (saveAmount != 0) reward.transfer(savings, saveAmount); << @audit-ok
  }

Also in claim_ function:

      if (saveAmount != 0) {
        saved[msg.sender][reward] = savedAmount + saveAmount;
        reward.transfer(savings, saveAmount); << @audit-ok
      }
    }
    if (claimAmount != 0) {
      reward.transfer(msg.sender, claimAmount); << @audit-ok
      emit RewardPaid(reward, msg.sender, claimAmount);
    }

And in the finishDistribution function:

 function finishDistribution(IERC20 reward) public onlyRole(DEFAULT_ADMIN_ROLE) onlyReward(reward) {
    updateIndex(reward);

    if (block.timestamp < rewards[reward].finishAt) {
      uint256 finishAt = rewards[reward].finishAt;
      rewards[reward].finishAt = uint40(block.timestamp);
      reward.transfer(savings, (finishAt - block.timestamp) * rewards[reward].rate); << @audit-ok
    }

    emit DistributionFinished(reward, msg.sender);
  }

In the above snippet, the claimWithdraw function uses reward.transfer(account, claimAmount) to send tokens to an account. If account is a contract that does not handle ERC20 tokens correctly, this transfer will fail silently.

Impact

The primary impact of this vulnerability is the potential loss of tokens. Users expecting to receive their rewards may find that their balances remain unchanged, leading to confusion and frustration. Additionally, this vulnerability could be exploited by attackers to drain tokens from the contract under certain conditions, such as if the contract is tricked into sending tokens to a malicious contract controlled by an attacker.

Code Snippet

StakedEXA.sol#L202
StakedEXA.sol#L195
StakedEXA.sol#L390
StakedEXA.sol#L394
StakedEXA.sol#L431

Tool used

Manual Review

Recommendation

The contract should use the SafeERC20 library's safeTransfer method instead of the native .transfer method. The SafeERC20 library checks if the recipient is a contract and, if so, calls its fallback function instead of directly sending tokens. This ensures that the contract behaves correctly even when interacting with other contracts.

@github-actions github-actions bot added Has Duplicates A valid issue with 1+ other issues describing the same vulnerability Excluded Excluded by the judge without consulting the protocol or the senior labels Jul 28, 2024
@z3s
Copy link
Collaborator

z3s commented Jul 30, 2024

Invalid; From README:

only fully ERC-20 compliant tokens without weird traits.

@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 Jul 30, 2024
@sherlock-admin2 sherlock-admin2 changed the title Curly Vanilla Barracuda - Insecure Token Transfer Methods MarsellusWallace - Insecure Token Transfer Methods Aug 9, 2024
@sherlock-admin2 sherlock-admin2 added Non-Reward This issue will not receive a payout and removed Has Duplicates A valid issue with 1+ other issues describing the same vulnerability labels Aug 9, 2024
@sherlock-admin2
Copy link
Contributor Author

The protocol team fixed this issue in the following PRs/commits:
exactly/protocol#756

@sherlock-admin2
Copy link
Contributor Author

The Lead Senior Watson signed off on the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Excluded Excluded by the judge without consulting the protocol or the senior Non-Reward This issue will not receive a payout 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

3 participants