Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Bumpy Tiger Hawk - Updating participation will break core functionalities #658

Open
sherlock-admin2 opened this issue Feb 19, 2025 · 0 comments

Comments

@sherlock-admin2
Copy link
Contributor

Bumpy Tiger Hawk

Medium

Updating participation will break core functionalities

Summary

The updateParticipation function in the Launch contract incorrectly uses currencyAmount and userToken amounts, which are from different tokens, causing faulty accounting. This primarily impacts the cancellation of non-finalized launch group participations, making the core functionality of cancelling participation non-executable.

Root Cause

In the following code section of the updateParticipation function there is a "conceptual issue", that the currencyAmount (refund and additional) is used for setting and comparing with the userToken amount, which are the values from two different tokens.

if (prevInfo.currencyAmount > newCurrencyAmount) {
            // Calculate refund amount
            uint256 refundCurrencyAmount = prevInfo.currencyAmount - newCurrencyAmount;
            // Validate user new requested token amount is greater than min token amount per user
            if (userTokenAmount - refundCurrencyAmount < settings.minTokenAmountPerUser) {
                revert MinUserTokenAllocationNotReached(
                    request.launchGroupId, request.userId, userTokenAmount, request.tokenAmount
                );
            }
            // Update total tokens requested for user for launch group
            userTokens.set(request.userId, userTokenAmount - refundCurrencyAmount);
            // Transfer payment currency from contract to user
            IERC20(request.currency).safeTransfer(msg.sender, refundCurrencyAmount);
        } else if (newCurrencyAmount > prevInfo.currencyAmount) {
            // Calculate additional payment amount
            uint256 additionalCurrencyAmount = newCurrencyAmount - prevInfo.currencyAmount;
            // Validate user new requested token amount is within launch group user allocation limits
            if (userTokenAmount + additionalCurrencyAmount > settings.maxTokenAmountPerUser) {
                revert MaxUserTokenAllocationReached(
                    request.launchGroupId, request.userId, userTokenAmount, request.tokenAmount
                );
            }
            // Update total tokens requested for user for launch group
            userTokens.set(request.userId, userTokenAmount + additionalCurrencyAmount);
            // Transfer payment currency from user to contract
            IERC20(request.currency).safeTransferFrom(msg.sender, address(this), additionalCurrencyAmount);
        }

Specifically these lines, will mostly affect the cancelation of the participation which is core functionality of the lauchGroup with the finalizesAtParticipation parameter set to false:

userTokens.set(request.userId, userTokenAmount - refundCurrencyAmount);
userTokens.set(request.userId, userTokenAmount + additionalCurrencyAmount);

https://github.com/sherlock-audit/2025-02-rova/blob/53fb6d71d253676bfbd00926e8f217f40c62d8c5/rova-contracts/src/Launch.sol#L361
https://github.com/sherlock-audit/2025-02-rova/blob/53fb6d71d253676bfbd00926e8f217f40c62d8c5/rova-contracts/src/Launch.sol#L374

Internal Pre-conditions

For Cancelation revert:
TokenPriceBps != 1

External Pre-conditions

/

Attack Path

State of the Launch contract:
minAmountPerUser: 500
maxAmountPerUser: 3000
tokenPriceBps: 2

Attack path for cancelation:

  1. User joins launchGroup with request of 800 tokenAmount, so the currency amount is 1600
  2. User updates participation, so the request for the tokenAmount is 700 launchToken
  3. Due to incorrect accounting, wrong value is accounted as userTokens value and instead of 700, it will be 600
  4. If user tries to cancel participation it will fail, because userTokenAmout - info.tokenAmount will underflow, because userTokenAmount is 600 and info.tokenAmount is 700, and the cancelation will revert

Impact

If update of participation is done, the cancelation of the participation will fail, which is breaking core functionality, since it is intended by protocol, that the lauchGroups that are not finalized at participation should be cancelable (could loose currency tokens paid if get finalized, which will lead in getting launch tokens that user didn't want since he wanted to cancel participation). Furthermore, if the duration of the lauchGroup is long enough (longer than 1 week), then one more problem will arise, and that's that the users could have their funds locked for longer than a week.

PoC

No response

Mitigation

Consider using the request.tokenAmount in:

  • checks weather the token amount is greater or not then min and max amount
  • and when calling userTokens.set()
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant