-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Description
When a bApp adds new tokens via updateBAppsTokens(), these tokens are assigned a risk level of 0 instead of the specified risk level. The specified risk level is then stored as a pending value that only takes effect if the bApp owner calls updateBAppsTokens() again after waiting for the 14-day timelock period to expire.
Root Cause
In BasedAppsManager::updateBAppsTokens(), the logic treats updates that add a new token(s) and those which update existing token configurations identically:
uint32 requestTime = uint32(block.timestamp);
address token;
ICore.SharedRiskLevel storage tokenData;
ProtocolStorageLib.Data storage sp = ProtocolStorageLib.load();
for (uint256 i = 0; i < tokenConfigs.length; ) {
token = tokenConfigs[i].token;
tokenData = s.bAppTokens[msg.sender][token]; // <--- for a new token mapping returns default values
if (requestTime > tokenData.effectTime) {
tokenData.currentValue = tokenData.pendingValue; // <---- currentValue set to 0
}
tokenData.pendingValue = tokenConfigs[i].sharedRiskLevel; // <--- Sets intended risk as pending,
tokenData.effectTime = requestTime + sp.tokenUpdateTimelockPeriod; // <--- Not adjustedable for 14 days
tokenData.isSet = true; // <--- strategies can immediately make obligations
unchecked {
i++;
}
}For new tokens, both effectTime and pendingValue start at 0, so the condition requestTime > tokenData.effectTime evaluates to true, setting currentValue to 0 instead of the specified risk level.
Impact
- Strategies: Can immediately allocate to new tokens with risk level 0 instead of the intended risk level, potentially allowing unintended over-commitment behavior
- bApps: Weight calculations use incorrect risk parameters for 14+ days
- Protocol: Inconsistent behavior compared to initial token registration
Proof of Concept
- Add the following test case to your existing
BasedAppsManager.t.sol - Run
forge test --match-contract BasedAppsManagerTest --match-test testNewTokenHasZeroRiskLevel -vvvv
function testNewTokenHasZeroRiskLevel() public {
// 1. Register bApp with initial token
ICore.TokenConfig[] memory initialTokens = createSingleTokenConfig(
address(erc20mock),
1000000 // β = 1.0
);
vm.prank(USER1);
proxiedManager.registerBApp(initialTokens, metadataURI);
// 2. Add NEW token via updateBAppsTokens with intended risk level
ICore.TokenConfig[] memory newTokens = createSingleTokenConfig(
address(erc20mock2),
2000000 // β = 2.0 (INTENDED)
);
vm.prank(USER1);
proxiedManager.updateBAppsTokens(newTokens);
// 3. Demonstate that new token has wrong risk level
(uint32 currentRisk, bool isSet, uint32 pendingRisk, ) =
proxiedManager.bAppTokens(USER1, address(erc20mock2));
assertEq(isSet, true, "New token should be available immediately");
assertEq(currentRisk, 0, "Issue: New token has risk level 0");
assertEq(pendingRisk, 2000000, "Specified risk level is only pending");
// bApp is now stuck with risk level 0 for 14 days
}Proposed Solution
Distinguish between new and existing tokens in updateBAppsTokens():
if (!tokenData.isSet) {
// NEW TOKEN: Set immediately (like registration)
tokenData.currentValue = tokenConfigs[i].sharedRiskLevel;
tokenData.isSet = true;
} else {
// EXISTING TOKEN: Use timelock for changes
if (requestTime > tokenData.effectTime) {
tokenData.currentValue = tokenData.pendingValue;
}
tokenData.pendingValue = tokenConfigs[i].sharedRiskLevel;
tokenData.effectTime = requestTime + sp.tokenUpdateTimelockPeriod;
}This approach:
- Gives new tokens immediate effect with specified parameters
- Maintains timelock protection for existing token changes
- Eliminates the incorrect 0 assignment
- Creates consistent behavior with initial registration
Additional Context
The current logic creates inconsistent behavior in the protocol:
registerBApp(): New tokens get immediate effect with specified risk levelsupdateBAppsTokens(): New tokens get incorrect 0 risk level for 14+ days
The immediate effect approach is more appropriate because:
- Adding new tokens doesn't impact existing participants or their obligations
- Strategies must voluntarily choose to allocate to new tokens
- No existing harm occurs, unlike changing parameters of active tokens
- bApp owners should have control over their own token parameters without unnecessary delays
- The timelock mechanism should protect against changes to existing token parameters, not the addition of entirely new tokens