F-2025-0002·state-desynchronization
Tier updates not reflected in lockPeriods array leads to stale staking period information
TL;DR
updateTier mutates the tiers mapping but never updates the lockPeriods array, so getLockPeriods returns stale data and integrators see periods that no longer match the actual valid set.
Severity
MEDIUM
Impact
MEDIUM
Likelihood
MEDIUM
Method
MManual review
CAT.
Complexity
LOW
Exploitability
MEDIUM
02Section · Description
Description
The StakingContract maintains staking period information in two separate data structures: tiers and lockPeriods. When updating tiers through the updateTier function, the corresponding lockPeriods array is not updated to reflect these changes:
solidity
function updateTier(uint numDays, uint basisPoints) external onlyOwner {require(basisPoints <= 10000, "Invalid basis points");uint oldRate = tiers[numDays];tiers[numDays] = basisPoints;// lockPeriods is not updated hereemit TierUpdated(numDays, oldRate, basisPoints);}
This creates a misalignment between the actual available staking periods in tiers and what is exposed through the getLockPeriods() function:
solidity
function getLockPeriods() external view returns (uint[] memory) {return lockPeriods; // Returns stale data that doesn't reflect tier updates}
03Section · Impact
Impact
- Stale Data:
getLockPeriods()returns outdated information that does not reflect the current state of available staking periods after tier updates. - UI / Integration Inconsistency: Users and integrated protocols receive incorrect information about available staking periods because
getLockPeriods()does not reflect updates made throughupdateTier. - Protocol Confusion: Creates confusion about which staking periods are actually valid, as the two data structures maintain different states.
04Section · Recommendation
Recommendation
Modify updateTier to maintain synchronisation between tiers and lockPeriods:
solidity
function updateTier(uint numDays, uint basisPoints) external onlyOwner {require(basisPoints <= 10000, "Invalid basis points");uint oldRate = tiers[numDays];// If this is a new period, add it to lockPeriodsif (tiers[numDays] == 0) {lockPeriods.push(numDays);}// Update the tiertiers[numDays] = basisPoints;emit TierUpdated(numDays, oldRate, basisPoints);}
05Section · Resolution
Resolution
Ample Protocol: Fixed.
Zealynx: Verified.
Status
Fixed