Summary
The upgradeTier()
function is intended to upgrade to the next tier. However, the issue lies in how the new tier's minting check is implemented: it checks fromTierIndex + 1
, however it does not check if the highest tier has been reached, leaving no further tiers available.
Vulnerability Details
upgradeTier() is implemented as follows:
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);
}
As you can see, it only validates the upper limit but does not check if fromTierIndex
is already at the highest tier.
Impact
The check for the next tier index is implemented incorrectly, causing the transaction to revert.
Tools Used
Manual review.
Recommendations
The correct implementation should also check if fromTierIndex
is already at the maximum tier.
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(fromTierIndex != 0 && 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);
}