Project

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

Missing update will lead to new members not able to join even when capacity is not reached

Summary

In MembershipFactory users could join tiers by purchasing membership via joinDao function that looks like this :

/// @notice Allows a user to join a DAO by purchasing a membership NFT at a specific tier
/// @param daoMembershipAddress The address of the DAO membership NFT
/// @param tierIndex The index of the tier to join
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);
}

After checking and passing tier index and if there are available memberships the function will update daos mapping with minted amount and transfer funds from sender and mint the nft to the sender with correct tier index and amount.

The users could upgrade their tier via upgradeTier function and within sponsored daos by burning 2 NFT's from their current tier and minting 1 NFT for the next tier and function looks like this:

/// @notice Allows users to upgrade their tier within a sponsored DAO
/// @param daoMembershipAddress The address of the DAO membership NFT
/// @param fromTierIndex The current tier index of the user
function upgradeTier(address daoMembershipAddress, uint256 fromTierIndex) external {
require(daos[daoMembershipAddress].daoType == DAOType.SPONSORED, "Upgrade not allowed.");
require(daos[daoMembershipAddress].noOfTiers >= fromTierIndex + 1, "No higher tier available.");
IMembershipERC1155(daoMembershipAddress).burn(_msgSender(), fromTierIndex, 2);
IMembershipERC1155(daoMembershipAddress).mint(_msgSender(), fromTierIndex - 1, 1);
emit UserJoinedDAO(_msgSender(), daoMembershipAddress, fromTierIndex - 1);
}

Vulnerability Details

The issue here is that upgradeTier does not update daos mapping when upgrade happen and this will lead that new members could not join when there is available room.

PoC:

Lets say the user want to upgrade from tier 7 to tier 6 and tier 7 reached its capacity (for example lets say capacity is 500).
When upgrading as we mentioned before user need to burn 2 nft, so the capacity should be 498/500 after the upgrade is done. This should leave room for new members to join the current tier. But since it is not updated anywhere the new users would not be able to join (even tho they should) because protocol will think the tier is still full and because this requiremend in joinDAO would revert :

require(daos[daoMembershipAddress].tiers[tierIndex].amount > daos[daoMembershipAddress].tiers[tierIndex].minted, "Tier full.");

Impact

Due to missing update new members would not be able to join and that will cost protocol of potential profit also.

Tools Used

Manual Review.

Recommendations

Make the following changes to the upgradeTier function:

function upgradeTier(address daoMembershipAddress, uint256 fromTierIndex) external {
require(daos[daoMembershipAddress].daoType == DAOType.SPONSORED, "Upgrade not allowed.");
require(daos[daoMembershipAddress].noOfTiers >= fromTierIndex + 1, "No higher tier available.");
+ daos[daoMembershipAddress].tiers[fromTierIndex].minted -= 2;
+ daos[daoMembershipAddress].tiers[fromTierIndex - 1].minted += 1;
IMembershipERC1155(daoMembershipAddress).burn(_msgSender(), fromTierIndex, 2);
IMembershipERC1155(daoMembershipAddress).mint(_msgSender(), fromTierIndex - 1, 1);
emit UserJoinedDAO(_msgSender(), daoMembershipAddress, fromTierIndex - 1);
}

This will correctly update data in both tiers.

Updates

Lead Judging Commences

0xbrivan2 Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Appeal created

mrmorningstar Submitter
10 months ago
0xbrivan2 Lead Judge
10 months ago
0xbrivan2 Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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