https://github.com/OpenEdenHQ/openeden.usdoexpress.audit/tree/f3f31d2ac15e3253cba342229f9d05495f95d6fd
The vulnerability occurs in the quota management logic within setUserQuota(). When a user's quota is set to zero, the function clears authorizedUsers[user] = false and resets their used quota, but does not remove the user from the users array. Subsequently, when reassigning a positive quota to the same user, the condition if (!authorizedUsers[user]) evaluates to true, causing the user to be pushed into the users array again, creating a duplicate entry.
Repeating this reset-and-reassign cycle results in unbounded growth of duplicate entries in the users array, with each cycle adding another duplicate of the same user.
function setUserQuota(address user, uint256 quota) external onlyOwner {
uint256 oldQuota = userQuotas[user];
uint256 usedQuota = usedQuotas[user];
// Update total allocated accounting
if (oldQuota > 0) {
totalAllocated = totalAllocated - oldQuota;
}
if (quota > 0) {
// Check that new quota isn't less than already used amount
if (quota < usedQuota) {
revert QuotaExceedsUsed(quota, usedQuota);
}
// Check if new allocation fits within total liquidity
if (totalAllocated + quota > totalLiquidity) {
revert QuotaExceedsTotal(quota, totalLiquidity - totalAllocated);
}
totalAllocated = totalAllocated + quota;
// Add to users array if new user
if (!authorizedUsers[user]) {
users.push(user);
authorizedUsers[user] = true;
}
} else {
// Removing quota - also clear used quota
authorizedUsers[user] = false;
if (usedQuota > 0) {
totalUsed = totalUsed - usedQuota;
usedQuotas[user] = 0;
}
}
userQuotas[user] = quota;
emit QuotaSet(user, quota);
}
The duplicate entries cause the users array to grow unbounded when quotas are reset to zero and reassigned. This leads to storage bloat and makes operations that enumerate the array increasingly gas-expensive. Functions like getAllUsers() may eventually become unusable due to gas limits when called on-chain with large arrays containing many duplicates.
This behavior can be reproduced through the following sequence:
authorizedUsers[user] = trueauthorizedUsers[user] = false but leaves the user in the users array