Project

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

Missing Event Emission in `MembershipFactory::updateDAOMembership` Function

Summary

The updateDAOMembership function in the MembershipFactory contract lacks event emission for critical state changes. This function modifies core DAO configurations including tier structures and maximum member limits without emitting any events to track these modifications. This omission significantly impacts the contract's transparency and makes it difficult for off-chain services to track and react to DAO configuration changes.

Vulnerability Details

Location: MembershipFactory.sol - updateDAOMembership function (L144-178)

function updateDAOMembership(string calldata ensName, TierConfig[] memory tierConfigs)
external onlyRole(EXTERNAL_CALLER) returns (address) {
address daoAddress = getENSAddress[ensName];
require(tierConfigs.length <= TIER_MAX, "Invalid tier count.");
require(tierConfigs.length > 0, "Invalid tier count.");
require(daoAddress != address(0), "DAO does not exist.");
DAOConfig storage dao = daos[daoAddress];
if(dao.daoType == DAOType.SPONSORED){
require(tierConfigs.length == TIER_MAX, "Invalid tier count.");
}
uint256 maxMembers = 0;
// Preserve minted values and adjust the length of dao.tiers
for (uint256 i = 0; i < tierConfigs.length; i++) {
if (i < dao.tiers.length) {
tierConfigs[i].minted = dao.tiers[i].minted;
}
}
// Reset and update the tiers array
delete dao.tiers;
for (uint256 i = 0; i < tierConfigs.length; i++) {
dao.tiers.push(tierConfigs[i]);
maxMembers += tierConfigs[i].amount;
}
// updating the ceiling limit acc to new data
if(maxMembers > dao.maxMembers){
dao.maxMembers = maxMembers;
}
dao.noOfTiers = tierConfigs.length;
return daoAddress;
}

The function modifies several critical state variables:

Updates the tier configurations array (dao.tiers)
Modifies the maximum member limit (dao.maxMembers)
Updates the number of tiers (dao.noOfTiers)

However, no events are emitted to track these changes, unlike other state-changing functions in the contract such as createNewDAOMembership which emits the MembershipDAONFTCreated event.

Contrast with the proper event emission in createNewDAOMembership:

emit MembershipDAONFTCreated(daoConfig.ensname, address(proxy), dao);

Impact

  • Transparency Loss:

    • Off-chain services cannot track DAO configuration changes

    • Difficulty in maintaining UI synchronization with contract state

  • Operational Challenges:

    • DAO members have no way to receive notifications about tier structure changes

    • Historical tracking of DAO evolution becomes impossible

    • Potential synchronization issues between front-end applications and contract state

  • Integration Issues:

    • Third-party integrations cannot react to DAO updates

    • Indexing services miss critical state changes

    • Analytics platforms receive incomplete data

Tools Used

Manual code review

Recommendations

Add an event emission at the end of the updateDAOMembership function:

// Add event definition
event DAOUpdated(
string indexed ensName,
address indexed daoAddress,
uint256 previousMaxMembers,
uint256 newMaxMembers,
uint256 newNoOfTiers,
TierConfig[] newTiers
);
// Modify function to emit event
function updateDAOMembership(string calldata ensName, TierConfig[] memory tierConfigs)
external onlyRole(EXTERNAL_CALLER) returns (address) {
address daoAddress = getENSAddress[ensName];
// ... existing code ...
uint256 previousMaxMembers = dao.maxMembers;
// ... existing code ...
dao.noOfTiers = tierConfigs.length;
emit DAOUpdated(
ensName,
daoAddress,
previousMaxMembers,
dao.maxMembers,
dao.noOfTiers,
tierConfigs
);
return daoAddress;
}
Updates

Lead Judging Commences

0xbrivan2 Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
0xbrivan2 Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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