Project

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

Upgrading Tier functionality can bypass the maximum amount of token permitted for a particular Tier.

Summary

When creating DAOs, the creator specifies the maximum number of tokens that can be minted for each tier. This number is compared to the total number of tokens minted when joining the DAO to ensure that members don't exceed this amount. The problem lies when a member is upgrading their token tier. The amount is not compared to the amount minted, which will lead to tiers having more tokens than what was designed.

Vulnerability Details

The joinDAO function, ensures that the total tokens minted don't exceed the total supply specified for a token tier and increases the amount of tokens minted for that tier.

https://github.com/Cyfrin/2024-11-one-world/blob/main/contracts/dao/MembershipFactory.sol#L140

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);
}

The issue lies with the UpgradeTier function, this function burns two tokens from the current tier and mints a new token in the next tier, the problem here is that the maximum amount for the minted tier is not checked, so the token minted can exceed the initial amount set for that tier.

https://github.com/Cyfrin/2024-11-one-world/blob/main/contracts/dao/MembershipFactory.sol#L155

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);
}

For example, the maximum amount set for Tier 3 is 10, and 10 tokens have been minted for Tier 3.

Let's say Alice calls joinDAOwith a tierIndex of 3 this call will revert because it is currently full.

Alice can bypass this maximum number by minting two tokens on Tier 4 and then upgrading to Tier 3.

This will increase the total amount of tokens on tier 3 to 11, thereby exceeding the maximum amount which is 10.

Impact

Tiers will have more than the specified members which is not the intended design

Tools Used

Manual Analysis

Recommendations

This simple fix below will do;

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.");
+ require(daos[daoMembershipAddress].tiers[fromTierIndex - 1].amount > daos[daoMembershipAddress].tiers[fromTierIndex - 1].minted, "Tier full.");
IMembershipERC1155(daoMembershipAddress).burn(_msgSender(), fromTierIndex, 2);
IMembershipERC1155(daoMembershipAddress).mint(_msgSender(), fromTierIndex - 1, 1);
+ daos[daoMembershipAddress].tiers[fromTierIndex - 1].minted += 1;
+ daos[daoMembershipAddress].tiers[fromTierIndex].minted -= 2;
emit UserJoinedDAO(_msgSender(), daoMembershipAddress, fromTierIndex - 1);
}

This line require(daos[daoMembershipAddress].tiers[fromTierIndex - 1].amount > daos[daoMembershipAddress].tiers[fromTierIndex - 1].minted, "Tier full."); ensures that the intended tier is not full.

The line daos[daoMembershipAddress].tiers[fromTierIndex - 1].minted += 1; increases the amount minted for the new Tier and daos[daoMembershipAddress].tiers[fromTierIndex].minted -= 2, reduces the amount burned on the current Tier.

Updates

Lead Judging Commences

0xbrivan2 Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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

Give us feedback!