Project

One World
NFTDeFi
15,000 USDC
View results
Submission Details
Severity: high
Invalid

Race Conditions in `joinDAO` function leading to overfilled tiers

Summary

The joinDao function allows users to join a DAO by purchasing membership in a specific tier. The function performs checks to ensure that the tiers is not full before allowing users to join. However, there is a vulnerability in the form of a race condition that could allow multiple users to join a tier that is already full. This vulnerability arises due to the lack of synchronization between the tier capacity check and the actual state update, leading to inconsistent and erroneous tier membership.

Vulnerability Details

The issue exists in the way the joinDAO function handles the tier full check. The function checks if a tier is full with the condition;

function joinDAO(address daoMembershipAddress, uint256 tierIndex) external {
require(daos[daoMembershipAddress].noOfTiers > tierIndex, "Invalid tier.");
require(daos[daoMembershipAddress].tiers[tierIndex].amount > daos[daoMembershipAddress].tiers[tierIndex].minted, "Tier full.");
uint256 tierPrice = daos[daoMembershipAddress].tiers[tierIndex].price;
uint256 platformFees = (20 * tierPrice) / 100;
daos[daoMembershipAddress].tiers[tierIndex].minted += 1;
IERC20(daos[daoMembershipAddress].currency).transferFrom(_msgSender(), owpWallet, platformFees);
IERC20(daos[daoMembershipAddress].currency).transferFrom(_msgSender(), daoMembershipAddress, tierPrice - platformFees);
IMembershipERC1155(daoMembershipAddress).mint(_msgSender(), tierIndex, 1);
emit UserJoinedDAO(_msgSender(), daoMembershipAddress, tierIndex);
}

If the condition passes(i.e. the tier is not full, the user proceeds with the payment and the membership minting process. However, if multiple users attempt to join the same tier, they may all pass the check before the tier's minted count is updated. This leads to a race condition where more users are able to join a tier than the specified limit (amount), violating the tier's maximum membership capacity

Scenario

  1. User 1 calls joinDAO for Tier 2. The contract checks if the tier is full, and since the tier has space (minted<amount), the transaction continues.

  2. User 2 calls joinDAO for Tier 2 shortly after. The contract again checks if the tier is full, and since the tier still has space (minted<amount), User 2's transaction proceeds.

  3. Both users pass the require statement check, and their payments are transferred successfully.

  4. However, before the minted value is updated after both transactions, the actual number of users in the tier exceeds the specified amount resulting in the tier being overfilled.

  5. This leads to User 1 and User 2 being added to the tier despite the tier's maximum membership being reached, causing discrepancies in the DAO's tier structure.

Impact

  • Multiple users may join a tier though the tier has already reached its membership limit. This causes inconsistency between the actual number of members and the expected number based on the amount field of the tier configuration.

  • The minted count, which tracks the number of users in a tier, becomes inaccurate. This could results in future operations depending on the correct minted count being incorrectly handled.

Tools Used

Manual Review

Recommendations

Implement a locking mechanism to ensure that no other transaction can modify the state of the tier while another user is attempting to join. This prevents concurrent transactions from bypassing the tier full check

Updates

Lead Judging Commences

0xbrivan2 Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
0xbrivan2 Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!