# NodeOp can get rewards even if there was an error in registering the node as a validator

GoGoPool MinipoolManager allows Staking->Error state transition without resetting avaxAssignedHighWater, letting a NodeOp claim GGP rewards for a failed validator registration.

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

**Target:** MinipoolManager / ClaimNodeOp Solidity contracts
**Root cause:** recordStakingError() does not reset avaxAssignedHighWater, and the state machine permits Staking->Error, so a minipool that errored still counts toward reward eligibility.
**Steps:**
1. NodeOp creates minipool via createMinipool(depositAmt, avaxAssignmentRequest, duration) and stakes GGP
2. Rialto calls `claimAndInitiateStaking(nodeID)` then `recordStakingStart(nodeID, txID, ts)`
3. Rialto calls `recordStakingError{value: deposit+assignment}(nodeID, errorCode)` — avaxAssignedHighWater stays at depositAmt
4. NodeOp calls `withdrawMinipoolFunds(nodeID)` to recover deposit
5. After rewards cycle, `nopClaim.isEligible(nodeOp)` returns true; `calculateAndDistributeRewards` then `claimAndRestake` yields GGP rewards
**How found:** Reading the docs on reward eligibility for valid minipools, then noticing recordStakingError does not reset avaxAssignedHighWater while recordStakingStart does, and that the FSM allows Staking->Error.
**Exploitation:** NodeOp registers a minipool, has Rialto drive it through Staking then Error (legal FSM transition), withdraws deposit, and later claims GGP rewards despite the validator never registering.
**Insight:** When a protocol tracks eligibility via a high-water mark updated only on the success path, check every failure/abort transition for a matching reset — stale accounting state is a common reward-farming vector.
