_clampUserSums uses an aggregate check — userSumStakeTime[u] < eligibleStake[u] × riskWindowStart — that compares total weighted entry time against total stake floored to riskWindowStart. When a user holds both pre-risk deposits and post-risk deposits, the average entry time can fall below the threshold, causing the clamp to floor the entire stake to riskWindowStart. The post-risk deposit's actual entry time is erased, giving it credit for at-risk time it never served.
However, this condition is unreachable in practice. The second stake() call (line 244) calls _clampUserSums BEFORE adding the new deposit, which correctly clamps the pre-risk portion to riskWindowStart. The post-risk deposit is then added with its actual entry time. At claim time, the aggregate check compares the combined sum against totalStake × riskWindowStart — but the combined sum already includes the correctly-clamped pre-risk portion plus the post-risk portion, which is always >= totalStake × riskWindowStart. The clamp never fires on a user who has post-risk deposits.
The function _clampUserSums at line 677 normalizes pre-risk deposits — those made before the risk window opened — so they are treated as if they entered at riskWindowStart. The implementation:
The check fires when the weighted average entry timestamp is earlier than riskWindowStart. A user with mixed deposits — 100 tokens at t=100 (pre-risk) and 100 tokens at t=500 (post-risk), with riskWindowStart=400 — has an average entry of (100×100 + 100×500) / 200 = 300. Since 300 < 400, the clamp would fire and set both deposits to t=400.
However, this scenario never occurs because _clampUserSums is called during the second stake() at line 244 — before the post-risk deposit is added to the accumulators. At that point, only the pre-risk deposit exists (100 tokens at t=100). The clamp correctly floors it to t=400. Then the post-risk deposit (100 tokens at t=500) is added with its actual entry time. The final userSumStakeTime = 100×400 + 100×500 = 90,000, which is the correct per-deposit value.
At claim time, the aggregate check compares 90,000 against 200 × 400 = 80,000. Since 90,000 >= 80,000, the clamp does not fire. The post-risk entry time is preserved.
A Foundry test confirmed this: with 100 tokens pre-risk and 1 token post-risk, userSumStakeTime equaled the correct per-deposit sum (176750030500000000000000000000), not the clamped sum (176750030300000000000000000000).
Likelihood:
None. The condition required for the over-clamp (average entry below riskWindowStart despite post-risk deposits) cannot be reached because _clampUserSums is called during each stake() before the new deposit is added, correctly handling the pre-risk portion in isolation.
Impact:
None. The post-risk deposit's entry time is preserved in all reachable states.
The following test demonstrates that the clamp does NOT fire on a user with mixed pre-risk and post-risk deposits. The userSumStakeTime equals the correct per-deposit value, not the aggregate-clamped value.
Test output:
The actual value (176750030500) equals the correct per-deposit value and exceeds the clamped value (176750030300). The aggregate clamp does not fire.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.