Project

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

Tier pricing is not applied on `upgradeTier`, thus lower tier can upgrade without paying fee as targeted tier (assuming higher tier, higher pricing)

Summary

The upgradeTier function does not enforce a fee check, allowing users to bypass tier-specific pricing.

Vulnerability Details

The joinDAO function calculates and charges a tier-specific price when joining a DAO tier, as shown below:

File: MembershipFactory.sol
140: function joinDAO(address daoMembershipAddress, uint256 tierIndex) external {
141: require(daos[daoMembershipAddress].noOfTiers > tierIndex, "Invalid tier.");
142: require(daos[daoMembershipAddress].tiers[tierIndex].amount > daos[daoMembershipAddress].tiers[tierIndex].minted, "Tier full.");
143: @> uint256 tierPrice = daos[daoMembershipAddress].tiers[tierIndex].price;
144: @> uint256 platformFees = (20 * tierPrice) / 100;
145: daos[daoMembershipAddress].tiers[tierIndex].minted += 1;
146: @> IERC20(daos[daoMembershipAddress].currency).transferFrom(_msgSender(), owpWallet, platformFees);
147: @> IERC20(daos[daoMembershipAddress].currency).transferFrom(_msgSender(), daoMembershipAddress, tierPrice - platformFees);
148: IMembershipERC1155(daoMembershipAddress).mint(_msgSender(), tierIndex, 1);
149: emit UserJoinedDAO(_msgSender(), daoMembershipAddress, tierIndex);
150: }

In contrast, the upgradeTier function does not perform a fee check, meaning users could join a lower-cost tier and upgrade without paying the higher tier’s price. This could suggest that all tiers are intended to have the same price, which may not align with the intended tier classification structure unless following a first-come, first-served (FCFS) model.

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

Impact

Users can avoid paying the appropriate tier price by initially joining a lower-priced tier and then upgrading without an additional fee.

Tools Used

Manual analysis

Recommendations

Add a fee check in the upgradeTier function to enforce tier-specific pricing when upgrading and/or require some additional payment or refund when there is discrepancy between the tier pricing.

Updates

Lead Judging Commences

0xbrivan2 Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Appeal created

chainnue Submitter
10 months ago
0xbrivan2 Lead Judge
10 months ago
0xbrivan2 Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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