Omniscia Boson Protocol Audit
SellerHandlerFacet Manual Review Findings
SellerHandlerFacet Manual Review Findings
SHF-01M: Incorrect Iterator Usage
| Type | Severity | Location |
|---|---|---|
| Logical Fault | ![]() | SellerHandlerFacet.sol:L277 |
Description:
The nested for loop within the SellerHandlerFacet::optInToSellerUpdate function re-uses the i variable of the outer loop instead of declaring a new one. As such, the inner loop can corrupt the outer loop's iteration.
Impact:
If the SellerHandlerFacet::optInToSellerUpdate function is invoked with multiple _fieldsToUpdate, the iterator will potentially skip or repeat fields to update as it will jump from i to collectionCount, the latter of which can be greater than or lower than the expected value of i + 1.
Example:
contracts/protocol/facets/SellerHandlerFacet.sol
233for (uint256 i = 0; i < _fieldsToUpdate.length; i++) {234 SellerUpdateFields role = _fieldsToUpdate[i];235
236 // Approve admin update237 if (role == SellerUpdateFields.Admin && sellerPendingUpdate.admin != address(0)) {238 require(sellerPendingUpdate.admin == sender, UNAUTHORIZED_CALLER_UPDATE);239
240 preUpdateSellerCheck(_sellerId, sender, lookups);241
242 // Delete old seller id by admin mapping243 delete lookups.sellerIdByAdmin[seller.admin];244
245 // Update admin246 seller.admin = sender;247
248 // Store new seller id by admin mapping249 lookups.sellerIdByAdmin[sender] = _sellerId;250
251 // Delete pending update admin252 delete sellerPendingUpdate.admin;253
254 // Delete auth token for seller id if it exists255 if (authToken.tokenType != AuthTokenType.None) {256 delete lookups.sellerIdByAuthToken[authToken.tokenType][authToken.tokenId];257 delete protocolEntities().authTokens[_sellerId];258 }259
260 updateApplied = true;261 } else if (role == SellerUpdateFields.Assistant && sellerPendingUpdate.assistant != address(0)) {262 // Approve assistant update263 require(sellerPendingUpdate.assistant == sender, UNAUTHORIZED_CALLER_UPDATE);264
265 preUpdateSellerCheck(_sellerId, sender, lookups);266
267 // Delete old seller id by assistant mapping268 delete lookups.sellerIdByAssistant[seller.assistant];269
270 // Update assistant271 seller.assistant = sender;272
273 // Transfer ownership of voucher contract to new assistant274 IBosonVoucher(lookups.cloneAddress[_sellerId]).transferOwnership(sender); // default voucher contract275 Collection[] storage sellersAdditionalCollections = lookups.additionalCollections[_sellerId];276 uint256 collectionCount = sellersAdditionalCollections.length;277 for (i = 0; i < collectionCount; i++) {278 // Additional collections (if they exist)279 IBosonVoucher(sellersAdditionalCollections[i].collectionAddress).transferOwnership(sender);280 }Recommendation:
We advise a new iterator to be declared (i.e. j) to ensure that the loops do not affect each other's iterators.
Alleviation (2b9f60b6c3323fd234b570089ceff924cdb5851c):
The inner loop iterator has been correctly updated to a new variable labelled j, alleviating this exhibit.
