Assessment reports>Cove>Medium findings>Missing mapping update in ,BasketToken.updateBitFlag(), causes rebalancing failure
Category: Coding Mistakes

Missing mapping update in BasketToken.updateBitFlag() causes rebalancing failure

Medium Severity
Medium Impact
Low Likelihood

Description

The updateBitFlag() function does not update the basketAssetToIndexPlusOne mapping after adding a new asset to the registry. This leads to errors during rebalancing when the rebalance cannot locate the new asset.

function updateBitFlag(address basket, uint256 bitFlag) external onlyRole(_TIMELOCK_ROLE) {
    // Checks
    // Check if basket exists
    uint256 indexPlusOne = _bmStorage.basketTokenToIndexPlusOne[basket];
    if (indexPlusOne == 0) {
        revert BasketTokenNotFound();
    }
    uint256 currentBitFlag = BasketToken(basket).bitFlag();
    if (currentBitFlag == bitFlag) {
        revert BitFlagMustBeDifferent();
    }
    // Check if the new bitFlag is inclusive of the current bitFlag
    if ((currentBitFlag & bitFlag) != currentBitFlag) {
        revert BitFlagMustIncludeCurrent();
    }
    address strategy = BasketToken(basket).strategy();
    if (!WeightStrategy(strategy).supportsBitFlag(bitFlag)) {
        revert BitFlagUnsupportedByStrategy();
    }
    bytes32 newId = keccak256(abi.encodePacked(bitFlag, strategy));
    if (_bmStorage.basketIdToAddress[newId] != address(0)) {
        revert BasketIdAlreadyExists();
    }
    // Remove the old bitFlag mapping and add the new bitFlag mapping
    bytes32 oldId = keccak256(abi.encodePacked(currentBitFlag, strategy));
    _bmStorage.basketIdToAddress[oldId] = address(0);
    _bmStorage.basketIdToAddress[newId] = basket;
    _bmStorage.basketAssets[basket] = AssetRegistry(_bmStorage.assetRegistry).getAssets(bitFlag);
    emit BasketBitFlagUpdated(basket, currentBitFlag, bitFlag, oldId, newId);
    // Update the bitFlag in the BasketToken contract
    BasketToken(basket).setBitFlag(bitFlag);
}
function basketTokenToRebalanceAssetToIndex(
    BasketManagerStorage storage self,
    address basketToken,
    address asset
)
    public
    view
    returns (uint256 index)
{
    index = self.basketAssetToIndexPlusOne[basketToken][asset];
    if (index == 0) {
        revert AssetNotFoundInBasket();
    }
    unchecked {
        // Overflow not possible: index is not 0
        return index - 1;
    }
}

Here is an error scenario.

  1. A new asset is added to the AssetRegistry.

  2. Then, BasketManager.updateBitFlag() is called to enable the new asset. The basketAssetToIndexPlusOne mapping does not include the index of the new asset because it is only initialized in createNewBasket().

  3. During rebalancing, it calls basketTokenToRebalanceAssetToIndex() via _processInternalTrades() in proposeTokenSwap(). This causes an AssetNotFound error as the new asset's index is missing from basketAssetToIndexPlusOne.

  4. The rebalancing process fails, and the new asset cannot be included in the rebalance.

Impact

The current fee-calculation method leads to undercollected fees, causing financial loss to the protocol and underperformance of fee collection for the protocol.

Recommendations

Modify the updateBitFlag() function to ensure the basketAssetToIndexPlusOne mapping is updated whenever a new asset is added.

Remediation

This issue has been acknowledged by Storm Labs, and a fix was implemented in commit 9e67b7b8.

Zellic © 2025Back to top ↑