_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.
View preliminary resultsAppeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.