The sponsor can call goToProduction on the agreement, which moves it directly to PRODUCTION without entering an active‑risk state. This leaves riskWindowStart == 0 permanently, while the withdraw function blocks exits based on the broader registry state. Simultaneously, the entire snapshotTotalBonus is treated as unearned and swept to the sponsor’s recoveryAddress. The combined effect locks the stakers’ principal for the full term and steals the entire bonus pool.
Stakers expect to earn a bonus if they keep their funds in the pool through the risk window. They can withdraw before the risk window opens.
The sponsor calls goToProduction, which moves the agreement directly to PRODUCTION without entering UNDER_ATTACK. The pool never sets riskWindowStart, so withdrawals are permanently disabled even though no risk materialised, and the entire bonus is swept to the sponsor.
Likelihood:
The sponsor is also the agreement owner (enforced by the factory). They can call goToProduction in a single transaction, skipping the attack phase entirely.
Stakers have no window to react because the transition is instant and withdrawals are locked immediately.
Impact:
Stakers lose access to their principal for the full term and earn zero bonus.
The sponsor captures the entire bonus pool, which may include third‑party contributions.
Explanation:
The sponsor creates a pool in ATTACK_REQUESTED state and contributes a 50‑token bonus. A staker deposits 100 tokens. The sponsor then calls goToProduction, which directly moves the agreement to PRODUCTION. The staker attempts to withdraw but the transaction reverts because the registry state is no longer pre‑attack, even though no risk was observed. After expiry, claimExpired resolves the pool to SURVIVED. The staker claims and receives only their principal (100 tokens). The sponsor then calls sweepUnclaimedBonus and gets the full 50‑token bonus. This shows the bait‑and‑switch: principal locked without risk, bonus stolen by sponsor.
Mitigation explanation:
Two separate changes address the bait‑and‑switch:
1. Withdrawal gating: The original withdraw function locks withdrawals if the registry state is anything other than the three pre‑attack states, even when riskWindowStart == 0. The fix removes the registry‑state disjunction and locks withdrawals only on riskWindowStart != 0. This restores the guarantee that stakers can exit freely until actual risk is observed. A terminal PRODUCTION reached via goToProduction will no longer block withdrawals because riskWindowStart remains zero.
2. Bonus destination: When riskWindowStart == 0, the bonus was treated as unearned and swept to the sponsor. The mitigation replaces this with a refund to the original bonus contributors (pro‑rata). This ensures third‑party bonus funds are never captured by the sponsor on a no‑risk outcome.
Together, these changes prevent the sponsor from both locking principal and stealing the bonus with a single goToProduction call.
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.