# Incorrect game type can be proven and finalized due to unsafe cast

OptimismPortal2 downcasts GameType uint32 to uint8 in raw(), so game types differing by 256 compare equal, letting an unwatched buggy game prove and finalize fraudulent withdrawals.

- Payout: Contest reward
- Severity: medium
- Program: Optimism 2024
- Credited: Stiglitz
- Disclosed: 2024-02-08
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2024-02-optimism-2024-judging/issues/84
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-02-optimism-2024%3AM-1
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:sherlock sev:medium tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** OptimismPortal2 L1 bridge contract / dispute game type comparison
**Root cause:** LibUDT.raw() casts GameType (uint32) to uint8 via assembly, so any two game types congruent mod 256 are treated as equal during proveWithdrawalTransaction and finalizeWithdrawalTransaction.
**Steps:**
1. Set respectedGameType to 256 via `setRespectedGameType(GameType.wrap(256))`.
2. Create a game with `disputeGameFactory.create(GameType.wrap(0), Claim.wrap(_outputRoot), abi.encode(uint(0xFF)))` — gameType 0 is known-exploitable and unwatched.
3. Call `optimismPortal2.proveWithdrawalTransaction(_tx, disputeGameFactory.gameCount()-1, _outputRootProof, _withdrawalProof)`; passes because 0 % 256 == 256 % 256.
4. Warp 4 days, `game.resolveClaim(0); game.resolve();`, warp 4 more days.
5. Call `optimismPortal2.finalizeWithdrawalTransaction(_defaultTx)`; withdrawal of 100 wei succeeds despite wrong game type.
**How found:** Code review of the assembly cast in LibUDT.raw() returning uint8 while GameType is uint32, then reasoning about the off-chain watcher comment stating only respectedGameType games are watched.
**Exploitation:** Attacker creates a dispute game of an old, known-buggy game type whose value collides mod 256 with the current respectedGameType. Off-chain challengers only watch the respected type, so the game is unchallenged; attacker forces DEFENDER_WINS, proves an invalid output root, and finalizes arbitrary withdrawals draining Portal funds.
**Escalation:** Any game type value >255 colliding mod 256 with respected type works; non-sequential/namespaced game types make collision reachable without exhausting 0-255.
**Insight:** When a type is widened (uint8→uint32) but a helper still downcasts via assembly, check every comparison site for modular collisions; also check whether off-chain monitoring keys on the same truncated value.
