# MinipoolManager: recordStakingError function does not decrease minipoolCount leading to too high GGP rewards for staker

recordStakingError in GoGoPool's MinipoolManager fails to decrement minipoolCount, so a staker's rewardsStartTime never resets, letting them skip the 14-day eligibility wait and earn excess GGP rewards.

- Payout: Contest reward
- Severity: medium
- Program: GoGoPool
- Credited: HollaDieWaldfee
- Disclosed: 2023-03-21
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-12-gogopool-findings/issues/235
- Library page: https://bugbountylibrary.com/r/c4%3A2022-12-gogopool%3AM-19
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic vuln:reward-distribution

**Target:** MinipoolManager / ClaimNodeOp staking reward accounting
**Root cause:** recordStakingError does not call staking.decreaseMinipoolCount(owner), so a staker's minipoolCount never returns to zero after an errored minipool.
**Steps:**
1. Stake GGP and create a minipool via createMinipool(depositAmt, avaxAssignmentRequest, duration).
2. Rialto calls claimAndInitiateStaking(nodeID) then recordStakingStart(nodeID, txID, block.timestamp).
3. Rialto calls recordStakingError{value: validationAmt}(nodeID, errorCode) — minipoolCount stays 1 instead of dropping to 0.
4. Rialto calls finishFailedMinipoolByMultisig(nodeID); minipoolCount still 1.
5. Staker creates a new minipool; because minipoolCount never hit zero, ClaimNodeOp.calculateAndDistributeRewards does not reset rewardsStartTime, so the staker is immediately reward-eligible instead of waiting rewardsEligibilityMinSeconds (14 days).
**How found:** Code review of recordStakingError against the state transitions in ClaimNodeOp.calculateAndDistributeRewards, noticing minipoolCount is used to gate rewardsStartTime reset and is never decremented on the error path; confirmed with a Foundry test logging minipoolCount across Staking/Error/Finished states.
**Exploitation:** A node operator whose minipool errors out keeps a nonzero minipoolCount; on creating a new minipool they bypass the 14-day rewardsEligibilityMinSeconds wait and collect GGP node-operator rewards immediately, earning more than entitled.
**Insight:** When a counter gates a time-based eligibility reset, audit every state-transition path (error/finish/cancel) for symmetric increment/decrement — the error path is the classic place a decrement is forgotten.
